专栏首页码匠的流水账聊聊DependenciesBasedLoadBalancer
原创

聊聊DependenciesBasedLoadBalancer

本文主要研究一下DependenciesBasedLoadBalancer

DependenciesBasedLoadBalancer

spring-cloud-zookeeper-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/zookeeper/discovery/dependency/DependenciesBasedLoadBalancer.java

public class DependenciesBasedLoadBalancer extends DynamicServerListLoadBalancer {
​
    private static final Log log = LogFactory.getLog(DependenciesBasedLoadBalancer.class);
​
    private final Map<String, IRule> ruleCache = new ConcurrentHashMap<>();
​
    private final ZookeeperDependencies zookeeperDependencies;
​
    public DependenciesBasedLoadBalancer(ZookeeperDependencies zookeeperDependencies,
            ServerList<?> serverList, IClientConfig config, IPing iPing) {
        super(config);
        this.zookeeperDependencies = zookeeperDependencies;
        setServersList(serverList.getInitialListOfServers());
        setPing(iPing);
        setServerListImpl(serverList);
    }
​
    @Override
    public Server chooseServer(Object key) {
        String keyAsString;
        if ("default".equals(key)) { // this is the default hint, use name instead
            keyAsString = getName();
        }
        else {
            keyAsString = (String) key;
        }
        ZookeeperDependency dependency = this.zookeeperDependencies
                .getDependencyForAlias(keyAsString);
        log.debug(String.format("Current dependencies are [%s]",
                this.zookeeperDependencies));
        if (dependency == null) {
            log.debug(String.format(
                    "No dependency found for alias [%s] - will use the default rule which is [%s]",
                    keyAsString, this.rule));
            return this.rule.choose(key);
        }
        cacheEntryIfMissing(keyAsString, dependency);
        log.debug(String.format(
                "Will try to retrieve dependency for key [%s]. Current cache contents [%s]",
                keyAsString, this.ruleCache));
        updateListOfServers();
        return this.ruleCache.get(keyAsString).choose(key);
    }
​
    private void cacheEntryIfMissing(String keyAsString, ZookeeperDependency dependency) {
        if (!this.ruleCache.containsKey(keyAsString)) {
            log.debug(String.format("Cache doesn't contain entry for [%s]", keyAsString));
            this.ruleCache.put(keyAsString,
                    chooseRuleForLoadBalancerType(dependency.getLoadBalancerType()));
        }
    }
​
    private IRule chooseRuleForLoadBalancerType(LoadBalancerType type) {
        switch (type) {
        case ROUND_ROBIN:
            return getRoundRobinRule();
        case RANDOM:
            return getRandomRule();
        case STICKY:
            return getStickyRule();
        default:
            throw new IllegalArgumentException("Unknown load balancer type " + type);
        }
    }
​
    private RoundRobinRule getRoundRobinRule() {
        return new RoundRobinRule(this);
    }
​
    private IRule getRandomRule() {
        RandomRule randomRule = new RandomRule();
        randomRule.setLoadBalancer(this);
        return randomRule;
    }
​
    private IRule getStickyRule() {
        StickyRule stickyRule = new StickyRule(getRoundRobinRule());
        stickyRule.setLoadBalancer(this);
        return stickyRule;
    }
​
}
  • DependenciesBasedLoadBalancer继承了com.netflix.loadbalancer.DynamicServerListLoadBalancer
  • 其chooseServer方法会使用zookeeperDependencies.getDependencyForAlias来跟进key获取ZookeeperDependency,如果dependency为null则直接使用rule.choose(key),不为null则进行chahe,然后更新server列表,最后通过ruleCache.get(keyAsString).choose(key)返回
  • cacheEntryIfMissing方法会根据ZookeeperDependency.getLoadBalancerType()进行chooseRuleForLoadBalancerType,这里分为了ROUND_ROBIN、RANDOM、STICKY三种

StickyRule

spring-cloud-zookeeper-discovery-2.1.2.RELEASE-sources.jar!/org/springframework/cloud/zookeeper/discovery/dependency/StickyRule.java

public class StickyRule extends AbstractLoadBalancerRule {
​
    private static final Log log = LogFactory.getLog(StickyRule.class);
​
    private final IRule masterStrategy;
​
    private final AtomicReference<Server> ourInstance = new AtomicReference<>(null);
​
    private final AtomicInteger instanceNumber = new AtomicInteger(-1);
​
    public StickyRule(IRule masterStrategy) {
        this.masterStrategy = masterStrategy;
    }
​
    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
​
    }
​
    @Override
    public Server choose(Object key) {
        final List<Server> instances = getLoadBalancer().getServerList(true);
        log.debug(String.format("Instances taken from load balancer [%s]", instances));
        Server localOurInstance = this.ourInstance.get();
        log.debug(String.format("Current saved instance [%s]", localOurInstance));
        if (!instances.contains(localOurInstance)) {
            this.ourInstance.compareAndSet(localOurInstance, null);
        }
        if (this.ourInstance.get() == null) {
            Server instance = this.masterStrategy.choose(key);
            if (this.ourInstance.compareAndSet(null, instance)) {
                this.instanceNumber.incrementAndGet();
            }
        }
        return this.ourInstance.get();
    }
​
    /**
     * Each time a new instance is picked, an internal counter is incremented. This way
     * you can track when/if the instance changes. The instance can change when the
     * selected instance is not in the current list of instances returned by the instance
     * provider
     * @return instance number
     */
    public int getInstanceNumber() {
        return this.instanceNumber.get();
    }
​
}
  • StickyRule继承了com.netflix.loadbalancer.AbstractLoadBalancerRule;其choose方法首先通过getLoadBalancer().getServerList(true)获取server列表,对于该列表没有localOurInstance的,则更新本地引用为null;然后判断localOurInstance是否为null,为null的话则使用masterStrategy.choose(key)进行选择然后更新;最后返回ourInstance.get()

小结

  • DependenciesBasedLoadBalancer继承了com.netflix.loadbalancer.DynamicServerListLoadBalancer
  • 其chooseServer方法会使用zookeeperDependencies.getDependencyForAlias来跟进key获取ZookeeperDependency,如果dependency为null则直接使用rule.choose(key),不为null则进行chahe,然后更新server列表,最后通过ruleCache.get(keyAsString).choose(key)返回
  • cacheEntryIfMissing方法会根据ZookeeperDependency.getLoadBalancerType()进行chooseRuleForLoadBalancerType,这里分为了ROUND_ROBIN、RANDOM、STICKY三种

doc

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 浅析spring声明式事务使用

    springboot中和注解形式的是在@Transactional注解中配置的(添加注解时添加这些):

    开发架构二三事
  • spring boot入门,看这篇文章就够了

    给maven 的settings.xml配置文件的profiles标签添加下面的代码:

    李红
  • Java描述设计模式(04):抽象工厂模式

    汽车生产根据用户选择的汽车类型,指定不同的工厂进行生产,选择红旗轿车,就要使用中国工厂,选择奥迪轿车,就要使用德国工厂。

    知了一笑
  • 聊聊feign的Contract

    feign-core-10.2.3-sources.jar!/feign/Contract.java

    codecraft
  • 基于Spring Cloud Netflix的TCC柔性事务和EDA事件驱动示例

    Spring Cloud为开发者提供了快速构建分布式系统中的一些常见工具,如分布式配置中心,服务发现与注册中心,智能路由,服务熔断及降级,消息总线,分布式追踪的...

    李红
  • Spring Boot 邮件发送的 5 种姿势!

    邮件发送其实是一个非常常见的需求,用户注册,找回密码等地方,都会用到,使用 JavaSE 代码发送邮件,步骤还是挺繁琐的,Spring Boot 中对于邮件发送...

    江南一点雨
  • Java描述设计模式(03):工厂方法模式

    类的创建模式,又叫做虚拟构造子(Virtual Constructor)模式或者多态性工厂(Polymorphic Factory)模式。工厂方法模式的用意是定...

    知了一笑
  • Spring Boot 使用 SLF4J 进行日志记录

    大家好,我是你们的导师,我每天都会在这里给大家分享一些干货内容(当然了,周末也要允许老师休息一下哈)。昨天老师跟大家分享了Spring Boot 返回 JSON...

    挨踢小子部落阁
  • 分布式 Session 解决方案

    来源:https://www.cnblogs.com/SimpleWu/p/10118674.html

    java思维导图
  • SpringMVC-易于同其它View框架无缝集成

    Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 ...

    一点博客

扫码关注云+社区

领取腾讯云代金券