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解决,效率会高一些。也可以使用锁。

  • 相关阅读:
    1.4.2.3. SETUP(Core Data 应用程序实践指南)
    1.4.2.2. PATHS(Core Data 应用程序实践指南)
    1.4.2.1. FILES(Core Data 应用程序实践指南)
    1.4.2. 实现 Core Data Helper 类(Core Data 应用程序实践指南)
    1.4.1. Core Data Helper 简介(Core Data 应用程序实践指南)
    1.4. 为现有的应用程序添加 Core Data 支持(Core Data 应用程序实践指南)
    1.3.2. App Icon 和 Launch Image(Core Data 应用程序实践指南)
    1.3.1. 新建Xcode项目并设置故事板(Core Data 应用程序实践指南)
    php验证邮箱是否合法
    如何使js函数异步执行
  • 原文地址:https://www.cnblogs.com/panzi/p/10651287.html
Copyright © 2011-2022 走看看