zoukankan      html  css  js  c++  java
  • 几行代码实现负载均衡轮询算法

    前言

      负载均衡在架构设计中是经常提到的一种方案,用以提高系统处理量。今天用几句代码实现Round Robin方式,用白话文说就是有活大家轮着干。在看了Ribbion源码之后,确实是几行代码。

    实现思路

    • 首先,要有一组服务列表
        private List<String> serverList = new LinkedList<>();
    
        public RoundRibbon() {
            serverList.add("http://server.01");
            serverList.add("http://server.02");
            serverList.add("http://server.03");
            serverList.add("http://server.04");
            serverList.add("http://server.05");
        }
    
    • 然后要有一个全局的索引变量,然后通过取余的方式计算下一个服务索引:
        int nextServerIndex = (currentIndex  + 1) % serverList.size();
    
    • 上面的代码在实战中会有线程安全的问题,因此可以采用 AtomicInteger 实现。

    生产实现

      在 Netflix/ribbon 的 RoundRobinRule 中实现代码如下:

     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) {
                 //获取可用的server列表
                List<Server> reachableServers = lb.getReachableServers();
                List<Server> allServers = lb.getAllServers();
                int upCount = reachableServers.size();
                int serverCount = allServers.size();
    
                if ((upCount == 0) || (serverCount == 0)) {
                    log.warn("No up servers available from load balancer: " + lb);
                    return null;
                }
                //核心实现,获取server索引
                int nextServerIndex = incrementAndGetModulo(serverCount);
                server = allServers.get(nextServerIndex);
    
                if (server == null) {
                    /* Transient. */
                    Thread.yield();
                    continue;
                }
                //是这种 
                if (server.isAlive() && (server.isReadyToServe())) {
                    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;
                //通过 CAS 设置下一个搜索引值(解决并发索引值可能重复的问题)
                if (nextServerCyclicCounter.compareAndSet(current, next))
                    return next;
            }
        }
    

    总结

    轮询方式实现很简单,关键难点就是解决线程安全问题。例子中通过使用CAS解决,效率会高一些。也可以使用锁。

  • 相关阅读:
    javascript 获取 sx:datetimepicker 的值
    struts-dojo的使用
    struts-dojo的使用
    HTML 标签的 target 属性
    HTML 标签的 target 属性
    关于用struts2框架中iframe对应的jsp页面的不到action的值的问题
    关于用struts2框架中iframe对应的jsp页面的不到action的值的问题
    浏览器加载、渲染html的顺序和页面优化
    浏览器加载、渲染html的顺序和页面优化
    linux 安装swoole扩展方法
  • 原文地址:https://www.cnblogs.com/panzi/p/10651287.html
Copyright © 2011-2022 走看看