【源码】Spring Cloud —— Ribbon 2 ILoadBalancer
前言
上一章节主要介绍了:
- RibbonClientConfigurationRegistrar,注册对应 RibbonClient 的组件到容器中,由 SpringClientFactory 创建管理对应的 上下文
- LoadBalancerClient,负载均衡 顶层接口,底层委托给 ILoadBalancer 实现
本章节结合源码介绍 ILoadBalancer 接口及其部分实现类
版本
Spring Cloud Netflix 版本:2.2.3.RELEASE
ILoadBalancer
public interface ILoadBalancer {
// 服务实例添加
public void addServers(List<Server> newServers);
// 筛选服务实例
public Server chooseServer(Object key);
// 标记服务下线
public void markServerDown(Server server);
// @Deprecated,见下面两个方法
@Deprecated
public List<Server> getServerList(boolean availableOnly);
// 存活服务列表获取
public List<Server> getReachableServers();
// 所有服务列表获取
public List<Server> getAllServers();
}
顶层接口,由 com.netflix.ribbon
依赖提供,定义了 服务实例获取、服务列表获取 等相关方法
AbstractLoadBalancer
public abstract class AbstractLoadBalancer implements ILoadBalancer {
// 服务实例状态枚举
public enum ServerGroup{
ALL,
STATUS_UP,
STATUS_NOT_UP
}
// chooseServer 委托给 chooseServer(null)
public Server chooseServer() {
return chooseServer(null);
}
// 根据状态筛选服务实例列表
public abstract List<Server> getServerList(ServerGroup serverGroup);
// LoadBalancerStats:LoadBalancer 相关统计封装
public abstract LoadBalancerStats getLoadBalancerStats();
}
ILoadBalancer 的抽象实现
BaseLoadBalancer
AbstractLoadBalancer 的实现类,它维护了 服务列表、服务状态 等属性
// 所有服务实例列表
protected volatile List<Server> allServerList = Collections
.synchronizedList(new ArrayList<Server>());
// 所有有效服务实例列表
protected volatile List<Server> upServerList = Collections
.synchronizedList(new ArrayList<Server>());
------------------------------------------------------
// 服务实例状态统计
protected LoadBalancerStats lbStats;
------------------------------------------------------
// 负载均衡策略
protected IRule rule = DEFAULT_RULE;
继续解读核心方法的实现
addServers(List newServers)
// 把所有服务实例放到一个新的集合里再 set
public void addServers(List<Server> newServers) {
if (newServers != null && newServers.size() > 0) {
try {
ArrayList<Server> newList = new ArrayList<Server>();
newList.addAll(allServerList);
newList.addAll(newServers);
setServersList(newList);
} catch (Exception e) {
// ...
}
}
}
服务实例的添加
chooseServer(Object key)
public Server chooseServer(Object key) {
// 计数
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
// IRule#choose
return rule.choose(key);
} catch (Exception e) {
// ...
}
}
}
服务实例的选取最终由 负载均衡 策略实例 IRule 实现
markServerDown(Server server)
public void markServerDown(Server server) {
if (server == null || !server.isAlive()) {
return;
}
// 下线
server.setAlive(false);
// 事件发布
notifyServerStatusChangeListener(singleton(server));
}
服务实例标记下线
getReachableServers() & getAllServers()
@Override
public List<Server> getReachableServers() {
return Collections.unmodifiableList(upServerList);
}
@Override
public List<Server> getAllServers() {
return Collections.unmodifiableList(allServerList);
}
返回维护的对应属性即可
getServerList(ServerGroup serverGroup)
public List<Server> getServerList(ServerGroup serverGroup) {
switch (serverGroup) {
case ALL:
return allServerList;
case STATUS_UP:
return upServerList;
// STATUS_NOT_UP = ALL - STATUS_UP
case STATUS_NOT_UP:
ArrayList<Server> notAvailableServers = new ArrayList<Server>(
allServerList);
ArrayList<Server> upServers = new ArrayList<Server>(upServerList);
notAvailableServers.removeAll(upServers);
return notAvailableServers;
}
return new ArrayList<Server>();
}
根据状态筛选 服务实例 列表
DynamicServerListLoadBalancer
拓展了 BaseLoadBalancer,提供了 动态更新 服务列表的能力
ZoneAwareLoadBalancer
ZoneAwareLoadBalancer 继承了 DynamicServerListLoadBalancer,重点是拓展了 chooseServer
方法,提供了 区域亲和 的实现
public Server chooseServer(Object key) {
if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
// 区域亲和关闭,或可用服务实例 <= 1
return super.chooseServer(key);
}
Server server = null;
try {
LoadBalancerStats lbStats = getLoadBalancerStats();
// 获取区域快照
Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
// 从动态配置获取 平均负载 属性
if (triggeringLoad == null) {
triggeringLoad = DynamicPropertyFactory.getInstance().getDoubleProperty(
"ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2d);
}
// 从动态配置获取 实例故障率 属性
if (triggeringBlackoutPercentage == null) {
triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance().getDoubleProperty(
"ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999d);
}
// 根据对应属性获取可用区域集合
Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
// ZoneAvoidanceRule.randomChooseZone 从可用区域集合随机选择一个 zone
if (availableZones != null && availableZones.size() < zoneSnapshot.keySet().size()) {
String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
if (zone != null) {
// 根据 zone 获取对应的 BaseLoadBalancer
BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);
// BaseLoadBalancer#chooseServer 获取服务实例
server = zoneLoadBalancer.chooseServer(key);
}
}
} catch (Exception e) {
// ...
}
if (server != null) {
return server;
} else {
logger.debug("Zone avoidance logic is not invoked.");
return super.chooseServer(key);
}
}
------------------ getLoadBalancer ------------------
BaseLoadBalancer getLoadBalancer(String zone) {
zone = zone.toLowerCase();
BaseLoadBalancer loadBalancer = balancers.get(zone);
// 每个区域对应的 BaseLoadBalancer 缓存在 balancers
if (loadBalancer == null) {
// IRule 默认与外部实例相同,即默认 ZoneAvoidanceRule
IRule rule = cloneRule(this.getRule());
loadBalancer = new BaseLoadBalancer(this.getName() + "_" + zone, rule, this.getLoadBalancerStats());
BaseLoadBalancer prev = balancers.putIfAbsent(zone, loadBalancer);
if (prev != null) {
loadBalancer = prev;
}
}
return loadBalancer;
}
- 从实例状态属性
LoadBalancerStats lbStats
中获取 区域快照 - 从 动态配置 获取两个属性:平均负载、实例故障率
- 根据上述属性获取 可用区域集合
- 由 ZoneAvoidanceRule 随机选择一个区域
zone
- 获取该
zone
对应的 BaseLoadBalancer - 最终 服务实例 的获取由
BaseLoadBalancer#chooseServer
实现,上文已解读,该行为将委托给负载均衡策略实例 IRule 实现
同时,ZoneAwareLoadBalancer 是 Spring Cloud 默认提供的 负载均衡 组件实例
// RibbonClientConfiguration
@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);
}
总结
ILoadBalancer 封装了 Ribbon 对 负载均衡 的实现,提供了诸如 服务实例获取、服务列表的维护 等功能,其中 服务实例 的获取最终由 负载均衡 策略实例 IRule 来实现,下章节结合源码解读 IRule 相关接口和实现类
上一篇:【源码】Spring Cloud —— Ribbon 1 RibbonClientConfigurationRegistrar LoadBalancerClient 相关
下一篇:【源码】Spring Cloud —— Ribbon 3 IRule
参考
《Spring Cloud 微服务架构进阶》 —— 朱荣鑫 张天 黄迪璇