8.负载均衡器

一、引子

负载均衡策略可以了解到ribbon实现的各种负载均衡策略,当然也可以自己实现相应的算法。其中主要的接口IRule中有个定义如下:

public ILoadBalancer getLoadBalancer();

算法使用的server列表以及状态信息都从它获取,这里,就从它开始。

二、接口

ILoadBalancer,从源码的注释中很容易看出,它定义负载均衡的操作,并对server进行存储。接口如下:


public interface ILoadBalancer {
    public void addServers(List<Server> newServers);
    public Server chooseServer(Object key);
    public void markServerDown(Server server);
    public List<Server> getReachableServers();
    public List<Server> getAllServers();
}

那么ILoadBalancer的实现有哪些,参考下图:
在这里插入图片描述

三、实现

  1. 首先看一下addServer如何实现
    addServers(List newServers)的默认实现为BaseLoadBalancer,其内部持有两个list,如下:

    protected volatile List<Server> allServerList;
    protected volatile List<Server> upServerList;
    

    allServerList代表所有的server,
    upServerList代表已经起来的server。
    addServers实现其实也比较简单,即将server列表付给这两个成员变量。

  2. 那么如和区分server是否起来了呢?
    其实实现是比较简单的,BaseLoadBalancer内部启动定时任务,每30秒执行一次ping任务,将ping通的server赋给upServerList。
    这里涉及到的ping就是我们之前说过的ping

  3. 有了上面的实现,那么剩余的方法也就很容易了:

     public List<Server> getReachableServers() {
         return Collections.unmodifiableList(upServerList);
     }
     public List<Server> getAllServers() {
         return Collections.unmodifiableList(allServerList);
     }
    

    其实现仅仅是返回相应的成员变量。

  4. 可以看到BaseLoadBalancer有一个子类DynamicServerListLoadBalancer
    从它的名字DynamicServerList可以看出它具有动态更新Server类别的功能,其实这个功能实现比较简单,就是依赖ServerListUpdater实现的。
    它获取到server列表后,再委托ServerListFilter进行server过滤,最后设置到BaseLoadBalancer的两个成员变量中:allServerList,upServerList。
    到这里,我们来张图简单总结一下server列表是如何动态更新的:
    在这里插入图片描述

    1. ServerListUpdater通过定时任务发起server列表获取。
    2. ServerList通过EurekaClient获取server列表。
    3. EurekaClient发起http请求到EurekaServer,获取server列表。
    4. ServerListUpdater获取结果回调ILoadBalancer设置结果。
    5. ILoadBalancer通过ServerListFilter进行过滤。
    6. IPing定时ping,检测server的活性。
      这里需要提一点,在状态统计中LoadBalancerStats持有一个map,对应着zone和server列表,它的更新就来自于上面的流程,即DynamicServerListLoadBalancer最后获取到server列表后,会对LoadBalancerStats的map进行更新。
  5. ZoneAwareLoadBalancer
    此类继承自DynamicServerListLoadBalancer,是负载均衡器的最终实现,也是ribbon默认使用的类。它有如下功能:(翻译自该类的注释):

    1. 一般来说,当选择server时能够避免某个不健康的zone。
    2. 衡量zone健康状况的关键指标是平均活跃请求,即某个zone的平均活跃请求=这个zone中,还未完成的请求/存活的server
      当某个状况不好的zone慢慢的发生超时的时候(即大量的请求被卡住),这个指标是非常有效的。
    3. 此均衡器将会计算所有的存活的zone的状况:
      当任何某个zone平均活跃请求达到配置的阈值时,这个zone将会从被从存活列表中移除;
      如果多个zone达到阈值,那么具有平均server请求量最大的zone将会被移除;
    4. 一旦状况最坏的zone被移除,那么将会按照zone具有的实例数量作为概率来选择某个zone。
    5. 选择完zone,将会使用IRule来选择一个server,默认的实现为ZoneAvoidanceRule(由于此时只有一个zone,故ZoneAvoidanceRule退化为AvailabilityFilteringRule)。

    注:ZoneAwareLoadBalancer使用了ZoneAvoidanceRule来实现,对应如下三个方法:

    1. ZoneAvoidanceRule.createSnapshot
    2. ZoneAvoidanceRule.getAvailableZones
    3. ZoneAvoidanceRule.randomChooseZone
    4. 而这三个方法都是静态方法,ZoneAvoidanceRule也使用了其中的方法来实现zone的排除和筛选,也就是说ZoneAwareLoadBalancer的zone过滤选择和ZoneAvoidanceRule是一样的但是ZoneAwareLoadBalancer采用了ZoneAvoidanceRule的静态方法的方式实现,感觉有些ugly。

    另外,ZoneAwareLoadBalancer持有一个map,为每个zone都单独创建了一个BaseLoadBalancer来进行过滤选定一个zone之后的server选择。

  6. 最后,来看一下核心方法chooseServer是如何实现的,我们已经知道了最终负载均衡的实现是ZoneAwareLoadBalancer,而它也重写了chooseServer,它的choose过程如下:
    在这里插入图片描述
    单个zone的choose过程说明:

    1. 从LoadBalancerStats查询存活的zone数量。
    2. 发现为1,调用BaseLoadBalancer的chooseServer
    3. BaseLoadBalancer的实现很简单,直接委托给具体的Rule来选择
    4. 最终会使用ZoneAvoidanceRule,而此时zone的数量为1,ZoneAvoidanceRule的zone过滤选择功能不起作用,退化为AvailabilityFilteringRule,即按照server断路器打开或者并发量过大过滤掉一些server,再轮询选择一个。

    多个zone的choose过程说明:

    1. 从LoadBalancerStats查询存活的zone数量。
    2. 发现>1,则调用ZoneAvoidanceRule进行zone的过滤和挑选。
    3. 挑选好zone之后,跟 单个zone的choose过程一样了,委托给BaseLoadBalancer来进行具体的server挑选。
发布了62 篇原创文章 · 获赞 23 · 访问量 15万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章