路由算法-WeightedResponseTimeRule

路由算法-WeightedResponseTimeRule

算法模拟:

1>假如现在有五台机器部署的同一个服务,30s内得这段时间统计得结果如下:

  • 第一台: 120ms
  • 第二台: 150ms
  • 第三台: 80ms
  • 第四台: 90ms
  • 第五台: 180ms

那么路由总时间比重为: 120 + 150 + 80 + 90 + 180 = 620.0ms

2>每一台机器的比重如下:

初始化比重weight: 0.0

  • 第一台: 0.0 + (620 - 120) = 500.0 weight:500.0 weightSoFar: 500.0
  • 第二台: 500.0 + (620 - 150) = 970.0 weight:470.0 weightSoFar:970.0
  • 第三台: 970.0 + (620 - 80) = 1510.0 weight: 540.0 weightSoFar:1510.0
  • 第四台: 1510.0 + (620 - 90) = 2040.0 weight:530.0 weightSoFar:2040.0
  • 第五台: 2040.0 + (620 - 180) = 2480.0 weight: 440.0 weightSoFar:2480.0

此时将每个weightSoFar放到一个列表中,与server列表相对应

3>概率计算如下:

  • 第一台的概率: 500.0 / 2480.0 = 0.201612
  • 第二台的概率: (970.0 - 500.0) / 2480.0 = 0.189516
  • 第三台的概率: (1510.0 - 970.0) / 2480.0 = 0.217141
  • 第四台的概率: (2040.0 - 1510.0) / 2480.0 = 0.213709
  • 第五台的概率: (2480.0 - 2040.0) / 2480.0 = 0.177419

结果: 第三台 > 第四台 > 第一台 > 第二台 > 第五台

4>机器server的获取

(0.0~1.0)*2480获取的值落到(0,500]为第一台机器,落到(500,970]为第二台机器,落到(970,1510]为第三台机器,落到(1510,2040]为第四台机器,落到(2040,2480]为第五台机器,

定时任务

每30s获取一下权重列表

    void initialize(ILoadBalancer lb) {        
        if (serverWeightTimer != null) {
            serverWeightTimer.cancel();
        }
        //定时任务每间隔30s获得一下权重列表
        serverWeightTimer = new Timer("NFLoadBalancer-serverWeightTimer-"
                + name, true);
        serverWeightTimer.schedule(new DynamicServerWeightTask(), 0,
                serverWeightTaskTimerInterval);
        // do a initial run
        ServerWeight sw = new ServerWeight();
        sw.maintainWeights();
        //关闭时的钩子函数
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            public void run() {
                logger
                        .info("Stopping NFLoadBalancer-serverWeightTimer-"
                                + name);
                serverWeightTimer.cancel();
            }
        }));
    }

 class DynamicServerWeightTask extends TimerTask {
        public void run() {
            ServerWeight serverWeight = new ServerWeight();
            try {
                serverWeight.maintainWeights();
            } catch (Exception e) {
                logger.error("Error running DynamicServerWeightTask for {}", name, e);
            }
        }
    }

权重列表的获取

class ServerWeight {

        public void maintainWeights() {
            ILoadBalancer lb = getLoadBalancer();
            if (lb == null) {
                return;
            }
            
            if (!serverWeightAssignmentInProgress.compareAndSet(false,  true))  {
                return; 
            }
            
            try {
                logger.info("Weight adjusting job started");
                AbstractLoadBalancer nlb = (AbstractLoadBalancer) lb;
                LoadBalancerStats stats = nlb.getLoadBalancerStats();
                if (stats == null) {
                    // no statistics, nothing to do
                    return;
                }
                double totalResponseTime = 0;
                // 获得每台server平均响应时间的总和
                for (Server server : nlb.getAllServers()) {
                    // this will automatically load the stats if not in cache
                    ServerStats ss = stats.getSingleServerStat(server);
                    totalResponseTime += ss.getResponseTimeAvg();
                }
                // weight for each server is (sum of responseTime of all servers - responseTime)
                // so that the longer the response time, the less the weight and the less likely to be chosen
                Double weightSoFar = 0.0;
                
                // create new list and hot swap the reference
                List<Double> finalWeights = new ArrayList<Double>();
                for (Server server : nlb.getAllServers()) {
                    ServerStats ss = stats.getSingleServerStat(server);
                    double weight = totalResponseTime - ss.getResponseTimeAvg();
                    weightSoFar += weight;
                    finalWeights.add(weightSoFar);   
                }
                setWeights(finalWeights);
            } catch (Exception e) {
                logger.error("Error calculating server weights", e);
            } finally {
                serverWeightAssignmentInProgress.set(false);
            }

        }
    }

机器的获取

public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            // get hold of the current reference in case it is changed from the other thread
            List<Double> currentWeights = accumulatedWeights;
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();

            if (serverCount == 0) {
                return null;
            }

            int serverIndex = 0;

            // 获得最大的权重值
            double maxTotalWeight = currentWeights.size() == 0 ? 0 : currentWeights.get(currentWeights.size() - 1); 
            // 权重列表获得非法走轮询算法
            if (maxTotalWeight < 0.001d || serverCount != currentWeights.size()) {
                server =  super.choose(getLoadBalancer(), key);
                if(server == null) {
                    return server;
                }
            } else {
                // 取0.0-maxTotalWeight之间的随机数,然后再权重列表中获取区间内的server
                double randomWeight = random.nextDouble() * maxTotalWeight;
                // pick the server index based on the randomIndex
                int n = 0;
                for (Double d : currentWeights) {
                    if (d >= randomWeight) {
                        serverIndex = n;
                        break;
                    } else {
                        n++;
                    }
                }

                server = allList.get(serverIndex);
            }

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            // Next.
            server = null;
        }
        return server;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值