[源码分析]-Ribbon(1): 7种负载均衡算法

Ribbon是客户端负载均衡算法。

1. 顶层接口

IRule是负载均衡算法的顶层接口,定义了三个方法。

public interface IRule{
    /*
     * 根据key选择一个存活的服务器
     */

    Server choose(Object key);

    /**
     * 设置lb
     */
    void setLoadBalancer(ILoadBalancer lb);

    /**
     * 获取lb
     */
    ILoadBalancer getLoadBalancer();
}

其所有的实现类都是抽象类AbstractLoadBalancerRule的子类。AbstractLoadBalancerRule定义了lb字段。

public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {

    /**
     * 核心属性
     */
    private ILoadBalancer lb;
        
    @Override
    public void setLoadBalancer(ILoadBalancer lb){
        this.lb = lb;
    }
    
    @Override
    public ILoadBalancer getLoadBalancer(){
        return lb;
    }      
}

2. 轮询策略

策略实现类RoundRobinRule。

就是用个自增计数器,然后对所有server进行取模。但是这里对计数器有个较好的处理,可以防止计数器的溢出。

    private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextServerCyclicCounter.get();
            //下一次要访问的服务index
            int next = (current + 1) % modulo;
            //***可这操作既可以让计数器自增,还可防止溢出***
            if (nextServerCyclicCounter.compareAndSet(current, next)){
                return next;
            }
        }
    }

3. 重试策略

策略实现类RetryRule。

规定了重试时间为500ms,子策略使用轮询策略。

    public Server choose(ILoadBalancer lb, Object key) {
        //默认只能重试500ms,因此计算出截至时间戳
        long requestTime = System.currentTimeMillis();
        long deadline = requestTime + maxRetryMillis;

        Server answer = null;

        answer = subRule.choose(key);

        //如果从subRule中没有选择到server,或者server不是aclive,但还未到达截至时间,则进行重试
        if (((answer == null) || (!answer.isAlive())) && (System.currentTimeMillis() < deadline)) {

            //到达超时时间后,对发送中断信号,结束下面的while循环
            InterruptTask task = new InterruptTask(deadline - System.currentTimeMillis());

            while (!Thread.interrupted()) {
                answer = subRule.choose(key);

                //如果从subRule中没有选择到server,或者server不是aclive,但还未到达截至时间,则进行重试
                if (((answer == null) || (!answer.isAlive())) && (System.currentTimeMillis() < deadline)) {
                    /* pause and retry hoping it's transient */
                    //放弃一次cpu机会
                    Thread.yield();
                } else {
                    //选择到了server,或者超时了,则退出循环
                    break;
                }
            }
            //如果逻辑到达这里的时候,还没有超时,则取消task
            task.cancel();
        }

        if ((answer == null) || (!answer.isAlive())) {
            return null;
        } else {
            return answer;
        }
    }

4. 随机策略

策略实现类RandomRule。

获取随机值,然后用该随机值返回服务。

ThreadLocalRandom.current().nextInt(serverCount)

5. 响应时间权重策略

策略实现类WeightedResponseTimeRule。

假设有3个server,分别为A, B, C,平均响应时间是5,20,50.

那么算法如下:

(1)计算所有server的平均响应时间之和:sum = 5+20+50 = 75;

(2)计算每个server的累计权重:

    1)A:sum - 5 = 70

    2)B:70 + sum - 20 = 125

    3)C:125 + sum - 50 = 150

(3)取一个随机值[0 - 150),根据这个随机值,查看哪个server的累计权重大于该值,且最接近该值,则这个server被选中。

这里面蕴含的逻辑是,谁的响应时间最小,则它的跨度越大,就越容易被随机值选中。

6. 客户端可配置策略

策略实现类ClientConfigEnabledRoundRobinRule。

内部就是RoundRobinRule。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值