上一篇文章:跟乐乐学微服务!(一) SpringCloud组件Eureka的应用
下一篇文章:跟乐乐学微服务!(三)SpringCloud组件熔断器 Hystrix
什么是负载均衡?
在微服务中,消费者需要去访问注册中心,从注册中心中拉取服务提供方的服务地址。
但是,我们不妨设想一下这个问题。假如有两个相同服务提供方的服务实例注册到了注册中心,分别为Provider A和Provider B。
那么此时,消费者这边在不知道哪个最为空闲的情况下,必须要选择其中一个服务提供者;后果就是所有请求都将访问这个服务提供者,增加了该服务提供者的负担。
此时,就需要负载均衡来实现了。
负载均衡会根据特定的算法,从Eureka拉取过来的服务列表中选择出最为空闲的一个服务提供者,然后去消费它。
什么是Ribbon?
在这之前,负载均衡的实现通常需要我们自己编写负载均衡算法。
但是通过Ribbon,可以直接使用它基于已经写好了的算法,去实现负载均衡。
Ribbon虽然是一个组件,但是Eureka组件中已经集成了它,因此只要你引入了Eureka的依赖,就不需要引用Ribbon的依赖。
使用
- 一.在消费者模块的启动类中,在RestTemplate配置方法上添加‘@LoadBalanced’注解
- 二.在controller层,由原先通过discoveryClient对象拉取服务,再选取其中一个,改为直接访问服务名。
补充:Ribbon配置
-
Ribbon的配置文件有全局配置和局部配置两种方式。后者在配置时,需要在最外面一层定义一个名字为服务提供方名称的key。
-
Ribbon默认的负载均衡策略是轮询。SpringBoot也帮提供了修改负载均衡规则的配置。下面就可以修改为随机的。
ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
- Ribbon默认的请求提供方服务时的超时时长为1秒(1000)。如果超过了这个时长会直接断开,或者给Hystrix降级处理(如果应用了Hystrix组件)。
ribbon.ConnectTimeout=1000 # 建立链接的超时时长,默认1秒。衡量的是消费方和提供方建立连接所耗费的时长。
ribbon.ReadTimeout=1000 # 读取超时时长。默认1秒。衡量的是消费方和提供方建立连接后,从读取资源到响应回消费方本地所耗费的时长。
- Ribbon还有重试机制,当请求超时后,会自动地重新发起请求。默认是开启状态的。
ribbon.OkToRetryOnAllOperations: true # 默认为true,是否对所有的请求重试。
ribbon.MaxAutoRetries: 1 # 表示当消费方访问提供方实例出错后,对同一个提供方实例所进行的重试次数。默认为1。
ribbon.MaxAutoRetriesNextServer: 2 # 当对同一个提供方实例的重试达到了规定次数后,会自动更换另一个实例进行请求;此处设置的是更换实例的次数。默认为2。
转换为yaml格式后如下:
- 全局配置格式
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 将负载均衡策略改为随机。
ReadTimeout: 1000 # 读取超时时长。默认1秒。衡量的是消费方和提供方建立连接后,从读取资源到响应回消费方本地所耗费的时长
ConnectTimeout: 1000 # 建立链接的超时时长,默认1秒。衡量的是消费方和提供方建立连接所耗费的时长。
OkToRetryOnAllOperations: true # 默认为true,是否对所有的请求重试。
MaxAutoRetries: 1 # 表示当消费方访问提供方实例出错后,对同一个提供方实例所进行的重试次数。默认为1。
MaxAutoRetriesNextServer: 2 # 当对同一个提供方实例的重试达到了规定次数后,会自动更换另一个实例进行请求;此处设置的是更换实例的次数。默认为2
- 局部配置格式
database-provider-service: # 该ribbon负载均衡配置应用于名为’database-provider-service‘的提供方。
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 将负载均衡策略改为随机。
ReadTimeout: 1000 # 读取超时时长。默认1秒。衡量的是消费方和提供方建立连接后,从读取资源到响应回消费方本地所耗费的时长
ConnectTimeout: 1000 # 建立链接的超时时长,默认1秒。衡量的是消费方和提供方建立连接所耗费的时长。
OkToRetryOnAllOperations: true # 默认为true,是否对所有的请求重试。
MaxAutoRetries: 1 # 表示当消费方访问提供方实例出错后,对同一个提供方实例所进行的重试次数。默认为1。
MaxAutoRetriesNextServer: 2 # 当对同一个提供方实例的重试达到了规定次数后,会自动更换另一个实例进行请求;此处设置的是更换实例的次数。默认为2。
原理探索:源码跟踪
为什么只输入了service名称就可以访问了呢?之前还要获取ip和端口。
显然是有组件根据service名称,获取到了服务实例的ip和端口。
因为消费者模块使用的是RestTemplate,spring的负载均衡自动配置类LoadBalancerAutoConfiguration.LoadBalancerInterceptorConfig 会自动配置负载均衡拦截器(在spring-cloud-commons-**.jar包中的spring.factories中定义的自动配置类), 它就是LoadBalancerInterceptor ,这个类会在对RestTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。
- 我们进行源码跟踪:
- 继续跟入execute方法:发现获取了9092端口的服务
- 再跟下一次,发现获取的是9091、9092之间切换
多次访问消费者模块对外暴露的请求地址;然后跟进代码,发现其果然实现了负载均衡。