ribbon源码浅析
-
Ribbon 自动配置提前加载
RibbonAutoConfiguration被@AutoConfigureBefore(LoadBalanceAutoConfiguration)标记,会在负载均衡配置之前初始化,创建实现了LoadBalancerClient接口的RibbonLoadBalancerClient,这是 Ribbon 实现服务实例选择的核心。 -
@LoadBalanced触发增强逻辑当RestTemplate被@LoadBalanced注解修饰时,LoadBalanceAutoConfiguration会介入配置,创建LoadBalancerInterceptor、RestTemplateCustomizer和SmartInitializingSingleton组件。 -
拦截器注入与绑定
LoadBalancerInterceptor以LoadBalancerClient为依赖创建;RestTemplateCustomizer会将该拦截器添加到所有被@LoadBalanced修饰的RestTemplate的拦截器链中;SmartInitializingSingleton会在所有单例 Bean 初始化完成后,确保所有目标RestTemplate都成功绑定拦截器。 -
请求拦截与负载均衡执行被增强的
RestTemplate发起请求时,会先被LoadBalancerInterceptor拦截,调用LoadBalancerClient解析服务名,通过 Ribbon 内置的负载均衡策略从注册中心获取的实例列表中选择一个目标实例,替换请求地址为实例真实 IP 和端口,再发起实际调用,实现客户端侧负载均衡。
当代码执行 restTemplate.getForObject("http://microservice-provider-user/" + id, User.class) 时,Ribbon 的核心执行流程如下:
- 请求拦截:调用被
@LoadBalanced修饰的RestTemplate发起请求,请求会被LoadBalancerInterceptor.intercept()方法拦截。 - 负载均衡器获取:拦截器调用
LoadBalancerClient.execute()方法,通过getLoadBalancer(serviceId)获取对应服务的ILoadBalancer实例,即ZoneAwareLoadBalancer。 - 负载均衡器初始化:
ZoneAwareLoadBalancer由RibbonClientConfiguration配置类初始化,其父类DynamicServerListLoadBalancer在初始化时会注入PollingServerListUpdater、ServerList和IPing组件。 - 服务列表定时拉取:
DynamicServerListLoadBalancer调用restOfInit()方法,启动PollingServerListUpdater.start(),开启定时任务。该任务会周期性调用updateListOfServers()。 - 从Nacos获取实例:
updateListOfServers()调用NacosServerList.getUpdatedListOfServers(),通过namingService.selectInstances()从Nacos客户端缓存中拉取服务实例列表。 6. 更新本地实例列表:将拉取到的实例列表通过updateAllServerList()更新到BaseLoadBalancer中,并调用setServersList()完成本地缓存更新。 7. 选择服务实例:ZoneAwareLoadBalancer根据内置的负载均衡策略,从最新的实例列表中选择一个可用的服务实例。 8. 请求转发:将原请求中的服务名替换为选中实例的真实IP和端口,完成请求转发,实现客户端侧负载均衡。
Ribbon 选择服务实例时,从 getServer(loadBalancer) 入口调用 loadBalancer.chooseServer("default"),进入 BaseLoadBalancer.chooseServer(key) 方法,该方法会将实例选择逻辑委托给配置的 IRule 实现类,配置优先级为配置文件优先于 Java 代码配置,默认使用 ZoneAvoidanceRule,它继承自 PredicateBasedRule,最终执行 rule.choose(key) 方法,先通过谓词过滤出可用实例,再基于轮询算法,从 0 开始计数、每次请求自增 1 后对实例列表长度取模,得到目标实例下标,完成服务实例的选择。