1、微服务
1.1 概念
通常而言,微服务架构是一种架构模式或者说是一种架构风格,它提倡将单一应用程序划分为一组小的服务,每个服务运行在其独立的自己的进程中,服务之间互相协调,互相配合,为用户提供最终价值。服务之间采用轻量级的通信机制相互沟通(通常是RESTful API,Dubbo采用了RPC远程过程调用)。每个服务都为照着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中式的服务管理机制、对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具进行构建,可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来缩写服务,也可以使用不同的数据存储。
1.2 理解
微服务化的核心就是将传统 的一站式应用,根据业务拆分成一个一个的服务,彻底的去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事,从技术角度看就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动或销毁,拥有自己独立的数据库。
1.3 优点
1、 每个服务够内聚,足够小,代码容易理解,这样能聚焦一个指定对业务功能或业务需求
2、 开发简单、开发效率提高,一个服务可能就是专一的只干一件事
3、 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段还是在部署阶段都是独立的
4、 微服务能够使用不同的语言进行开发
5、 易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如Jenkins、Hudson、bamboo
6、 微服务只是业务逻辑的代码,不会和HTML、CSS或其他界面组件混合
7、 每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一数据库
1.4 缺点
1、 开发人员要处理分布式系统的复杂性
2、 多服务运维难度,随着服务的增加,运维的压力也在增大
3、 系统部署依赖
4、 服务间通信成本
5、 数据一致性
6、 系统集成测试
7、 性能监控
1.5 技术栈
1、 服务开发:Springboot、Spring等
2、 服务配置与管理:Archaius、Diamond等
3、 服务注册与发现:Eureka、Consul、Zookeeper等
4、 服务调用:Feign等
5、 消息队列:Kafka、RabbitMQ、ActiveMQ等
6、 服务配置中心管理:SpringCloud Config、Chef等
7、 服务路由(API网关):Zuul等
8、 服务监控:Zabbix、Nagios、Metrics、Spectator等
9、 全链路追踪:Zipkin、Brave、Dapper等
10、 服务部署:Docker、OpenStack、Kubernetes等
11、 数据流操作开发包:SpringCloud Stream(分装与Redis;Rabbit、Kafka等发送接收消息)
12、 事件消息总线:SpringCloud Bus
1.6 五大组件
1、 Eureka:服务注册与发现
2、 Ribbon:负载均衡
3、 Hystrix:断路器
4、 Zuul:路由网关
5、 SpringCloud Config:分布式配置中心
1.7 Springboot与Springcloud的联系与区别
1、 SpringBoot专注于快速、方便的开发单个微服务个体
2、 SpringCloud关注全局的服务治理框架
3、 SpringCloud是关注全局的微服务整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来
4、 SpringBoot可以离开SpringCloud独立开发项目,但是SpringCloud离不开SpringBoot,两者属于依赖的关系
2、Eureka
2.1 概念
Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。
而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。SpringCloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。
2.2 组件
2.2.1 Eureka Server
提供服务注册服务,各个节点启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到
2.2.2 Eureka Client
是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)
2.3 三个角色
2.3.1 Eureka Server
服务注册中心,负责服务列表的注册、维护和查询等功能;
2.3.2 Service Provider
服务提供方,同时也是一个Eureka Client
,负责将所提供的服务向Eureka Server
进行注册、续约和注销等操作。注册时所提供的主要数据包括服务名、机器ip、端口号、域名等,从而能够使服务消费方能够找到;
2.3.3 Service Consumer
服务消费方,同时也是一个Eureka Client
,同样也会向Eureka Server
注册本身所提供的服务。但在本示例工程中更多的是从Eureka Server
中获取相应的服务列表,以便能够发起服务调用。
2.4 Eureka配置
2.4.1 application.yml(独立Eureka服务器)
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
2.4.2 application.yml(两个对等感知Eureka服务器)
---
spring:
profiles: peer1
eureka:
instance:
hostname: peer1
client:
serviceUrl:
defaultZone: http://peer2/eureka/
---
spring:
profiles: peer2
eureka:
instance:
hostname: peer2
client:
serviceUrl:
defaultZone: http://peer1/eureka/
2.4.3 application.yml(三个对等感知Eureka服务器)
eureka:
client:
serviceUrl:
defaultZone: http://peer1/eureka/,http://peer2/eureka/,http://peer3/eureka/
---
spring:
profiles: peer1
eureka:
instance:
hostname: peer1
---
spring:
profiles: peer2
eureka:
instance:
hostname: peer2
---
spring:
profiles: peer3
eureka:
instance:
hostname: peer3
2.4.4 配置详解
eureka:
client: #eureka客户端配置
register-with-eureka: true #是否将自己注册到eureka服务端上去
fetch-registry: true #是否获取eureka服务端上注册的服务列表
service-url:
defaultZone: http://localhost:8001/eureka/ #指定注册中心地址
enabled: true # 启用eureka客户端
registry-fetch-interval-seconds: 30 #定义去eureka服务端获取服务列表的时间间隔
instance: #eureka客户端实例配置
lease-renewal-interval-in-seconds: 30 #定义服务多久去注册中心续约
lease-expiration-duration-in-seconds: 90 #定义服务多久不去续约认为服务失效
metadata-map:
zone: guangdong #所在区域
hostname: localhost #服务主机名称
prefer-ip-address: false #是否优先使用ip来作为主机名
server: #eureka服务端配置
enable-self-preservation: false #关闭eureka服务端的保护机制
2.5 Eureka注解
2.5.1 @EnableDiscoveryClient
能够让注册中心发现,扫描到该服务,并且可以是除Eureka注册中心之外其他注册中心
2.5.2 @EnableEurekaClient
只能让Eureka作为注册中心发现并且扫描
2.5.3 @EnableEurekaServer
开启 eureka server 服务端,可以接受其他服务注册进来
3、Ribbon
3.1 概念
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套 客户端 负载均衡 的工具。
它的主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。
3.2 负载均衡
负载均衡(Load Balance),简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA(高可用)。
1、 集中式负载均衡:即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方。
2、 进程内负载均衡:将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。
Ribbon就属于进程内负载均衡,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。
3.3 @LoadBalanced
3.3.1 注入
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
3.3.2 报错
java.lang.IllegalStateException: No instances available for XXX
3.3.3 解决思路
为什么加上 @LoadBalanced就不能访问ip加端口呢?
主要因为其使用ribbon组件,当我们应用依赖了eureka-client的时候,eureka-client依赖了ribbon,虽然看是ribbon没有存在感,但是ribbon默默的发挥着自己的负载均衡能力。在加了注解 @LoadBalanced 之后,我们的restTemplate 会走这个类RibbonLoadBalancerClient,serverid必须是我们访问的服务名称 ,当我们直接输入ip的时候获取的server是null,就会抛出异常。而这个服务名称是需要我们在Eureka中配置的,如果没有配置直接访问则会报错。
因为ribbon的作用是负载均衡,那么你直接使用ip地址,那么就无法起到负载均衡的作用,因为每次都是调用同一个服务,当你使用的是服务名称的时候,他会根据自己的算法去选择具有该服务名称的服务。
结论:因为我的IP没有在Eureka中经行配置。
为什么使用new RestTemplate则可以正常访问?
因为添加了ribbon依赖后,会在项目启动的时候自动往RestTemplate中添加LoadBalancerInterceptor拦截器,直接new的对象没有加@LoadBalanced,通过Debug工具发现在访问时没有被该拦截器拦截。所以就能正常访问。
3.3.4 解决方法
①服务直接的调用,如果要使用服务名进行调用,应该使用spring.application.name的值进行访问
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://microservice-dept";
②Eureka-client在2.x版本中包含Ribbon,同时加入会冲突;
另外Eureka-client与Ribbon版本不同也无法加载@LoadBalanced注解
3.3.5 总结
1)用户创建RestTemplate
2)添加了ribbon依赖后,会在项目启动的时候自动往RestTemplate中添加LoadBalancerInterceptor拦截器
3)用户根据RestTemplate发起请求时,会将请求转发到LoadBalancerInterceptor去执行,该拦截器会根据指定的负载均衡方式获取该次请求对应的应用服务端IP、port
4)根据获取到的IP、port重新封装请求,发送HTTP请求,返回具体响应
3.4 Ribbon配置
3.4.1 Ribbon工作流程
1、 选择EurekaServer,它优先选择在同一个区域内负载较少的EurekaServer
2、 根据用户指定的策略(轮询、随机、根据响应时间加权 等等),在从EurekaServer取到的服务注册列表中选择一个调用地址
3.4.2 Ribbon配置流程
(1) ribbon-provider
①创建ribbon-provider项目,导入Eureka-client依赖包(2.x版本后已包含Ribbon),用于给Ribbon提供服务调用
②配置ribbon-provider的yml文件,设置端口号、eureka服务注册地址、spring.application.name等属性值
③创建ribbon-provider的service与controller层作为服务调用接口
(2) ribbon-consumer
①创建ribbon-consumer项目,导入Eureka-client依赖包,用于调用Ribbon-provider提供的负载均衡服务
②配置ribbon-consumer的yml文件,设置端口号,eureka服务注册地址,springapplicationname与ribbon-provider的调用路径
server:
port: 8301
spring:
application:
name: ribbon-consumer
eureka:
client: