ribbon源码浅析

0 阅读2分钟

ribbon源码浅析

  • Ribbon 自动配置提前加载RibbonAutoConfiguration@AutoConfigureBefore(LoadBalanceAutoConfiguration) 标记,会在负载均衡配置之前初始化,创建实现了 LoadBalancerClient 接口的 RibbonLoadBalancerClient,这是 Ribbon 实现服务实例选择的核心。

  • @LoadBalanced 触发增强逻辑RestTemplate@LoadBalanced 注解修饰时,LoadBalanceAutoConfiguration 会介入配置,创建 LoadBalancerInterceptorRestTemplateCustomizerSmartInitializingSingleton 组件。

  • 拦截器注入与绑定LoadBalancerInterceptorLoadBalancerClient 为依赖创建;RestTemplateCustomizer 会将该拦截器添加到所有被 @LoadBalanced 修饰的 RestTemplate 的拦截器链中;SmartInitializingSingleton 会在所有单例 Bean 初始化完成后,确保所有目标 RestTemplate 都成功绑定拦截器。

  • 请求拦截与负载均衡执行被增强的 RestTemplate 发起请求时,会先被 LoadBalancerInterceptor 拦截,调用 LoadBalancerClient 解析服务名,通过 Ribbon 内置的负载均衡策略从注册中心获取的实例列表中选择一个目标实例,替换请求地址为实例真实 IP 和端口,再发起实际调用,实现客户端侧负载均衡。 image.png

当代码执行 restTemplate.getForObject("http://microservice-provider-user/" + id, User.class) 时,Ribbon 的核心执行流程如下:

  1. 请求拦截:调用被 @LoadBalanced 修饰的 RestTemplate 发起请求,请求会被 LoadBalancerInterceptor.intercept() 方法拦截。
  2. 负载均衡器获取:拦截器调用 LoadBalancerClient.execute() 方法,通过 getLoadBalancer(serviceId) 获取对应服务的 ILoadBalancer 实例,即 ZoneAwareLoadBalancer
  3. 负载均衡器初始化ZoneAwareLoadBalancerRibbonClientConfiguration 配置类初始化,其父类 DynamicServerListLoadBalancer 在初始化时会注入 PollingServerListUpdaterServerListIPing 组件。
  4. 服务列表定时拉取DynamicServerListLoadBalancer 调用 restOfInit() 方法,启动 PollingServerListUpdater.start(),开启定时任务。该任务会周期性调用 updateListOfServers()
  5. 从Nacos获取实例updateListOfServers() 调用 NacosServerList.getUpdatedListOfServers(),通过 namingService.selectInstances() 从Nacos客户端缓存中拉取服务实例列表。 6. 更新本地实例列表:将拉取到的实例列表通过 updateAllServerList() 更新到 BaseLoadBalancer 中,并调用 setServersList() 完成本地缓存更新。 7. 选择服务实例ZoneAwareLoadBalancer 根据内置的负载均衡策略,从最新的实例列表中选择一个可用的服务实例。 8. 请求转发:将原请求中的服务名替换为选中实例的真实IP和端口,完成请求转发,实现客户端侧负载均衡。 image.png

Ribbon 选择服务实例时,从 getServer(loadBalancer) 入口调用 loadBalancer.chooseServer("default"),进入 BaseLoadBalancer.chooseServer(key) 方法,该方法会将实例选择逻辑委托给配置的 IRule 实现类,配置优先级为配置文件优先于 Java 代码配置,默认使用 ZoneAvoidanceRule,它继承自 PredicateBasedRule,最终执行 rule.choose(key) 方法,先通过谓词过滤出可用实例,再基于轮询算法,从 0 开始计数、每次请求自增 1 后对实例列表长度取模,得到目标实例下标,完成服务实例的选择。

image.png