微服务架构之均衡组件 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,查看BaseLoadBalancer类,它默认的情况下,实现了以下配置:
ILoadBalancerribbonLoadBalancer: ZoneAwareLoadBalancerIClientConfigribbonClientConfig: DefaultClientConfigImpl配置IRuleribbonRule: RoundRobinRule 路由策略IPingribbonPing: DummyPing 查看服务器是否可用策略ServerListribbonServerList: ConfigurationBasedServerList 获取服务器列表策略ServerListFilterribbonServerListFilter: 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)