RoundRibbon轮询算法-原理与源码
一、原理
默认情况下,Ribbon的负载均衡算法是RoundRibbon算法,该算法原理为:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标
注:每次服务重启动后rest接口计数从1开始。
假设我们的服务有2个实例,如下
List<Servicelnstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
如:
List [0] instances = 127.0.0.1:8002
List [1] instances = 127.0.0.1:8001
8001+ 8002组合成为集群,它们共计2台机器,集群总数为2,按照轮询算法原理:
- 当总请求数为1时: 1%2=1对应下标位置为1,则获得服务地址为127.0.0.1:8001
- 当总请求数位2时: 2%2=О对应下标位置为0,则获得服务地址为127.0.0.1:8002
- 当总请求数位3时: 3%2=1对应下标位置为1,则获得服务地址为127.0.0.1:8001
- 当总请求数位4时: 4%2=О对应下标位置为0,则获得服务地址为127.0.0.1:8002
- 如此类推…
二、源码
RoundRibbon算法在类继承关系中如下图所示:
负载均衡器Ribbon中的IRule负责选择什么样的负载均衡算法
源码中IRule的接口
package com.netflix.loadbalancer; /** - Interface that defines a "Rule" for a LoadBalancer. A Rule can be thought of - as a Strategy for loadbalacing. Well known loadbalancing strategies include - Round Robin, Response Time based etc. - - @author stonse - */ 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(); }
RoundRibbon关键源码即choose方法的源码如下:
public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { log.warn("no load balancer"); return null; } Server server = null; int count = 0; while (server == null && count++ < 10) { List<Server> reachableServers = lb.getReachableServers(); //获取所有【可达即状态为UP在线的服务】 List<Server> allServers = lb.getAllServers(); //获取所有的服务 int upCount = reachableServers.size(); int serverCount = allServers.size(); if ((upCount == 0) || (serverCount == 0)) { //若在线服务为0,则返回null log.warn("No up servers available from load balancer: " + lb); return null; } int nextServerIndex = incrementAndGetModulo(serverCount); //获取应该调用的服务所在reachableServerList中的index位置,由下面的incrementAndGetModulo方法的具体实现可以看到,就是取模得到的 server = allServers.get(nextServerIndex); if (server == null) { /* Transient. */ Thread.yield(); continue; } if (server.isAlive() && (server.isReadyToServe())) { //若获取到的server是在线的且可达的,则直接返回,否则继续while循环对下一个服务进行判断 return (server); } // Next. 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 The modulo to bound the value of the counter. * @return The next value. */ private int incrementAndGetModulo(int modulo) { / for (;;) { int current = nextServerCyclicCounter.get(); //当前的调用次数 int next = (current + 1) % modulo; if (nextServerCyclicCounter.compareAndSet(current, next)) return next; } }