Ribbon内置负载均衡规则源码

158 阅读2分钟

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;
    }
}