微服务架构之均衡组件 Ribbon解析:ILoadBalancer实现解析
ILoadBalancer
ILoadBalancer
是RIbbon
的关键类之一,它是定义软负载均衡操作过程的接口。
在上一小节中,读者应该已经了解到可以通过SpringClientFactory
工厂类的getLoadBalancer
函数获取ILoadBalancer
实例。根据Ribbon
的实例化机制,ILoadBalnacer
实例是在RibbonAutoConfiguration
中被创建生成的。SpringClientFactory
中的实例都是RibbonClientConfiguration
或者自己自定义Configuration类配置的Bean实例。
在RibbonClientConfiguration
中还有IRule
,IPing
和ServerList
相关的配置。使用者可以通过自定义配置类中来配置上述的几个实例。
如图所示,ZoneAwareLoadBalancer
是ILoadBalancer
接口的实现类之一,它是Ribbon
默认的ILoadBalancer
接口的实例。
//RibbonClientConfiguration.java
@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);
}
接下来按照ZoneAwareLoadBalancer
构造函数的参数的顺序来依次看一下与ILoadBalancer
相关的重要的类。IClientConfig、IRule、IPing、ServerList、ServerListFilter和ILoadBalancer,查看BaseLoadBalance
r类,它默认的情况下,实现了以下配置:
ILoadBalancer
ribbonLoadBalancer: ZoneAwareLoadBalancerIClientConfig
ribbonClientConfig: DefaultClientConfigImpl配置IRule
ribbonRule: RoundRobinRule 路由策略IPing
ribbonPing: DummyPing 查看服务器是否可用策略ServerList
ribbonServerList: ConfigurationBasedServerList 获取服务器列表策略ServerListFilter
ribbonServerListFilter: ZonePreferenceServerListFilter 服务器列表过滤策略
上述的类在接下来的文章中会进行一一介绍,本小节将着重讲解ILoadBalancer
的相关原理。
ZoneAwareLoadBalancer
的chooseServer
函数会首先使用DynamicPropertyFactory
来获取平均负载和实例故障率两个阈值,然后调用ZoneAvoidanceRule
的getAvailableZones
函数使用这两个阈值来获取所有可用的Zone列表。
@Override
public Server chooseServer(Object key) {
if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
logger.debug("Zone aware logic disabled or there is only one zone");
return super.chooseServer(key);
}
Server server = null;
try {
//获取当前有关负载均衡的服务器状态集合
LoadBalancerStats lbStats = getLoadBalancerStats();
Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
logger.debug("Zone snapshots: {}", zoneSnapshot);
//使用`DynamicPropertyFactory`获取平均负载的阈值
if (triggeringLoad == null) {
triggeringLoad = DynamicPropertyFactory.getInstance().getDoubleProperty(
"ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2d);
}
//使用`DynamicPropertyFactory`获取平均实例故障率的阈值
if (triggeringBlackoutPercentage == null) {
triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance().getDoubleProperty(
"ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999d);
}
//根据两个阈值来获取所有可用的zone列表。
Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
logger.debug("Available zones: {}", availableZones);
if (availableZones != null && availableZones.size() < zoneSnapshot.keySet().size()) {
//随机从可用的Zone列表中选择一个Zone
String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
logger.debug("Zone chosen: {}", zone);
if (zone != null) {
//得到zone对应的BaseLoadBalancer
BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);
server = zoneLoadBalancer.chooseServer(key);
}
}
} catch (Exception e) {
logger.error("Error choosing server using zone aware logic for load balancer={}", name, e);
}
if (server != null) {
return server;
} else {
logger.debug("Zone avoidance logic is not invoked.");
return super.chooseServer(key);
}
}
而BaseLoadBalancer
对象的chooseServer
函数实现比较简单,就是直接调用它的IRule
成员变量的choose
函数。IRule
就是负责实现负载均衡策略的接口,将会在下一篇进行详细描述。
//BaseLoadBalancer
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
return rule.choose(key);
} catch (Throwable t) {
return null;
}
}
}
ZoneAwareLoadBalancer
的chooseServer
函数会首先使用DynamicPropertyFactory
来获取平均负载和实例故障率两个阈值,然后调用ZoneAvoidanceRule
的getAvailableZones
函数使用这两个阈值来获取所有可用的Zone列表。然后在调用ZoneAvoidanceRule
的randomChooseZone
函数从上述的Zone列表中随机选出一个Zone,最后调用该Zone对应BaseLoadBalancer
实例的chooseServer
函数获取到最终的服务器。ZoneAwareLoadBalancer
会为不同的Zone调用不同的BaseLoadBalancer
的chooseServer
函数,这正体现了它类名的含义。
- 点赞
- 收藏
- 关注作者
评论(0)