• java 平滑加权轮询算法实现与讲解


                          java 平滑加权轮询算法实现与分析

    废话,可直接跳过: 有一个需求,需要在代码层面上 实现 灰度 发布,有一种很简单的办法就是取余,比如  当前时间戳(或者业务ID) % 10 对于10取余, 余1,2,3 的走 逻辑A,其他的走逻辑B,从而达到灰度发布的效果,但是我不甘于此,我想设计的复杂点,就去研究了下nginx相关的轮询算法, 我中意了一个 平滑加权轮询算法(再简单的东西,只要你愿意去思考,总能学到东西,不甘于现状)。

    • 平滑加权轮询算法  ---  直接贴代码

    • 平滑加权轮询算法 ---  分析

     

    一、平滑加权轮询算法  ---  直接贴代码

    public class SmoothServer {
    
        public SmoothServer(String ip, int weight, int curWeight) {
            this.ip = ip;
            this.weight = weight;
            this.curWeight = curWeight;
        }
    
        private String ip;
    
        private int weight;
    
        private int curWeight;
    
        public String getIp() {
            return ip;
        }
    
        public void setIp(String ip) {
            this.ip = ip;
        }
    
        public int getWeight() {
            return weight;
        }
    
        public void setWeight(int weight) {
            this.weight = weight;
        }
    
        public int getCurWeight() {
            return curWeight;
        }
    
        public void setCurWeight(int curWeight) {
            this.curWeight = curWeight;
        }
    }
    服务器实体类
    public class SmoothWeightRoundRobin {
    
        /**初始化所有的服务器**/
        List<SmoothServer> servers = new ArrayList<>();
    
        /**服务器权重总和*/
        private int weightCount;
    
        public void init(List<SmoothServer> servers) {
            this.servers = servers;
            this.weightCount = this.servers.stream().map(server -> server.getWeight()).reduce(0, (l, r) -> l + r);
    
        }
    
        /**获取需要执行的服务器**/
        public SmoothServer getServer() {
            SmoothServer tmpSv = null;
    
            for (SmoothServer sv : servers) {
                sv.setCurWeight(sv.getWeight() + sv.getCurWeight());
                if (tmpSv == null || tmpSv.getCurWeight() < sv.getCurWeight()) tmpSv = sv;
            }
    
            tmpSv.setCurWeight(tmpSv.getCurWeight() - weightCount);
            return tmpSv;
        }
    
    }
    平滑权衡算法
    public class RobinExecute {
    
        /** 线程使用完不会清除该变量,会一直保留着,由于线程 池化所以不用担心内存泄漏 **/
        private ThreadLocal<SmoothWeightRoundRobin> weightRoundRobinTl = new ThreadLocal<SmoothWeightRoundRobin>();
    
        private ReentrantLock lock = new ReentrantLock();
    
        /** 为什么添加volatile,是因为 ReentrantLock 并不保证内存可见性 **/
        private volatile SmoothWeightRoundRobin smoothWeightRoundRobin;
    
        public static void main(String[] args) {
    
            RobinExecute robinExecute = new RobinExecute();
    
            /** ==================    TheadLocal   ========================**/
            robinExecute.acquireWeightRoundRobinOfTheadLocal().getServer();
    
            /** ==================    ReentrantLock 可重入锁   ========================**/
            robinExecute.getLock().lock();  //notice: 注意此锁会无休止的等待资源,如果使用此锁,无比保证资源能够被拿到
            try {
                robinExecute.acquireWeightRoundRobinOfLock();
            } catch (Exception e) {
                e.printStackTrace();
            } finally { //确保一定要释放锁
                robinExecute.getLock().unlock();
            }
    
        }
    
        /**
         * 在分布式情况,第二种使用方式  使用cas ReentrantLock 可重入锁
         * notice:
         * @return
         */
        public SmoothServer acquireWeightRoundRobinOfLock() {
            if (smoothWeightRoundRobin == null) {
                SmoothWeightRoundRobin weightRoundRobin = new SmoothWeightRoundRobin();
                List<SmoothServer> servers = new ArrayList<>();
                servers.add(new SmoothServer("191", 1, 0));
                servers.add(new SmoothServer("192", 2, 0));
                servers.add(new SmoothServer("194", 4, 0));
                weightRoundRobin.init(servers);
                smoothWeightRoundRobin = weightRoundRobin;
            }
            return smoothWeightRoundRobin.getServer();
        }
    
        /**
         * 在分布式情况,第一种使用方式  ThreadLock
         * notice: 只有在使用池化技术的情况才建议使用此方式,否则达不到效果,还会造成内存泄漏
         * @return
         */
        public SmoothWeightRoundRobin acquireWeightRoundRobinOfTheadLocal() {
            return Optional.ofNullable(weightRoundRobinTl.get())
                .orElseGet(() -> {
                    SmoothWeightRoundRobin weightRoundRobin = new SmoothWeightRoundRobin();
                    List<SmoothServer> servers = new ArrayList<>();
                    servers.add(new SmoothServer("191", 1, 0));
                    servers.add(new SmoothServer("192", 2, 0));
                    servers.add(new SmoothServer("194", 4, 0));
                    weightRoundRobin.init(servers);
                    weightRoundRobinTl.set(weightRoundRobin);
                    return weightRoundRobin;
                });
        }
    
        public ReentrantLock getLock() {
            return lock;
        }
    
        public ThreadLocal<SmoothWeightRoundRobin> getWeightRoundRobinTl() {
            return weightRoundRobinTl;
        }
    }
    两种使用方式(适用分布式环境中)

    二、平滑加权轮询算法 ---  分析

     

  • 相关阅读:
    数据更新
    MVC学习笔记
    const关键字同static readonly 的区别
    RSS
    C语言中取地址跟C++中的引用是一个意思吗?
    生产者消费者模式
    使用foreach的时候,不能对List进修改,怎么办?
    SQL查询
    Windows下的Java访问USB设备解决之道(翻译Java libusb / libusbwin32 wrapper)
    Java SE 6d新特性: 编译器 API
  • 原文地址:https://www.cnblogs.com/Shock-W/p/10063631.html
Copyright © 2020-2023  润新知