目录
1.1、LoadBalancerAutoConfiguration原理分析
2、核心类LoadBlancedClient 接口以及其实现类
2.2.1 RibbonLoadBalancerClient简述
3.2.4、DynamicServerListLoadBalancer
一、Ribbon简介
Ribbon是Netflix公司开源的一个负载均衡的项目,相比于nginx 进程(应用)级别的负载均衡器,Ribbon是一个客户端负载均衡器(即通过编码的形式将负载功能内嵌到代码中),运行在客户端上。 Feign默认集成了Ribbon。为Ribbon配置服务提供者地址后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。在Spring Cloud中,当Ribbon与Eureka、Nacos等配合使用时,Ribbon可自动从注册中心获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。展示了Ribbon与Eureka配合使用时的架构
负载均衡
RandomRule 随机
RoundRobinRule 随机轮询
BestAvailableRule 获取空闲服务实例
WeightedResponseTimeRule 权重的形式挑选服务
RetryRule 重试规则 在RoundRobinRule 的基础上等
多协议(HTTP,TCP,UDP)支持异步和反应模型
缓存
默认从注册中心 中获取服务节点,但是如果注册中心的服务节点不可用则使用Ribbon缓存机制来获取服务
Ribbon中的关键组件
- ServerList:可以响应客户端的特定服务的服务器列表。
- ServerListFilter:可以动态获得的具有所需特征的候选服务器列表的过滤器。
- ServerListUpdater:用于执行动态服务器列表更新。
- Rule:负载均衡策略,用于确定从服务器列表返回哪个服务器。
- Ping:客户端用于快速检查服务器当时是否处于活动状态。
- LoadBalancer:负载均衡器,负责负载均衡调度的管理。
二、Ribbon与RestTemplate结合使用
前提准备启动多个服务和,这里通不过配置实例化RestTemplate(带有负载功能的)
@Configuration
public class RestConfig {
@Bean
//使用该注解为RestTemplate添加了负载均衡
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
在使用该RestTemplate对象的类上注入即可
@Service
public class RibbonService {
@Autowired
private RestTemplate restTemplate;
public String hi(String name){
//这里的服务路径是 我们在eureka注册中心设置的服务名,该服务名下有多个服务实例,
//每次基于负载规则来获取实力信息
return restTemplate.getForObject("http://service-another/hi?name="+name,String.class);
}
}
服务注册列表
在注册中心中可以看到一个服务对应多个服务实例,图中圈中的部分是我们进行负载均衡的服务实例
结果: 多次访问多实例的微服务,默认使用轮询来获取两个服务其中之一来提供服务。
三、Ribbon源码分析
0、问题释疑
在本篇博文中,我们源码的分析始终围绕两个核心疑问来进行展开
-
why 使用@LoadBalanced 修饰RestTemplate 就使得RestTemplate对象执行http请求(请求基于服务名)具备了负载请求的能力。
-
哪个组件帮我们实现了真正的负载均衡的功能,怎们实现的
1、@LoadBalanced原理探究
看到项目二的服务,我们不禁有疑问,为什么使用@LoadBalanced 注解 服务的调用就有了负载请求的能力,这里我们需要关注一下LoadBalancerAutoConfiguration类(补充:Ribbon之所以能够实现负载 是因为LoadBlancedClient 该类是Ribbon实现负载均衡的核心接口,这里读者先不用纠结这个类 ,该接口及其实现类会在后面说明,)
1.1、LoadBalancerAutoConfiguration原理分析
//被该@Configuration注解 springBoot启动后进行自动化的配置
@Configuration
//根据条件判断是否触发自动化配置
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
//获取到配置相关的
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
//维护一份使用@LoadBalanced修饰的RestTemplate 列表对象
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
//RestTemplateCustomizer 为RestTemplate 添加LoadBalancerInterceptor拦截器的
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializer(
final List<RestTemplateCustomizer> customizers) {
return new SmartInitializingSingleton() {
@Override
public void afterSingletonsInstantiated() {
for (RestTemplate restTemplate :
LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
}
};
}
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
//创建拦截器
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient,
requestFactory);
}
//将拦截器LoadBalancerInterceptor 添加到restTemplate
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
List<ClientHttpRequestInterceptor> list = new ArrayList<>
(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
}
};
}
}
}
- Ribbon要实现负载均衡自动化配置需要满足如下两个条件:
@ConditionalOnClass(RestTemplate.class):RestTemplate类必须存在于当前工程的环境中。
@ConditionalOnBean(LoadBalancerClient.class):在spring的Bean工程中必须有LoadBalancerClient.class的实现Bean。
- 在自动化配置中主要做三件事:
创建一个LoadBalancerInterceptor的Bean,用于实现对客户端发起请求时进行拦截,以实现客户端负载均衡。
创建一个RestTemplateCustomizer的Bean,用于给RestTemplate增加LoadBalance