目录
前言
上一篇文章探讨了最基础的负载均衡器BaseLoadBalancer
,该负载均衡器提供了最基础的负载能力拥有IPing
、IRule
两个主要的组件。但是BaseLoadBalancer
有如下的缺点:
- 服务列表无法做到动态化 例如注册了一个实例(新增一个配置) 它是无法感知的
- 无法做到服务过滤,比如某些服务负载已经很高了 或者已经熔断了
- 无法做到zone区域识别
DynamicServerListLoadBalancer介绍
DynamicServerListLoadBalancer
负载均衡器在BaseLoadBalancer
的基础上进一步集成了ServerListFilter
、ServerListUpdater
、ServerList
三大组件到此五大组件已经全部出现。所以DynamicServerListLoadBalancer
具有如下能力:可定制服务列表(例如可指定从注册中心获取,可从配置文件中获取)、可动态获取服务列表(例如配置文件中配置的服务列表变更可自动获取,注册中心中新增一个服务负载均衡可自动获取),服务过滤能力(可对某些条件的服务器过滤)。
DynamicServerListLoadBalancer初始化
构造方法
public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,
ServerList<T> serverList, ServerListFilter<T> filter,
ServerListUpdater serverListUpdater) {
super(clientConfig, rule, ping);
this.serverListImpl = serverList;
this.filter = filter;
this.serverListUpdater = serverListUpdater;
if (filter instanceof AbstractServerListFilter) {
((AbstractServerListFilter) filter).setLoadBalancerStats(getLoadBalancerStats());
}
restOfInit(clientConfig);
}
super(clientConfig, rule, ping)
:调用父构造器对IPing
、IRule
组件初始化以及设计Ping的间隔时间和最大的Ping时间。- 接着就是初始化三大组件(
ServerList
、ServerListUpdater
、ServerListFilter
) restOfInit()
最重要的就是通过ServerList
获取初始化服务列表启动ServerListUpdater
开始动态更新
restOfInit()
void restOfInit(IClientConfig clientConfig) {
boolean primeConnection = this.isEnablePrimingConnections();
this.setEnablePrimingConnections(false);
enableAndInitLearnNewServersFeature();
updateListOfServers();
if (primeConnection && this.getPrimeConnections() != null) {
this.getPrimeConnections()
.primeConnections(getReachableServers());
}
this.setEnablePrimingConnections(primeConnection);
}
这个方法最重要的这两句代码:enableAndInitLearnNewServersFeature(); updateListOfServers();
从名字不难看出他们的功能分别是 启用并且初始化学习新服务的功能和更新服务列表。enableAndInitLearnNewServersFeature
很简单 我们猜都能猜得到 肯定是调用ServerListUpdater
的start
方法开启。看一下下面的实现:
public void enableAndInitLearnNewServersFeature() {
serverListUpdater.start(updateAction);
}
可以把ServerListUpdater
理解成一个定时器 具体要执行的逻辑需要我们通过UpdateAction
指定过去。下面是DynamicServerListLoadBalancer
为ServerListUpdater
指定的执行逻辑。可以看到就是调用当前类的updateListOfServers()
方法。和restOfInit()
里面的部分逻辑是类似的。
protected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {
@Override
public void doUpdate() {
updateListOfServers();
}
};
updateListOfServers() 更新服务列表
上面我们看到ServerListUpdater
也是通过调用updateListOfServers()
来实现动态更新服务器列表的。该方法很简单但是很重要,因为它集成了ServerList
和ServerListFilter
的操作。
public void updateListOfServers() {
List<T> servers = new ArrayList<T>();
if (serverListImpl != null) {
servers = serverListImpl.getUpdatedListOfServers();
if (filter != null) {
servers = filter.getFilteredListOfServers(servers);
}
}
updateAllServerList(servers);
}
先从ServerList
中获取服务列表 然后通过ServerListFilter
来过滤服务列表,最终把过滤之后的服务列表传递给updateAllServerList
方法。
updateAllServerList()
protected void updateAllServerList(List<T> ls) {
if (serverListUpdateInProgress.compareAndSet(false, true)) {
try {
for (T s : ls) {
s.setAlive(true);
}
setServersList(ls);
super.forceQuickPing();
} finally {
serverListUpdateInProgress.set(false);
}
}
}
上述方法初始化Server
的alive
默认为true。然后通过IPing
来改变该值。上一篇文章中我们对Ping的过程做了一个简单的梳理,这里就不作赘述。【你好Ribbon】十二:Ribbon负载均衡器接口ILoadBalancer-最基础的负载均衡器BaseLoadBalancer
setServersList()
@Override
public void setServersList(List lsrv) {
//这个逻辑我们上一篇文章已经分析过
super.setServersList(lsrv);
//除了设置服务列表之外 下面主要是构建区域服务列表 然后设置到负载均衡指标统计中
List<T> serverList = (List<T>) lsrv;
Map<String, List<Server>> serversInZones = new HashMap<String, List<Server>>();
for (Server server : serverList) {
getLoadBalancerStats().getSingleServerStat(server);
String zone = server.getZone();
if (zone != null) {
zone = zone.toLowerCase();
List<Server> servers = serversInZones.get(zone);
if (servers == null) {
servers = new ArrayList<Server>();
serversInZones.put(zone, servers);
}
servers.add(server);
}
}
setServerListForZones(serversInZones);
}
- 设置负载均衡服务列表
super.setServersList(lsrv);
- 构造区域服务列表映射关系
serversInZones
将此对应关系设置进LoadBalancerStats
如何使用DynamicServerListLoadBalancer
配置config.peoperties
如下:
coredy.ribbon.listOfServers=172.10.1.11,172.10.1.12
示例代码:
@Test
public void test1(){
IClientConfig config = DefaultClientConfigImpl.getClientConfigWithDefaultValues("coredy");
IRule rule = new RoundRobinRule();
IPing ping = new DummyPing();
ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
serverList.initWithNiwsConfig(config);
//使用默认值 1秒后开始执行 然后30s重复执行
ServerListUpdater serverListUpdater = new PollingServerListUpdater();
ILoadBalancer loadBalancer
= new DynamicServerListLoadBalancer(config , rule , ping , serverList , null , serverListUpdater);
while (true){
Server server = loadBalancer.chooseServer(null);
System.out.println(server);
sleep(1000);
}
}
在程序运行的过程中向config.properties
文件中增加一个server。
coredy.ribbon.listOfServers=172.10.1.11,172.10.1.12,172.10.1.13
增加完一定要recompile
一次 否则不会加载。如下图右键config.peoperties
:
运行结果如下:
总结
DynamicServerListLoadBalancer
几乎具备了 负载均衡器该具备的所有的功能,它集成了Ribbon的五大负载均衡组件 所有也是一个应用比较多的一个负载均衡器。