• 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;
        }
    }
  • 相关阅读:
    xpath语法速查
    负载均衡设计
    Nginx负载均衡配置实例详解
    实现基于DNS的负载均衡
    建立双线服务器(双线游戏服务器)
    python学习
    python多线程概念
    python 多线程就这么简单(续)
    打包一沓开源的 C/C++ 包管理工具送给你!
    讲解开源项目:功能强大的 JS 文件上传库
  • 原文地址:https://www.cnblogs.com/suhaha/p/14641386.html
Copyright © 2020-2023  润新知