微服务架构之均衡组件 Ribbon解析:ILoadBalancer实现解析

举报
qingting-fly 发表于 2021/08/06 00:09:33 2021/08/06
【摘要】 ILoadBalancerILoadBalancer是RIbbon的关键类之一,它是定义软负载均衡操作过程的接口。在上一小节中,读者应该已经了解到可以通过SpringClientFactory工厂类的getLoadBalancer函数获取ILoadBalancer实例。根据Ribbon的实例化机制,ILoadBalnacer实例是在RibbonAutoConfiguration中被创建生成...

ILoadBalancer

ILoadBalancerRIbbon的关键类之一,它是定义软负载均衡操作过程的接口。

在上一小节中,读者应该已经了解到可以通过SpringClientFactory工厂类的getLoadBalancer函数获取ILoadBalancer实例。根据Ribbon的实例化机制,ILoadBalnacer实例是在RibbonAutoConfiguration中被创建生成的。SpringClientFactory中的实例都是RibbonClientConfiguration或者自己自定义Configuration类配置的Bean实例。

RibbonClientConfiguration中还有IRule,IPingServerList相关的配置。使用者可以通过自定义配置类中来配置上述的几个实例。

ZoneAwareLoadBalancer.png

如图所示,ZoneAwareLoadBalancerILoadBalancer接口的实现类之一,它是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);
}

Ribbon关键类图.png

接下来按照ZoneAwareLoadBalancer构造函数的参数的顺序来依次看一下与ILoadBalancer相关的重要的类。IClientConfig、IRule、IPing、ServerList、ServerListFilter和ILoadBalancer,查看BaseLoadBalancer类,它默认的情况下,实现了以下配置:

  • ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer
  • IClientConfig ribbonClientConfig: DefaultClientConfigImpl配置
  • IRule ribbonRule: RoundRobinRule 路由策略
  • IPing ribbonPing: DummyPing 查看服务器是否可用策略
  • ServerList ribbonServerList: ConfigurationBasedServerList 获取服务器列表策略
  • ServerListFilter ribbonServerListFilter: ZonePreferenceServerListFilter 服务器列表过滤策略

上述的类在接下来的文章中会进行一一介绍,本小节将着重讲解ILoadBalancer的相关原理。

ZoneAwareLoadBalancerchooseServer函数会首先使用DynamicPropertyFactory来获取平均负载和实例故障率两个阈值,然后调用ZoneAvoidanceRulegetAvailableZones函数使用这两个阈值来获取所有可用的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;
            }
        }
}

ZoneAwareLoadBalancerchooseServer函数会首先使用DynamicPropertyFactory来获取平均负载和实例故障率两个阈值,然后调用ZoneAvoidanceRulegetAvailableZones函数使用这两个阈值来获取所有可用的Zone列表。然后在调用ZoneAvoidanceRulerandomChooseZone函数从上述的Zone列表中随机选出一个Zone,最后调用该Zone对应BaseLoadBalancer实例的chooseServer函数获取到最终的服务器。ZoneAwareLoadBalancer会为不同的Zone调用不同的BaseLoadBalancerchooseServer函数,这正体现了它类名的含义。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。