序
本文主要研究一下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三种