Ribbon负载均衡算法原理与源码解读

负载均衡算法原理

  • 算法原理为:通过rest接口第几次请求数 % 服务器集群总数量 获取实际调用服务器位置的下标,每次服务重启后,rest接口第几次请求计数从1开始。

  • 可以想象一下,你要对一个服务器进行请求,然后负载均衡的默认算法是轮询算法,即你要保证你的请求对所有服务器集群是一个轮换的机制。
    又因为取余数便总能够得到比集群总数量小的数,联想数组下标,我们这个取的余数即可作为数组下标,当然这边理解为服务器位置的下标也是同种性质的。
    那么通过每次下标自增一,满了之后归0,即可实现轮询所有的服务器。

负载均衡算法源码解读

IRule接口:根据特定算法从服务列表中选取一个要访问的服务
在这里插入图片描述
IRule接口中choose方法的作用是从存活的服务中选择一个服务来使用

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

RoundRobinRule源码解读

默认负载均衡算法:轮询算法
spring容器能够使用这个RoundRobinRule类,所以我们理应查看它的构造方法。构造方法中将原始整形类赋初始值为0

public class RoundRobinRule extends AbstractLoadBalancerRule {
	private AtomicInteger nextServerCyclicCounter;
	
    public RoundRobinRule() {
        nextServerCyclicCounter = new AtomicInteger(0);
    }
}

我们轮询算法的重点肯定是在于如何从存活的服务中选出一个服务,那我们RoundRobinRule重写了IRule的choose方法

@Override
public Server choose(Object key) {
    return choose(getLoadBalancer(), key);
}

内部又调用choose(getLoadBalancer(), key)方法,步骤解析如下代码

public class RoundRobinRule extends AbstractLoadBalancerRule {
	private AtomicInteger nextServerCyclicCounter;
	
	public Server choose(ILoadBalancer lb, Object key) {
		// 1. 如果没有负载均衡,即报错
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }
		// 2. 进行服务器的选择
        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
        	// 2.1 获取所有可达的服务器(即存活的服务器)
            List<Server> reachableServers = lb.getReachableServers();
            // 2.2 获取所有服务器
            List<Server> allServers = lb.getAllServers();
            // 2.3 获取存活服务器的总数量,即上诉中的服务器集群总数量
            int upCount = reachableServers.size();
            // 2.4 获取所有服务器的总数量
            int serverCount = allServers.size();
			// 2.5 如果不存在存活服务器或者不存在服务器则报错
            if ((upCount == 0) || (serverCount == 0)) {
                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

			// 3. 获取下一个指定服务器的下标,即上述:取余后获取服务器下标
			// 这里的下一个,不要理解为第一次进来的下一次第二次
			// 应该理解为,你第一次请求进来的时候,这些代码是在你请求进来后去推算我们的服务器的位置,那这个next对于我们来说,即是第一次请求所对应的服务器
			// 所以我们这里读下标的时候是从1-2-3-...-0-1-2-3-...-0...
            int nextServerIndex = incrementAndGetModulo(serverCount);
            // 4. 根据下标获取对应服务器
            server = allServers.get(nextServerIndex);
			// 5. 判断一下所获取到的服务器是否为空,如果为空则结束本次循环继续开始下次循环
            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

			// 6. 判断该服务器是否存活是否准备好去做负载均衡的服务器,否则将server置null继续后续循环
            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }
            
            server = null;
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: "
                    + lb);
        }
        return server;
    }

	/**
     * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
     *
     * @param modulo 所有服务器的总数量
     * @return The next value.
     */
	private int incrementAndGetModulo(int modulo) {
        for (;;) {
        	// .get()即返回它自身的值,该值在创建对象放入spring容器时,即上面调用的构造方法,值为0
        	// 即当前下标为0 ,下一个下标为 (0+1)%总数
            int current = nextServerCyclicCounter.get();
            int next = (current + 1) % modulo;
            // cas比较,即如果current与nextServerCyclicCounter的值相等,则将nextServerCyclicCounter的值更新为next
            if (nextServerCyclicCounter.compareAndSet(current, next))
            	// 即这里实现了我们上述所说的取余数,那这个余数,就可以作为我们的服务器下标去获取服务器
                return next;
        }
    }
}

负载均衡接口

public interface ILoadBalancer {
	/**
	 * @return Only the servers that are up and reachable.
     */
    public List<Server> getReachableServers();

    /**
     * @return All known servers, both reachable and unreachable.
     */
	public List<Server> getAllServers();
}

这里指:如果expect值与this值相等,那就想this值更新为update,并返回true

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    // valueOffset理解为这个value的内存地址值
    private static final long valueOffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    private volatile int value;

    /**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值