AbstractLoadBalancerRule:负载均衡策略的抽象类,在该抽象类中定义了负载均衡器ILoadBalancer对象,改对象能够在具体实现选择服务器策略时,获取到一些负载均衡器中维护的信息来作为分配依据,并以此设计一些算法来实现针对特定场景的高效策略。
源码:
package com.netflix.loadbalancer;
import com.netflix.client.IClientConfigAware;
public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
private ILoadBalancer lb;
public AbstractLoadBalancerRule() {
}
public void setLoadBalancer(ILoadBalancer lb) {
this.lb = lb;
}
public ILoadBalancer getLoadBalancer() {
return this.lb;
}
}
RandomRule:该策略实现了从服务实例清单中随机选择一个服务实例的功能。
package com.netflix.loadbalancer;
import com.netflix.client.config.IClientConfig;
import edu.umd.cs.findbugs.annotations.SuppressWarnings;
import java.util.List;
import java.util.Random;
public class RandomRule extends AbstractLoadBalancerRule {
Random rand = new Random();
public RandomRule() {
}
//增加了一个负载均衡器对象参数
@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
//根据选择逻辑的实现,正常情况下每次选择都应该选出一个服务实例,如果出现死循环获取不到服务实例时,则很可能存在并发的Bug。
while(server == null) {
if (Thread.interrupted()) {
return null;
}
//通过传入的负载均衡器来获得可以用实例列表
List<Server> upList = lb.getReachableServers();
//获取所有实例列表
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
//以所有实例列表下标为基础生成一个随机数
int index = this.rand.nextInt(serverCount);
//将上面的随机数作为可以用实例列表的索引值来返回具体实例
server = (Server)upList.get(index);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
//将IRule接口的choose(Object key)函数实现委托给了该类中的 choose(ILoadBalancer lb, Object key)
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
RoundRobinRule:按照线性轮询的方式一次选择每个服务实例的功能。详细结构与RandomRule非常相似。除了循环条件不同外,就是从可用列表中获取服务实例的逻辑不通。
package com.netflix.loadbalancer;
import com.netflix.client.config.IClientConfig;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RoundRobinRule extends AbstractLoadBalancerRule {
private AtomicInteger nextServerCyclicCounter;
private static final boolean AVAILABLE_ONLY_SERVERS = true;
private static final boolean ALL_SERVERS = false;
private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);
public RoundRobinRule() {
this.nextServerCyclicCounter = new AtomicInteger(0);
}
public RoundRobinRule(ILoadBalancer lb) {
this();
this.setLoadBalancer(lb);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
} else {
Server server = null;
//记录循环次数
int count = 0;
while(true) {
//选择不同server超过10此,那么就会结束尝试
if (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if (upCount != 0 && serverCount != 0) {
int nextServerIndex = this.incrementAndGetModulo(serverCount);
server = (Server)allServers.get(nextServerIndex);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive() && server.isReadyToServe()) {
return server;
}
server = null;
}
continue;
}
log.warn("No up servers available from load balancer: " + lb);
return null;
}
//超过10次打印警告信息
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
}
}
//通过此方法叨叨线性循环,每次进行实例选择时通过此方法实现递增
private int incrementAndGetModulo(int modulo) {
int current;
int next;
do {
current = this.nextServerCyclicCounter.get();
next = (current + 1) % modulo;
} while(!this.nextServerCyclicCounter.compareAndSet(current, next));
return next;
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
RetryRule:该策略实现了一个具备重试机制的实例选择功能。
package com.netflix.loadbalancer;
import com.netflix.client.config.IClientConfig;
public class RetryRule extends AbstractLoadBalancerRule {
//定义IRule对象,默认使用了RoundRobinRule策略实例
IRule subRule = new RoundRobinRule();
long maxRetryMillis = 500L;
public RetryRule() {
}
public RetryRule(IRule subRule) {
this.subRule = (IRule)(subRule != null ? subRule : new RoundRobinRule());
}
public RetryRule(IRule subRule, long maxRetryMillis) {
this.subRule = (IRule)(subRule != null ? subRule : new RoundRobinRule());
this.maxRetryMillis = maxRetryMillis > 0L ? maxRetryMillis : 500L;
}
public void setRule(IRule subRule) {
this.subRule = (IRule)(subRule != null ? subRule : new RoundRobinRule());
}
public IRule getRule() {
return this.subRule;
}
public void setMaxRetryMillis(long maxRetryMillis) {
if (maxRetryMillis > 0L) {
this.maxRetryMillis = maxRetryMillis;
} else {
this.maxRetryMillis = 500L;
}
}
public long getMaxRetryMillis() {
return this.maxRetryMillis;
}
public void setLoadBalancer(ILoadBalancer lb) {
super.setLoadBalancer(lb);
this.subRule.setLoadBalancer(lb);
}
public Server choose(ILoadBalancer lb, Object key) {
long requestTime = System.currentTimeMillis();
long deadline = requestTime + this.maxRetryMillis;
Server answer = null;
//通过指定策略获取服务实例
answer = this.subRule.choose(key);
//未获取正确服务实例进
if ((answer == null || !answer.isAlive()) && System.currentTimeMillis() < deadline) {
InterruptTask task = new InterruptTask(deadline - System.currentTimeMillis());
//通过定义的策略反复尝试获取服务实例
while(!Thread.interrupted()) {
answer = this.subRule.choose(key);
//当获取到具体实例或设置的结束时间(maxRetryMillis参数定义的值+此方法开始的时间)则终止循环
if (answer != null && answer.isAlive() || System.currentTimeMillis() >= deadline) {
break;
}
Thread.yield();
}
task.cancel();
}
return answer != null && answer.isAlive() ? answer : null;
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
WeightedResponseTimeRule:此策略是对RoundRobinRule策略的扩展,增加了根据实例的运行情况来技术权重,并根据权重来挑选实例,已达到更优的分配效果。
package com.netflix.loadbalancer;
import com.netflix.client.config.IClientConfig;
import com.netflix.client.config.IClientConfigKey;
import edu.umd.cs.findbugs.annotations.SuppressWarnings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WeightedResponseTimeRule extends RoundRobinRule {
public static final IClientConfigKey<Integer> WEIGHT_TASK_TIMER_INTERVAL_CONFIG_KEY = new IClientConfigKey<Integer>() {
public String key() {
return "ServerWeightTaskTimerInterval";
}
public String toString() {
return this.key();
}
public Class<Integer> type() {
return Integer.class;
}
};
public static final int DEFAULT_TIMER_INTERVAL = 30000;
private int serverWeightTaskTimerInterval = 30000;
private static final Logger logger = LoggerFactory.getLogger(WeightedResponseTimeRule.class);
private volatile List<Double> accumulatedWeights = new ArrayList();
private final Random random = new Random();
protected Timer serverWeightTimer = null;
protected AtomicBoolean serverWeightAssignmentInProgress = new AtomicBoolean(false);
String name = "unknown";
public WeightedResponseTimeRule() {
}
public WeightedResponseTimeRule(ILoadBalancer lb) {
super(lb);
}
public void setLoadBalancer(ILoadBalancer lb) {
super.setLoadBalancer(lb);
if (lb instanceof BaseLoadBalancer) {
this.name = ((BaseLoadBalancer)lb).getName();
}
this.initialize(lb);
}
void initialize(ILoadBalancer lb) {
if (this.serverWeightTimer != null) {
this.serverWeightTimer.cancel();
}
this.serverWeightTimer = new Timer("NFLoadBalancer-serverWeightTimer-" + this.name, true);
//启动一个定时任务,用来为每个服务实例计算权重,改任务默认30秒执行一次
this.serverWeightTimer.schedule(new WeightedResponseTimeRule.DynamicServerWeightTask(), 0L, (long)this.serverWeightTaskTimerInterval);
WeightedResponseTimeRule.ServerWeight sw = new WeightedResponseTimeRule.ServerWeight();
sw.maintainWeights();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
WeightedResponseTimeRule.logger.info("Stopping NFLoadBalancer-serverWeightTimer-" + WeightedResponseTimeRule.this.name);
WeightedResponseTimeRule.this.serverWeightTimer.cancel();
}
}));
}
public void shutdown() {
if (this.serverWeightTimer != null) {
logger.info("Stopping NFLoadBalancer-serverWeightTimer-" + this.name);
this.serverWeightTimer.cancel();
}
}
List<Double> getAccumulatedWeights() {
return Collections.unmodifiableList(this.accumulatedWeights);
}
@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
List<Double> currentWeights = this.accumulatedWeights;
if (Thread.interrupted()) {
return null;
}
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
int serverIndex = 0;
//获取最后一个实例的权重
double maxTotalWeight = currentWeights.size() == 0 ? 0.0D : (Double)currentWeights.get(currentWeights.size() - 1);
//最后一个实例的权重值大于 0.001进
if (maxTotalWeight >= 0.001D && serverCount == currentWeights.size()) {
//产生一个[0,maxTotalWeight]的随机数
double randomWeight = this.random.nextDouble() * maxTotalWeight;
int n = 0;
//遍历维护的权重清单,若权重值大于等于随机得到的数值,就选择这个实例
for(Iterator var13 = currentWeights.iterator(); var13.hasNext(); ++n) {
Double d = (Double)var13.next();
if (d >= randomWeight) {
serverIndex = n;
break;
}
}
server = (Server)allList.get(serverIndex);
} else {//否则调用父类的的线性轮询策略
server = super.choose(this.getLoadBalancer(), key);
if (server == null) {
return server;
}
}
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
}
}
return server;
}
}
void setWeights(List<Double> weights) {
this.accumulatedWeights = weights;
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
super.initWithNiwsConfig(clientConfig);
this.serverWeightTaskTimerInterval = (Integer)clientConfig.get(WEIGHT_TASK_TIMER_INTERVAL_CONFIG_KEY, 30000);
}
class ServerWeight {
ServerWeight() {
}
//维护实例权重的计算函数
public void maintainWeights() {
ILoadBalancer lb = WeightedResponseTimeRule.this.getLoadBalancer();
if (lb != null) {
if (WeightedResponseTimeRule.this.serverWeightAssignmentInProgress.compareAndSet(false, true)) {
try {
WeightedResponseTimeRule.logger.info("Weight adjusting job started");
AbstractLoadBalancer nlb = (AbstractLoadBalancer)lb;
LoadBalancerStats stats = nlb.getLoadBalancerStats();
if (stats != null) {
//计算所有实例的平均响应时间的总和
double totalResponseTime = 0.0D;
ServerStats ss;
//根据LoadBalancerStats中记录的每个实例的统计信息,累加所有实例的平均响应时间,得到总平均响应时间totalResponseTime
for(Iterator var6 = nlb.getAllServers().iterator(); var6.hasNext(); totalResponseTime += ss.getResponseTimeAvg()) {
Server server = (Server)var6.next();
//如果服务实例的状态快照不在缓存中,那么这里会进行自动加载
ss = stats.getSingleServerStat(server);
}
Double weightSoFar = 0.0D;
List<Double> finalWeights = new ArrayList();
Iterator var20 = nlb.getAllServers().iterator();
//逐个计算每个实例的权重:weightSoFar+totalResponseTime-实例的平均响应时间,这里的权重值只是表示个实例权重区间的上限,并非某个实例的优先级,所以不是数值越大被选中的概率就约到。区间是指weights保存的权重值构建:每个实例的区间下限是上个实例的区间上限,第一个实例的下限默认为0。权重区间的宽度越大被选中的概率就越高,权重区间的宽度=总得平均响应时间-实例的平均响应时间,所以实例的平均响应时间越短、权重区间的宽度越大
while(var20.hasNext()) {
Server serverx = (Server)var20.next();
ServerStats ssx = stats.getSingleServerStat(serverx);
double weight = totalResponseTime - ssx.getResponseTimeAvg();
weightSoFar = weightSoFar + weight;
finalWeights.add(weightSoFar);
}
WeightedResponseTimeRule.this.setWeights(finalWeights);
return;
}
} catch (Exception var16) {
WeightedResponseTimeRule.logger.error("Error calculating server weights", var16);
return;
} finally {
WeightedResponseTimeRule.this.serverWeightAssignmentInProgress.set(false);
}
}
}
}
}
class DynamicServerWeightTask extends TimerTask {
DynamicServerWeightTask() {
}
public void run() {
WeightedResponseTimeRule.ServerWeight serverWeight = WeightedResponseTimeRule.this.new ServerWeight();
try {
serverWeight.maintainWeights();
} catch (Exception var3) {
WeightedResponseTimeRule.logger.error("Error running DynamicServerWeightTask for {}", WeightedResponseTimeRule.this.name, var3);
}
}
}
}
ClientConfigEnabledRoundRobinRule:该策略一般不会直接使用,使用的主要场景在于继承此策略来实现一些高级策略,如果遇到无法实施的情况时,可调用父类的实现作为备选。
package com.netflix.loadbalancer;
import com.netflix.client.config.IClientConfig;
public class ClientConfigEnabledRoundRobinRule extends AbstractLoadBalancerRule {
RoundRobinRule roundRobinRule = new RoundRobinRule();
public ClientConfigEnabledRoundRobinRule() {
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
this.roundRobinRule = new RoundRobinRule();
}
public void setLoadBalancer(ILoadBalancer lb) {
super.setLoadBalancer(lb);
this.roundRobinRule.setLoadBalancer(lb);
}
public Server choose(Object key) {
if (this.roundRobinRule != null) {
return this.roundRobinRule.choose(key);
} else {
throw new IllegalArgumentException("This class has not been initialized with the RoundRobinRule class");
}
}
}
BestAvailableRule:该策略通过遍历负载均衡器中维护的所有的服务实例,同时过滤掉故障的实例,以LoadBalancerStats中保存的实例信息来选出并发请求数最小的一个,此策略的特性是可选出最空闲的实例。
package com.netflix.loadbalancer;
import java.util.Iterator;
import java.util.List;
public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule {
private LoadBalancerStats loadBalancerStats;
public BestAvailableRule() {
}
public Server choose(Object key) {
//如果LoadBalancerStats保存的实例信息为空时将调用父类的线性轮询策略
if (this.loadBalancerStats == null) {
return super.choose(key);
} else {
List<Server> serverList = this.getLoadBalancer().getAllServers();
int minimalConcurrentConnections = 2147483647;
long currentTime = System.currentTimeMillis();
Server chosen = null;
Iterator var7 = serverList.iterator();
while(var7.hasNext()) {
Server server = (Server)var7.next();
ServerStats serverStats = this.loadBalancerStats.getSingleServerStat(server);
if (!serverStats.isCircuitBreakerTripped(currentTime)) {
int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);
if (concurrentConnections < minimalConcurrentConnections) {
minimalConcurrentConnections = concurrentConnections;
chosen = server;
}
}
}
if (chosen == null) {
return super.choose(key);
} else {
return chosen;
}
}
}
public void setLoadBalancer(ILoadBalancer lb) {
super.setLoadBalancer(lb);
if (lb instanceof AbstractLoadBalancer) {
this.loadBalancerStats = ((AbstractLoadBalancer)lb).getLoadBalancerStats();
}
}
}
PredicateBasedRule:这是一个抽象策略,通过子类中实现的getPredicate函数来过滤一部分服务实例,然后再以线性轮询的方式从过滤后的实例清单中选出一个。AvailabilityFilteringRule和ZoneAvoidanceRule策略继承此策略。
package com.netflix.loadbalancer;
import com.google.common.base.Optional;
public abstract class PredicateBasedRule extends ClientConfigEnabledRoundRobinRule {
public PredicateBasedRule() {
}
public abstract AbstractServerPredicate getPredicate();
public Server choose(Object key) {
ILoadBalancer lb = this.getLoadBalancer();
Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
return server.isPresent() ? (Server)server.get() : null;
}
}
更多文章:
点击跳转CSDN博客
点击跳转简书博客
公众号:代码小搬运