springCloud(九)

上一篇学习到了LoadBalance的其中一个关键组成部分是负载均衡策略,其最基础的接口是IRule。

public interface IRule{
    /*
     * choose one alive server from lb.allServers or
     * lb.upServers according to key
     * 
     * @return choosen Server object. NULL is returned if none
     *  server is available 
     */

    public Server choose(Object key);
    
    public void setLoadBalancer(ILoadBalancer lb);
    
    public ILoadBalancer getLoadBalancer();    
}

我们可以看到Ribbon已经实现接口的:



我们挨个看一遍,

首先是AvailabilityFilteringRule,他会根据把特殊情况的server排除,

特殊情况包括  1:in circuit breaker tripped state due to consecutive connection or read failures

2: have active connections that exceeds a configurable limit 

        一个是处于短路状态,一个是超过了最大连接数。

     过滤逻辑在AvailabilityPredicate中,

 @Override
    public boolean apply(@Nullable PredicateKey input) {
        LoadBalancerStats stats = getLBStats();
        if (stats == null) {
            return true;
        }
        return !shouldSkipServer(stats.getSingleServerStat(input.getServer()));
    }
    
    
    private boolean shouldSkipServer(ServerStats stats) {        
        if ((CIRCUIT_BREAKER_FILTERING.get() && stats.isCircuitBreakerTripped()) 
                || stats.getActiveRequestsCount() >= activeConnectionsLimit.get()) {
            return true;
        }
        return false;
    }



接下来是BestAvailableRule,首先是过滤掉短路状态的服务,在可用服务中选择并发数最小的。

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

我们可以看到,比较简单,遍历一遍所有的server,去除掉短路状态的服务后,选择出并发量最小的。


接下来是RandomRule,随机选择一个服务。

接下来是RetryRule,在已经有的规则上增加重试机制,默认情况下重试机制的规则是RoundRobinRule。

接下来是RoundRobinRule,轮训的方式选择server,其主要是保存了一个 AtomicInteger nextServerCyclicCounter;利用CAS保证线程安全。

其计算index的算法如下:

private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextServerCyclicCounter.get();
            int next = (current + 1) % modulo;
            if (nextServerCyclicCounter.compareAndSet(current, next))
                return next;
        }
    }
其中modulo就是服务的总数量。

最后一个是WeightedResponseTimeRule,动态的利用response时间计算全职。

doc中的例子非常好:

* The basic idea for weighted round robin has been obtained from JCS
 * The implementation for choosing the endpoint from the list of endpoints
 * is as follows:Let's assume 4 endpoints:A(wt=10), B(wt=30), C(wt=40), 
 * D(wt=20). 
 * <p>
 * Using the Random API, generate a random number between 1 and10+30+40+20.
 * Let's assume that the above list is randomized. Based on the weights, we
 * have intervals as follows:
 * <p>
 * 1-----10 (A's weight)
 * <br>
 * 11----40 (A's weight + B's weight)
 * <br>
 * 41----80 (A's weight + B's weight + C's weight)
 * <br>
 * 81----100(A's weight + B's weight + C's weight + C's weight)
 * <p>
 * Here's the psuedo code for deciding where to send the request:
 * <p>
 * if (random_number between 1 & 10) {send request to A;}
 * <br>
 * else if (random_number between 11 & 40) {send request to B;}
 * <br>
 * else if (random_number between 41 & 80) {send request to C;}
 * <br>
 * else if (random_number between 81 & 100) {send request to D;}
 * <p>
 * When there is not enough statistics gathered for the servers, this rule
 * will fall back to use {@link RoundRobinRule}.

其实就是把总体看做一个圆盘,权重越大所占的面积越大,随机数落在其区域的概率越大。当统计稿率不足时,使用RoundRobinRule。

 // holds the accumulated weight from index 0 to current index
    // for example, element at index 2 holds the sum of weight of servers from 0 to 2
    private volatile List<Double> accumulatedWeights = new ArrayList<Double>();

其中把累加概率保存到了一个列表里,每次计算一个随机数,第一个大于随机数的位置,就是待选泽的server位置。


今天先到这里,接下来继续学习





发布了45 篇原创文章 · 获赞 21 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/ly262173911/article/details/78106352