目录
1.3RibbonLoadBalancerClient.execute()
在之前eureka中,我们给RestTemplate的bean
添加了@LoadBalanced
注解即可实现负载均衡功能,这是因为SpringCloud底层提供过一个名为 Ribbon 的组件,来实现负载均衡功能。
注意!!!
- cloud 2021 版本已经没有自带ribbon的整合,所以需要引入另一个支持的jar包
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.9.RELEASE</version> </dependency>
- cloud 2021 版本已经取消了对ribbon的支持,所以无法通过修改Ribbon负载均衡的模式来实现nacos提供的负载均衡模式
1.负载均衡原理
1.1总体流程:
我们只输入了 service 名称就可以访问,不需要获取ip和端口,显然根据 service 名称,就可以获取到了服务实例的ip和端口。这是因为LoadBalancerInterceptor
,这个类会在对 RestTemplate 的请求进行拦截,然后从 Eureka 根据服务 id 获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务 id。
1.2LoadBalancerInterceptor
LoadBalancerInterceptor实现了客户端请求拦截器ClientHttpRequestInterceptor,
实现了intercept()方法,拦截了用户的HttpRequest请求,进行以下操作:
request.getURI()
:获取请求地址,即 http://user-server/user/1originalUri.getHost()
:获取uri路径的主机名,其实就是服务名称user-server
this.loadBalancer.execute()
:根据获得的服务名称完成服务拉取
this.loadBalancer
是Ribbon
LoadBalancerClient
类型的对象,我们看这个execute()方法的内容
1.3Ribbon
LoadBalancerClient.execute()
操作:
getLoadBalancer(serviceId)
:根据服务id获取负载均衡器ILoadBalancer
,而负载均衡器ILoadBalancer
会拿着服务id去eureka中获取服务列表。getServer(loadBalancer)
:利用内置的负载均衡算法,从服务列表中选择一个。在图中可以看到获取了8082端口的服务
获取服务时,通过一个getServer()
方法来做负载均衡.
1.4 getServer()
方法
getServer()
方法又调用了chooseServer()
方法
进行服务选择的这个rule
是什么
这里的 rule 默认值是一个 RoundRobinRule,即
负载均衡默认使用了轮训算法。,当然我们也可以自定义。
1.5详细流程
总结:
- 请求进入Ribbon,被
LoadBalancerInterceptor负载均衡拦截器拦住,获取请求地址和服务名称(user-server)交给Ribbon
LoadBalancerClient
RibbonLoadBalancerClient获得服务名称后提交给
DynamicServerListLoadBalancer- DynamicServerListLoadBalancer根据服务名称(user-server)到eureka拉取服务列表
- 获得服务列表后,
IRule
利用内置负载均衡规则,从列表中选择一个,例如 localhost:8081返回给RibbonLoadBalancerClient
RibbonLoadBalancerClient用得到的ip和端口替换服务名称,得到真实的请求地址
http://localhost:8081/user/1,发起真实请求
2.负载均衡策略
Ribbon的负载均衡规则是一个叫做IRule的接口来定义的,每一个子接口都是一种规则:
2.1常见策略
内置负载均衡规则类 | 规则描述 |
RoundRobinRule | 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule | 对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit属性进行配置。 |
WeightedResponseTimeRule | 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。 |
ZoneAvoidanceRule | 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。 |
BestAvailableRule | 忽略那些短路的服务器,并选择并发数较低的服务器。 |
RandomRule | 随机选择一个可用的服务器。 |
RetryRule | 重试机制的选择逻辑 |
默认的实现就是ZoneAvoidanceRule,是一种轮询方案。
2.2自定义策略
通过定义IRule实现可以修改负载均衡规则,有两种方式:
2.2.1代码方式(作用于全局)
在order-service中的配置类中,定义一个新的IRule:
@Configuration
public class OrderConfiguration {
/**
* 创建RestTemplate并注入spring容器
* @return
*/
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
/**
* 修改负载均衡策略
*/
@Bean
public IRule iRule(){
return new RandomRule();
}
}
2.2.2配置文件方式(作用于指定服务)
在 order-service 的 application.yml 文件中,添加新的配置也可以修改规则:
user-server: # 给需要调用的微服务配置负载均衡规则,order-server服务去调用user-server服务 ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
配置文件方式的优先级更高
3.饥饿加载
启动orderservice,第一次访问时,时间消耗会大很多,这是因为 Ribbon 懒加载的机制,即第一次访问时才会去创建LoadBalanceClient,拉取集群地址,请求时间会很长。
饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载。
ribbon: eager-load: enabled: true # 开启饥饿加载 clients: user-server # 指定饥饿加载的服务名称 # clients: # 指定多个服务时 # - user-server # - xxx-server