一、引言
讲解Ribbon之前,先提4个问题,作为引子
1. 什么是负载均衡, 为什么要有负载均衡?
2. 你所知道的负载均衡有哪些?
3. 负载均衡主要体现在CAP中的哪些?
4. 如果让你设计一个负载均衡,需要考虑哪些点?
二、Ribbon出现的时机
1. 服务器端负载均衡器
传统上,Load Balancers是放置在服务器端的组件。当请求来自 客户端 时,它们将转到负载均衡器,负载均衡器将为请求指定 服务器。负载均衡器使用的最简单的算法是随机指定。在这种情况下,大多数负载平衡器是用于控制负载平衡的硬件集成软件。
重点:
对客户端不透明,客户端不知道服务器端的服务列表,甚至不知道自己发送请求的目标地址存在负载均衡器。
服务器端维护负载均衡服务器,控制负载均衡策略和算法。
2. 客户端负载均衡器
当负载均衡器位于 客户端 时,客户端得到可用的服务器列表然后按照特定的负载均衡策略,分发请求到不同的 服务器 。
重点:
对客户端透明,客户端需要知道服务器端的服务列表,需要自行决定请求要发送的目标地址。
客户端维护负载均衡服务器,控制负载均衡策略和算法。
目前单独提供的客户端实现比较少,大部分都是在框架内部自行实现。
三、Ribbon 介绍
Ribbon是Netflix公司开源的一个客户单负载均衡的项目,可以自动与 Eureka 进行交互。它提供下列特性:
负载均衡
容错
以异步和反应式模型执行多协议 (HTTP, TCP, UDP)
缓存和批量
Ribbon中的关键组件
四、Ribbon使用
1.在启动类中,声明一个RestTemplate的bean,用@LoadBalanced注解修饰:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
2. 在进行http调用的地方,通过@Autowired方式,注入RestTemplate,再通过restTemplate调用。调用时,写服务名就可以,比如按照下面这种方式调用。
return this.restTemplate.getForEntity("http://MICROSERVICE-PROVIDER/provider", String.class).getBody();
五、Spring Cloud Ribbon源码分析
由于源码分析一般比较枯燥,采用一种新的方式。如果有你来设计一套负载均衡,你会考虑哪些点。 一问一答的形式来层层解析
1. 如何引入负载均衡
重点: 使用负载均衡的开发量还是挺简单的,不过为什么在restTemplate上加个注解,通过restTemplate进行调用,就可以做到负载均衡呢,这里就需要研究下源码才能知道原因了。
2. 如何对请求进行拦截
重点:
注释中说明这个类是为Ribbon做自动配置的,类上的@Configuration说明这是一个配置类,在当前项目中存在RestTemplate类、并且存在LoadBalancerClient接口的实现类时,就满足了自动化配置的条件。
在LoadBalancerAutoConfiguration类中,创建了一个LoadBalancerInterceptor拦截器,还维护了一个被@LoadBalanced修饰的RestTemplate列表,在初始化的时候,会为每个restTemplate实例添加LoadBalancerInterceptor拦截器。
3. 如何对请求的服务进行解析
重点:
由于在自动配置类中,对restTemplate实例添加了LoadBalancerInterceptor拦截器,所以,当用restTemplate发送http请求时,就会执行这个拦截器的intercept方法。
intercept方法中,会根据request.getURI(),获取请求的uri,再获取host,我们在发送http请求的时候,是用的服务名作为host,所以,这里就会拿到服务名,再调用具体LoadBalancerClient实例的execute方法,发送请求。
4. 如何从注册中心获取服务列表
重点:
在这个方法中,就是通过eurekaClient去注册中心获取服务,将状态为up的服务实例封装成DiscoveryEnabledServer对象,然后放入列表返回,这就是获取服务列表的流程
5. 如何选择最匹配的服务
重点:
这个方法会根据server的zone和可用性来选择具体的实例,返回一个Server对象。需要理解zone的概念
6. 如何调用远程的服务
重点:
LoadBalancerClient的实现类为RibbonLoadBalancerClient,最终的负载均衡请求由它来执行。从一系列服务中,根据选择的服务,远程调用。比较经典的有http请求,ribbon封装的请求
7. 客户端如何维护服务列表
重点:
里面有个start方法,实现了Runnable接口,run方法里调用UpdateAction的doUpdate,之后再启动一个定时任务,执行这个方法。定时任务传入的两个时间参数:initialDelayMs和refreshIntervalMs,任务启动后一秒开始执行,并且每隔三十秒执行一次,用于刷新列表。构造DynamicServerListLoadBalancer实例的时候,就会启动一个定时任务了,一开始先获取服务列表,之后每隔三十秒获取一次。负载均衡时,就是通过负载均衡算法在实例列表中选择一个,发送请求。
六、 Spring Cloud Ribbon处理流程
七、Spring Cloud Ribbon源码跟踪图
八、小结
1. 分析了Spring Cloud Ribbon的核心处理源码-------功能强大
2. 跟踪了Spring Cloud Ribbon的处理流程主线-------架构优雅
3. 启发了如何自己来设计一套负载均衡中间件------- 流程清晰