暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring Cloud Feign【源码篇】Feign 如何调用Ribbon进行客户端负载均衡

花好夜猿 2019-06-30
582

参考资料:Spring Cloud 官网

相关版本:Spring Boot 2.1.5.RELEASE 、Spring Cloud Greenwich.SR

回顾

Spring Cloud Feign【源码篇】Feign 如何进行服务间请求调用 中,提到了 Feign 如何进行服务调用的。

Feign 在封装了相关的请求参数 RequestTemplate 后,发起服务远程请求调用。 代码如下:

从源码中可以很直观的看到真正发起服务请求调用的是 feign.Client#execute  

feign.Client#execute  为切入点,进行分析。

Feign 如何选择 Ribbon 作为负载均衡客户端

查看 feign.Client ,feign.Client 是一个接口,它有两个实现类

  • feign.Client.Default

  • org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient

其中 LoadBalancerFeignClient 为 Ribbon 负载均衡客户端实现类

Feign 是如何注册 LoadBalancerFeignClient  作为其客户端调用实现的。首先想到的就是自动配置类 FeignRibbonClientAutoConfiguration

聚焦 FeignRibbonClientAutoConfiguration

关注点:

  • 1、 @ConditionalOnClass({ ILoadBalancer.class, Feign.class })
    其中 ILoadBalancer.class 是 Ribbon 依赖中的类。换句话说,该配置需要 Ribbon 和 Feign 的相关依赖都引入才会生效。

  • 2、 @AutoConfigureBefore(FeignAutoConfiguration.class)
    如果该自动配置类生效,则在 FeignAutoConfiguration 之前进行配置,因为 FeignAutoConfiguration 关联到了 Feign Client 的代理对象的实例化,而其中真实发起请求调用的 Client 对象实例在 Feign Client 调用 Fiegn.Build 进行实例化时Client 实现对象需要提前实例化。 换句话说,如果 Client 对应Ribbon 的实现类 LoadBalancerFeignClient 存在,就是用 Ribbon 的负载均衡客户端进行请求调用处理,反之,使用默认的 feign.Client.Default。

  • 3、@Import({DefaultFeignLoadBalancedConfiguration.class})
    DefaultFeignLoadBalancedConfiguration 是一个 Bean 配置类,对 LoadBalancerFeignClient 进行了实例化配置。

总结

1、 Feign Client 在执行请求调用最终调用的是 Client#execute
2、 Client 是一个接口,其实现类 LoadBalancerFeignClient  和 Default。 在 Feign 代理对象实例化作为属性存入 Feign Client 代理对象中。
3、 当应用依赖中引入 Ribbon 相关依赖时,在 Feign 代理对象实例化前,会先生成 Client Ribbon 实现类 LoadBalancerFeignClient 的实例对象。反之,使用默认的 feign.Default 。

LoadBalancerFeignClient 如何衔接 Ribbon 实现客户端负载均衡

前提:Feign Client 最终执行调用的是 Client#execute 方法,而此时 Client 实现类是 LoadBalancerFeignClient。

调用 LoadBalancerFeignClient#execute 需要传递两个参数:Request 和 Request.Options 

其中参数 Request 数据结构如下

而 Request.Options 是进行 Ribbon 配置获取的选择条件

聚焦 LoadBalancerFeignClient#execute

代码 LoadBalancerFeignClient#execute 大体流程如下

  • step1、封装 Ribbon 请求信息

  • step2、获取 Ribbon 请求相关配置信息
    LoadBalancerFeignClient#getClientConfig

  • step3、根据封装的 RibbonRequest (ribbon请求) 和 requestConfig (ribbon请求配置属性) 发起请求。

下面具体看看 step2:获取配置信息 和step3:发起请求

步骤二详情:获取 Ribbon 请求配置参数信息

聚焦LoadBalancerFeignClient#getClientConfig

根据 Request.Options 选择 ribbon 配置的方式

  • 选择一:通过调用 SpringClientFactory#getClientConfig 获取。
    SpringClientFactory 在 Ribbon 的自动配置类 RibbonAutoConfiguration#springClientFactory 中进行实例化。
    在FeignRibbonClientAutoConfiguration 自动配置类 进行 LoadBalancerFeignClient Bean 配置实例化作为构造参数传入。

  • 选择二:自定义实例化 FeignOptionsClientConfig 配置类。
    FeignOptionsClientConfig 继承了 DefaultClientConfigImpl 。 DefaultClientConfigImpl 实现了 IClientConfig。与方式一获取到的 Ribbon 配置实现自同一个接口 IClientConfig

步骤三详情:根据 RibbonRequest 和 IClientConfig 发起请求。

LoadBalancerFeignClient#execute return 执行的代码如下

lbClient(clientName)
.executeWithLoadBalancer(ribbonRequest, requestConfig)
.toResponse();

代码中,两个主要执行逻辑

  • LoadBalancerFeignClient#lbClient

  • FeignLoadBalancer#executeWithLoadBalancer

分别来看看这两个执行逻辑。

聚焦LoadBalancerFeignClient#lbClient

LoadBalancerFeignClient#lbClient 逻辑:通过 clientName 获取 FeignLoadBalancer 对象。

而 FeignLoadBalancer 对象的获取是从 CachingSpringLoadBalancerFactory#create 中获取的。

CachingSpringLoadBalancerFactory 是一个缓存工厂,缓存了 clientName 对应 FeignLoadBalancer 关系结构。

通过代码,我们可以知道 FeignLoadBalancer 是实现 Feign 客户端负载均衡调用的一个类, FeignLoadBalancer 对 Ribbon ILoadBalancer 进行了封装,将 RIbbon 的数据 如:ILoadBalancer, IClientConfig 直接以成员变量的形式存入 FeignLoadBalancer 中。

CachingSpringLoadBalancerFactory 在 FeignRibbonClientAutoConfiguration 自动配置类中进行实例化,然后被作为实例化 LoadBalancerFeignClient 的构造参数。
在使用 Eureka Server 来维护服务列表时 FeignLoadBalancer 中的 ILoadBalancer 对应的是 DynamicServerListLoadBalancer ,DynamicServerListLoadBalancer 中维护的服务列表信息动态从 Eureka Server
中更新。 友情链接:
客户端负载均衡:Ribbon

聚焦 FeignLoadBalancer#executeWithLoadBalancer

在得到 FeignLoadBalancer 客户端负载均衡实例对象之后,就是开始调用 FeignLoadBalancer#executeWithLoadBalancer。

而 FeignLoadBalancer#executeWithLoadBalancer 方法是由其父类 AbstractLoadBalancerAwareClient 实现的。AbstractLoadBalancerAwareClient 属于 Ribbon 模块。

聚焦 AbstractLoadBalancerAwareClient#executeWithLoadBalancer

该方法有两个主要逻辑:

  • LoadBalancerCommand#submit
    该方法实现客户端负载均衡,根据 IRule(官方默认实现: ZoneAvoidanceRule) 从 ILoadBalancer(Eureka服务实例管理,默认:DynamicServerListLoadBalancer) 中获取一个Server实例对象。

  • this.execute(requestForServer, requestConfig)
    根据 LoadBalancerCommand#submit 获取到的 Server ,调用 FeignLoadBalancer#execute 发起服务调用请求,并返回结果。

针对 ZoneAvoidanceRule 规则等不进行展开。

总结

1、LoadBalancerFeignClient#execute() 是整个 Feign Client 的执行入口
2、LoadBalancerFeignClient#execute() 方法主线逻辑:

  • 封装 RibbonReuqest 请求对象

  • 从容器中获取 Ribbon 请求配置参数信息 IConfigClient

  • 根据 RibbonRequest 和 IConfigClient 构造 FeignLoadBalancer 。

3、FeignLoadBalancer 根据 Ribbon 的 IRule 规则从 Iloadbalancer 获取一个服务实例 server。
4、FeignLoadBalancer#execute 根据获取到的服务实例 Server 发起请求调用。然后返回。

最后总结

首先我们再来回顾一下Feign Client 发起请求的代码:

Feign Client 发起请求是由 Client 来进行处理。Client 默认实现类 Default 不支持客户端负载均衡功能。

当项目应用中引入了 Ribbon 相关依赖,触发自动配置类 FeignRibbonClientAutoConfiguration。

Feign Client 发起请求的 Client 实例对象由 Client.Default 变更为 LoadBalancerFeignClient。

LoadBalancerFeignClient#execute 发起请求调用,会生成 FeignLoadBalancer 来实现客户端负载均衡。

FeignLoadBalancer 其实就是 Feign 对 Ribbon 的一层封装,实际调用的就是 Ribbon 的负载均衡逻辑,包括 IRule 等 进行服务实例的获取。

-- END --

       长按二维码      

关注 [ WTF名字好难取 ] 公众号


往期回顾


Spring Cloud Feign【源码篇】Feign 如何进行服务间请求调用

Spring Cloud Feign【源码篇】Feign Hystrix Support

Spring Cloud Hystrix【理论篇】

Spring Cloud Hystrix【应用篇】

Spring Cloud Hystrix【应用篇】 Hystrix Dashboard

文章转载自花好夜猿,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论