zoukankan      html  css  js  c++  java
  • 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;
        }
    }
  • 相关阅读:
    VIM技巧, .vimrc文件
    vSphere Client克隆虚拟机
    vSphere、 ESXi、Vcenter、vSphere Client关系
    消耗系统内存
    zabbix2.4汉化
    普通用户执行ansible权限被拒绝
    putty秘钥转换成xhell支持的格式
    zbb20170922 mysql 字符集设置 比较 utf8_general_ci、utf8_unicode_ci和utf8_bin的区别
    zbb20170920 页面调用qq
    zbb20170919 tomcat 8 启动异常 Could not publish server configuration for Tomcat v8.0 Server at localhost. Multiple Contexts have a path of "A".
  • 原文地址:https://www.cnblogs.com/suhaha/p/14641386.html
Copyright © 2011-2022 走看看