Ribbon内置负载均衡的接口是IRule,可以看下其中几种的实现:
1:BestAvaliableRule:选择其中并发数最小的一个Server,如果Server被tripped了,就跳过,看下源码实现
@Override
public Server choose(Object key) {
if (loadBalancerStats == null) {
return super.choose(key);
}
//获取所有的实例列表
List<Server> serverList = getLoadBalancer().getAllServers();
//设置一个初始值,用于比较并发数
int minimalConcurrentConnections = Integer.MAX_VALUE;
long currentTime = System.currentTimeMillis();
Server chosen = null;
for (Server server: serverList) {
ServerStats serverStats = 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;
}
}
2:RandomRule:随机选择一个Server
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
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;
}
//serverCount是实例的数量,然后随机选取一个Server返回
int index = chooseRandomInt(serverCount);
server = upList.get(index);
if (server == null) {
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
3:RetryRule:对选定的负载均衡策略上重试机制,在一个配置时间段内当选择的Server不成功,则一直尝试使用subRule方式选择一个可用的Server
public Server choose(ILoadBalancer lb, Object key) {
long requestTime = System.currentTimeMillis();
//maxRetryMillis在源码中设置为 long maxRetryMillis = 500;
long deadline = requestTime + maxRetryMillis;
Server answer = null;
//subRule在源码中:IRule subRule = new RoundRobinRule();默认使用轮询的机制
answer = subRule.choose(key);
//如果选择的Server为空,或者不能正常使用,并且在重试时间段内
if (((answer == null) || (!answer.isAlive()))
&& (System.currentTimeMillis() < deadline)) {
InterruptTask task = new InterruptTask(deadline
- System.currentTimeMillis());
// 判断当前线程是否被中断
while (!Thread.interrupted()) {
//使用已有的策略在次选择一个Server
answer = subRule.choose(key);
// 如果选择出来的Server还是为空或者不可用,那么就再次进入while循环,选择一个Server,直到得到一个可用的Server
if (((answer == null) || (!answer.isAlive()))
&& (System.currentTimeMillis() < deadline)) {
/* pause and retry hoping it's transient */
Thread.yield();
} else {
break;
}
}
task.cancel();
}
if ((answer == null) || (!answer.isAlive())) {
return null;
} else {
return answer;
}
}
4:RoundRobinRule:轮询选择,轮询index,选择index对应的Server
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}
Server server = null;
int count = 0;
//这里的count是记录轮询次数,如果达到10次还没有获取到Server就会抛出异常
while (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)) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}
// incrementAndGetModulo方法就是实现轮询的方法,它使用了CAS机制来选取一个Server,直到得到一个可用的Server
int nextServerIndex = incrementAndGetModulo(serverCount);
server = allServers.get(nextServerIndex);
if (server == null) {
/* Transient. */
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}
// Next.
server = null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "
+ lb);
}
return server;
}
可以看下incrementAndGetModulo方法的实现
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}