还没有秃头吗?你真的需要大牛来教你如何深入解析Ribbon源码了

2022-10-28 15:14:44 浏览数 (1)

本章给大家讲解的内容是Ribbon源码解析。

Ribbon源码解析

Ribbon 的 源 码 解 析 我 们 从 @LoadBalanced 开 始 讲 起 , 添 加@LoadBalanced注解后AsyncRestTemplate就具备了负载均衡的能力,代码如下:

在初始化HTTP客户端时会加载Ribbon的拦截代码,同时根据配置文件中设置的负载均衡策略或者代码实现定制好的负载均衡策略,实现HTTP请求过程中的后端服务分发。所以源码解读可以分为两个部分。

● 初始化构造过程:获取@LoadBalanced注解标记RestTemplate或者AsyncRestTemplate,然后添加拦截器。

● 负载均衡服务选择过程:在Ribbon设定的负载均衡策略下,从服务集群中根据预定的负载均衡策略实现后端服务的选取及请求转发。

如下图所示是一个简要的Ribbon初始化及调用拦截HTTP请求实现负载均衡的流程。

Ribbon的初始化过程

@LoadBalanced注解对RestTemplate做了标记,使用Ribbon的自动化配置加载类实现对负载均衡客户端的加载,在生成的RestTemplate的Bean上添加注解后,它会配置LoadBalancerClient。首先我们看一下LoadBalancerClient的源码实现:

说明:LoadBalancerClient是一个接口,里面有三个方法。

● ServiceInstance choose(String serviceId)方法,根据传入的serviceId(服务名),从负载均衡器中选择一个服务实例,服务实例通过ServiceInstance类来表示。 ● execute方法,使用从负载均衡器中选择的服务实例来执行请求内容。 ● URI reconstructURI ( ServiceInstance instance , URIoriginal ) 方 法 :用 来 重 新 构 建 URI 。我 们 通 过RestTemplate 请 求 后 端 服 务 时 会 使 用 serviceId ( 服 务名),这个方法会把请求的URI进行转换,返回host port,再通过host port的形式去请求服务。

从META-INF/spring.factories文件来看Ribbon的自动化加载机制,主要是Spring Common的LoadBalancerClient的初始化和加载过程:

Ribbon的自动配置实现

下面是Ribbon的自动化配置实现:

● 说 明 1 # :Ribbon 将 所 有 标 记 @LoadBalanced 注 解 的RestTemplate保存到一个List集合中。

● 说 明 2 # :Ribbon 借 助 了 Spring IoC 容 器 的 SmartInitializingSingleton机制。实现该接口后,当所有单 例 Bean 都 被 初 始 化 完 成 后 , 容 器 会 调 用afterSingletonsInstantiated实现RestTemplateCustomizer的customize定制化方法。

● 说 明 3 # :获 取 RestTemplate 的 interceptors , 在 构 造LoadBalancerInterceptor时需要传入LoadBalanceClient实例参数,LoadBalanceClient是一个接口,具体实现类将实现choose(服务实例选择)和execute(请求转发执行)方法,这一步完成Ribbon负载均衡策略Bean的构造。

● 说明4:将说明3#中构造的loadBalancerInterceptor Bean实例注入RestTemplate的定制化Bean中,这一步骤也会在说明2# 的 afterSingletonsInstantiated 方 法 中 被 调 用 , 完 成RestTemplate的定制化及与LoadBalancerInterceptor实例关联。

Ribbon的重试策略

对于Ribbon的重试策略,可以参考RetryTemplate类的实现,它可以实现Ribbon的重试策略对RestTemplate的拦截控制,代码如下:

Ribbon的负载均衡行为逻辑

Ribbon主要在Spring Cloud Netflix中完成负载均衡行为的初始化过程,这部分初始化主要依赖spring-cloud-netflix-core模块。

下面我们看一下Ribbon在Spring Cloud中是如何实现初始化的,首先看Ribbon的自动加载机制META-INF/spring.factories:

下面是RibbonAutoConfiguration的实现,从源码中可以看到它会构 造 SpringClientFactory , LoadBalancerClient 初 始 化 构 造 需 要SpringClientFactory作为参数。

在Ribbon的自动化配置类中会通过RibbonClientConfiguration配置类获取YAML配置中的负载均衡配置,构造SpringClientFactory并生成LoadBalancer,代码如下:

可以看到,在RestTemplate执行HTTP请求时是如何通过Ribbon设置 的 拦 截 机 制 构 造 HTTP 客 户 端 请 求 的 。RestTemplate 继 承 了InterceptingHttpAccessor,而父类InterceptingHttpAccessor提供了获取及添加拦截器的方法,代码如下:

InterceptingHttpAccessor抽象类的作用正是为我们添加自定义的拦截器:

这段代码的实际拦截器的实例注入(依赖注入)过程其实来自上面的Ribbon自动化配置类 LoadBalancerAutoConfiguration,在配置类中它已经完成了拦截器的注册。

下面我们看一下当拦截HTTP请求后,RestTemplate将会执行哪些操作。首先,RestTemplate执行HTTP请求,从RestTemplate的实现源码 中 , 不 难 发 现 请 求 最 终 都 会 执 行 到 doExecute 方 法 中 。查 看doExecute 的 调 用 链 路 , 我 们 发 现 它 都 会 执 行 到LoadBalancerInterceptor的intercept拦截方法中,代码如下:

我们跟进到Ribbon的执行 拦 截 逻 辑, LoadBalancerClient.execute方法的具体代码如下:

从 上 述 代 码 可 知 , Ribbon 首 先 根 据 服 务 的 serviceId 调 用getLoadBalancer方法得到ILoadBalancer。创建loadBalancer的过程可以理解为组装选取服务的规则、服务集群的列表、检验服务是否存活等特性的过程(加载RibbonClientConfiguration配置类)。这里的核 心 是 getServer 方 法 , 根 据 ILoadBalancer 来 选 取 一 个 具 体 的Server,选取的过程会按照服务的负载均衡策略、服务列表、服务存活 情 况 进 行 筛 选 判 断 , 对 我 们 自 定 义 的 负 载 均 衡 策 略 将 执 行chooseServer操作,最终根据这些约束选择一个后端的服务实例。

本文给大家讲解的内容是Ribbon源码解析

  1. 下篇文章给大家讲解的内容是微服务容错与隔离:隔离机制
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。

0 人点赞