乐趣区

聊聊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

  • DependenciesBasedLoadBalancer
退出移动版