SpringCloud系列:
- SpringCloud入门必看例子
- 深入理解SpringCloud源码探究篇 | Eureka服务端源码分析
- 深入理解SpringCloud源码探究篇 | Eureka客户端源码分析
- 深入理解SpringCloud源码探究篇 | ribbon源码分析
- 深入理解SpringCloud源码探究篇 | Feign源码分析
下面先利用白话文来描述下ribbon的工作流程
Ribbon:
自动配置类RibbonClientConfiguration和EurekaRibbonClientConfiguration配置类进行各bean转载包括以下五大组件和ZoneAwareLoadBalancer初始化操作
五大组件:
ServerList:定义获取服务器列表 ,默认实现DiscoveryEnabledNIWSServerList
ServerListFilter:对ServerList服务器列表进行二次过滤 ,默认实现ZonePreferenceServerListFilter
ServerListUpdater: 定义服务更新策略 ,默认实现PollingServerListUpdater
IPing: 检查服务列表是否存活 默认实现NIWSDiscoveryPing
IRule :根据算法中从服务列表中选取一个要访问的服务 ,默认实现RoundRobinRule
ZoneAwareLoadBalancer: (ILoadBalancer默认的实现),ZoneAwareLoadBalancer是DynamicServerListLoadBalancer的子类,增加zone策略,DynamicServerListLoadBalancer对以上五大组件进行组合使用,调用ServerList接口,DiscoveryEnabledNIWSServerList(默认配置).getInitialListOfServers:从eureka客户端服务列表缓存中(DiscoveryClient.localRegionApps)获取服务列表 ;
ServerListUpdater定义服务更新策略 (默认PollingServerListUpdater),这里DynamicServerListLoadBalancer初始化过程中会传入自己实现的ServerListUpdater.UpdateAction对象调用ServerListUpdater.start(UpdateAction)启动一个定时任务,任务中进程调用传入UpdateAction.doUpdate方法,实际调用的是DynamicServerListLoadBalancer.updateListOfServers方法然后调用ServerList的getUpdatedListOfServers方法进行服务拉取更新,接着updateListOfServers方法里拿到的服务列表之后会进行调用ServerListFilter的getFilteredListOfServers进行过滤筛选。总而言之就是DynamicServerListLoadBalancer初始化过程中会调用PollingServerListUpdater.start启动一个定时任务进行实时调用DiscoveryEnabledNIWSServerList.getUpdatedListOfServers去获DiscoveryClient里的服务列表缓存(DiscoveryClient.localRegionApps)取最新服务列表接着通过ServerListFilter进行过滤,然后将服务列表setServersList放在自己的缓存allServerList里(这个是BaseLoadBalancer的allServerList)。接着就是IRule :根据算法中从服务列表中选取一个要访问的服务 ,默认RoundRobinRule轮询算法。DynamicServerListLoadBalancer实现了ILoadBalancer的chooseServer方法,该实现方法里调用的就是IRule.choose,自然这里说的就是RoundRobinRule实现的方法choose,choose调用BaseLoadBalancer获取到服务缓存列表allServerList,然后进过一系列操作选择出一个调用的服务进行返回。
以上提到的五大组件包括ILoadBalancer都是可以通过配置来进行自由选择实现类:
# 负载均衡类
{服务名}.ribbon.NFLoadBalancerClassName=ZoneAwareLoadBalancer
# 负载均衡规则类
{服务名}.ribbon.NFLoadBalancerRuleClassName=AvailabilityFilteringRule
# 心跳检测类
{服务名}.ribbon.NFLoadBalancerPingClassName=NIWSDiscoveryPing
# 服务列表类
{服务名}.ribbon.NIWSServerListClassName=DiscoveryEnabledNIWSServerList
# 服务过滤类
{服务名}.ribbon.NIWSServerListFilterClassName=ZonePreferenceServerListFilter
RibbonClientConfiguration配置类
@Bean
@ConditionalOnMissingBean
public IRule ribbonRule(IClientConfig config) {
if (this.propertiesFactory.isSet(IRule.class, name)) {
return this.propertiesFactory.get(IRule.class, config, name);
}
ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
rule.initWithNiwsConfig(config);
return rule;
}
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
if (this.propertiesFactory.isSet(IPing.class, name)) {
return this.propertiesFactory.get(IPing.class, config, name);
}
return new DummyPing();
}
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerList<Server> ribbonServerList(IClientConfig config) {
if (this.propertiesFactory.isSet(ServerList.class, name)) {
return this.propertiesFactory.get(ServerList.class, config, name);
}
ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
serverList.initWithNiwsConfig(config);
return serverList;
}
@Bean
@ConditionalOnMissingBean
public ServerListUpdater ribbonServerListUpdater(IClientConfig config) {
return new PollingServerListUpdater(config);
}
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
return this.propertiesFactory.get(ILoadBalancer.class, config, name);
}
return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
serverListFilter, serverListUpdater);
}
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
return this.propertiesFactory.get(ServerListFilter.class, config, name);
}
ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
filter.initWithNiwsConfig(config);
return filter;
}
EurekaRibbonClientConfiguration配置类

这两个配置类中我们可以发现初始化了ribbon的几大组件;这里我们可以看到先是从propertiesFactory配置中获取对应组件的自定义配置:
以上也证明我们前面提到的可以进行自定义配置个大组件的实现类
ServerList接口
有两个方法,第一个为初始服务列表获取,第二个方法为更新缓存服务列表
ServerList定义获取服务器列表 ,默认实现DiscoveryEnabledNIWSServerList:
这里两个实现方法均是调用obtainServersViaDiscovery方法进行服务列表拉取:
通过调用DiscoveryClient.getInstancesByVipAddress获取InstanceInfo服务信息列表:
从上面的调用上可以看到,从 DiscoveryClient的localRegionApps缓存中获取到服务列表信息然后进行返回
ServerListFilter接口
仅提供一个方法
ServerListFilter对ServerList服务器列表进行二次过滤 ,默认实现ZonePreferenceServerListFilter
ServerListUpdater接口
ServerListUpdater定义服务更新策略,默认实现PollingServerListUpdater:
实现start方法进行开启一个定时任务,目的就是刷新ribbon服务列表缓存
实际上调用的是传入的UpdateAction的doUpdate()方法,该方法在DynamicServerListLoadBalancer被实现重写,后面再描述
IRule接口
IRule根据算法从服务列表中选取一个要访问的服务 ,默认实现RoundRobinRule轮询:
以上可以清楚看到从ILoadBalancer的缓存列表allServerList里获取出所有的服务,然后进行轮询选择一个服务进行返回
ILoadBalancer
ILoadBalancer是ribbon整个的核心,相当于一个中央控制器,默认实现ZoneAwareLoadBalancer:
ZoneAwareLoadBalancer是DynamicServerListLoadBalancer的子类,增加zone策略,DynamicServerListLoadBalancer对以上五大组件进行组合使用:
我们先来看DynamicServerListLoadBalancer该类被初始化是做了哪些具体操作:
其他的操作均是将五大组件bean赋值于DynamicServerListLoadBalancer中,我们重点来看看restOfInit:
该方法调用enableAndInitLearnNewServersFeature以及updateListOfServers,我们先看enableAndInitLearnNewServersFeature:
这里我们可以清楚看到它调用了ServerListUpdater的start方法,start我们前面已经讲到就是启动了一个定时任务,具体操作线程我们需要看这个传入的UpdateAction的具体实现,DynamicServerListLoadBalancer实现了ServerListUpdater.UpdateAction:
然后doUpdate实际调用的是自己的updateListOfServers方法:
以上可以清楚看到利用ServerList的实现DiscoveryEnabledNIWSServerList调用getUpdatedListOfServers,该方法前面已经分析过,就是向eureka客户端的localRegionApps缓存进行服务的拉取操作然后返回服务列表。
接着调用ServerListFilter的实现进行二次过滤,这里我就不具体分析这个了。接着就是调用updateAllServerList(servers),然后接着setServersList对服务列表放入进BaseLoadBalancer的allServerList里
到这里也就是说DynamicServerListLoadBalancer初始化过程中调用ServerListUpdater.start方法进行启动一个定时任务来调用updateListOfServers方法,进行服务拉取操作以及过滤。我们回到restOfInit方法启动任务之后接着下一步还是调用updateListOfServers,其实就是一起动就去拉取服务列表。总而言之就是初始化过程进行服务拉取进自己的allServerList缓存列表中,然后定时进行服务拉取更新操作。
ILoadBalancer的对外提供中比较主要的就是chooseServer方法,用来服务挑选,我们直接看DynamicServerListLoadBalancer的父类BaseLoadBalancer的chooseServer方法:
以上可以看到利用IRule实现的choose进行服务挑选,前面初始化时已经将其实现类RoundRobinRule赋值了进来,前面也已经提到过RoundRobinRule的choose方法,这里不再赘述。
总结
ILoadBalancer被默认初始化ZoneAwareLoadBalancer,然后接着进行向eureka客户端的localRegionApps缓存中获取服务列表接着过滤后放入自己的缓存allServerList里。接着调用ServerListUpdater.start启动一个定时任务进行服务的拉取更新操作和过滤。在对外提供使用过程中调用chooseServer方法进行调用IRule的choose方法进行服务的挑选和具体服务返回。