自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Nacos之隨機(jī)權(quán)重負(fù)載均衡算法

開發(fā) 前端 算法
Nacos在Client選擇節(jié)點(diǎn)時(shí)提供了一種基于權(quán)重的隨機(jī)算法,通過源碼分析掌握其實(shí)現(xiàn)原理,方便實(shí)戰(zhàn)中加以運(yùn)用。

引言

Nacos在Client選擇節(jié)點(diǎn)時(shí)提供了一種基于權(quán)重的隨機(jī)算法,通過源碼分析掌握其實(shí)現(xiàn)原理,方便實(shí)戰(zhàn)中加以運(yùn)用。

一、內(nèi)容提要

下面以圖示的方式貫穿下隨機(jī)權(quán)重負(fù)載均衡算法的流程:

節(jié)點(diǎn)列表

假設(shè)注冊了5個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)的權(quán)重如下。

組織遞增數(shù)組

目的在于形成weights數(shù)組,該數(shù)組元素取值[0~1]范圍,元素逐個(gè)遞增,計(jì)算過程如下圖示。另外注意非健康節(jié)點(diǎn)或者權(quán)重小于等于0的不會被選擇。

隨機(jī)算法

通過生成[0~1]范圍的隨機(jī)數(shù),通過二分法查找遞增數(shù)組weights[]接近的index,再從注冊節(jié)點(diǎn)列表中返回節(jié)點(diǎn)。

二、源碼分析

隨機(jī)權(quán)重負(fù)載均衡算法是在NacosNamingService#selectOneHealthyInstance提供,一起走查下。

  1. @Override 
  2. public Instance selectOneHealthyInstance(String serviceName, String groupName, boolean subscribe) 
  3.   throws NacosException { 
  4.   return selectOneHealthyInstance(serviceName, groupName, new ArrayList<String>(), subscribe); 
  1. @Override 
  2. public Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters, 
  3.                                          boolean subscribe) throws NacosException { 
  4.   String clusterString = StringUtils.join(clusters, ","); 
  5.   // 注解@1 
  6.   if (subscribe) { 
  7.     ServiceInfo serviceInfo = serviceInfoHolder.getServiceInfo(serviceName, groupName, clusterString); 
  8.     if (null == serviceInfo) { 
  9.       serviceInfo = clientProxy.subscribe(serviceName, groupName, clusterString); 
  10.     } 
  11.     return Balancer.RandomByWeight.selectHost(serviceInfo); 
  12.   } else { 
  13.     // 注解@2 
  14.     ServiceInfo serviceInfo = clientProxy 
  15.       .queryInstancesOfService(serviceName, groupName, clusterString, 0, false); 
  16.     return Balancer.RandomByWeight.selectHost(serviceInfo); 
  17.   } 

注解@1 已訂閱「從緩存獲取注冊節(jié)點(diǎn)列表」,默認(rèn)subscribe為true。

注解@2 從 「從服務(wù)器獲取注冊節(jié)點(diǎn)列表」

  1. protected static Instance getHostByRandomWeight(List<Instance> hosts) { 
  2.   NAMING_LOGGER.debug("entry randomWithWeight"); 
  3.   if (hosts == null || hosts.size() == 0) { 
  4.     NAMING_LOGGER.debug("hosts == null || hosts.size() == 0"); 
  5.     return null
  6.   } 
  7.   NAMING_LOGGER.debug("new Chooser"); 
  8.   List<Pair<Instance>> hostsWithWeight = new ArrayList<Pair<Instance>>(); 
  9.   for (Instance host : hosts) { 
  10.     if (host.isHealthy()) {  // 注解@3 
  11.       hostsWithWeight.add(new Pair<Instance>(host, host.getWeight())); 
  12.     } 
  13.   } 
  14.   NAMING_LOGGER.debug("for (Host host : hosts)"); 
  15.   Chooser<String, Instance> vipChooser = new Chooser<String, Instance>("www.taobao.com"); 
  16.   // 注解@4 
  17.   vipChooser.refresh(hostsWithWeight); 
  18.   NAMING_LOGGER.debug("vipChooser.refresh"); 
  19.   // 注解@5 
  20.   return vipChooser.randomWithWeight(); 

注解@3 非健康節(jié)點(diǎn)不會被選中,組裝Pair的列表,包含健康節(jié)點(diǎn)的權(quán)重和Host信息

注解@4 刷新需要的數(shù)據(jù),具體包括三部分:所有健康節(jié)點(diǎn)權(quán)重求和、計(jì)算每個(gè)健康節(jié)點(diǎn)權(quán)重占比、組織遞增數(shù)組。

  1. public void refresh() { 
  2.     Double originWeightSum = (double) 0; 
  3.     // 注解@4.1 
  4.     for (Pair<T> item : itemsWithWeight) { 
  5.  
  6.         double weight = item.weight(); 
  7.         // ignore item which weight is zero.see test_randomWithWeight_weight0 in ChooserTest 
  8.         // weight小于等于 0的將會剔除 
  9.         if (weight <= 0) { 
  10.             continue
  11.         } 
  12.  
  13.         items.add(item.item()); 
  14.  
  15.         // 值如果無窮大 
  16.         if (Double.isInfinite(weight)) { 
  17.             weight = 10000.0D; 
  18.         } 
  19.  
  20.         // 值如果為非數(shù)字值 
  21.         if (Double.isNaN(weight)) { 
  22.             weight = 1.0D; 
  23.         } 
  24.  
  25.         // 累加權(quán)重總和 
  26.         originWeightSum += weight; 
  27.     } 
  28.  
  29.     // 注解@4.2 
  30.     double[] exactWeights = new double[items.size()]; 
  31.     int index = 0; 
  32.     for (Pair<T> item : itemsWithWeight) { 
  33.         double singleWeight = item.weight(); 
  34.         //ignore item which weight is zero.see test_randomWithWeight_weight0 in ChooserTest 
  35.         if (singleWeight <= 0) { 
  36.             continue
  37.         } 
  38.         // 每個(gè)節(jié)點(diǎn)權(quán)重的占比 
  39.         exactWeights[index++] = singleWeight / originWeightSum; 
  40.     } 
  41.  
  42.     // 注解@4.3 
  43.     weights = new double[items.size()]; 
  44.     double randomRange = 0D; 
  45.     for (int i = 0; i < index; i++) { 
  46.         weights[i] = randomRange + exactWeights[i]; 
  47.         randomRange += exactWeights[i]; 
  48.     } 
  49.    
  50.     double doublePrecisionDelta = 0.0001; 
  51.  
  52.     if (index == 0 || (Math.abs(weights[index - 1] - 1) < doublePrecisionDelta)) { 
  53.         return
  54.     } 
  55.     throw new IllegalStateException( 
  56.             "Cumulative Weight caculate wrong , the sum of probabilities does not equals 1."); 

注解@4.1 所有健康節(jié)點(diǎn)權(quán)重求和originWeightSum

注解@4.2 計(jì)算每個(gè)健康節(jié)點(diǎn)權(quán)重占比exactWeights數(shù)組

注解@4.3 組織遞增數(shù)組weights,每個(gè)元素值為數(shù)組前面元素之和

以一個(gè)例子來表示這個(gè)過程,假設(shè)有5個(gè)節(jié)點(diǎn):

  1. 1.2.3.4 100 
  2. 1.2.3.5 100 
  3. 1.2.3.6 100 
  4. 1.2.3.7 80 
  5. 1.2.3.8 60 

步驟一 計(jì)算節(jié)點(diǎn)權(quán)重求和

  • originWeightSum = 100 + 100 + 100 + 80 + 60 = 440

步驟二 計(jì)算每個(gè)節(jié)點(diǎn)權(quán)重占比

  • exactWeights[0] = 0.2272
  • exactWeights[1] = 0.2272
  • exactWeights[2] = 0.2272
  • exactWeights[3] = 0.1818
  • exactWeights[4] = 0.1363

步驟三 組織遞增數(shù)組weights

  • weights[0] = 0.2272
  • weights[1] = 0.4544
  • weights[2] = 0.6816
  • weights[3] = 0.8634
  • weights[4] = 1

注解@5 隨機(jī)選取一個(gè),邏輯如下:

  1. public T randomWithWeight() { 
  2.     Ref<T> ref = this.ref; 
  3.     // 注解@5.1 
  4.     double random = ThreadLocalRandom.current().nextDouble(0, 1); 
  5.     // 注解@5.2 
  6.     int index = Arrays.binarySearch(ref.weights, random); 
  7.     // 注解@5.3 
  8.     if (index < 0) { 
  9.         index = -index - 1; 
  10.     } else { 
  11.         // 注解@5.4 
  12.         return ref.items.get(index); 
  13.     } 
  14.  
  15.     // 返回選中的元素 
  16.     if (index >= 0 && index < ref.weights.length) { 
  17.         if (random < ref.weights[index]) { 
  18.             return ref.items.get(index); 
  19.         } 
  20.     } 
  21.  
  22.     /* This should never happen, but it ensures we will return a correct 
  23.      * object in case there is some floating point inequality problem 
  24.      * wrt the cumulative probabilities. */ 
  25.     return ref.items.get(ref.items.size() - 1); 

注解@5.1 產(chǎn)生0到1區(qū)間的隨機(jī)數(shù)

注解@5.2 二分法查找數(shù)組中接近的值

注解@5.3 沒有命中返回插入數(shù)組理想索引值

注解@5.4 命中直接返回選中節(jié)點(diǎn)

小結(jié): 一種基于權(quán)重的隨機(jī)算法的實(shí)現(xiàn)過程,扒開看也不復(fù)雜。

本文轉(zhuǎn)載自微信公眾號「瓜農(nóng)老梁」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系瓜農(nóng)老梁公眾號。

 

責(zé)任編輯:武曉燕 來源: 瓜農(nóng)老梁
相關(guān)推薦

2021-08-23 06:59:22

Nacos負(fù)載均衡客戶端

2010-05-04 16:10:51

負(fù)載均衡算法

2019-07-12 09:14:07

分布式系統(tǒng)負(fù)載均衡

2019-03-18 10:44:41

負(fù)載均衡DNSUDP

2018-11-07 10:12:37

2024-12-20 12:12:19

Redis負(fù)載均衡節(jié)點(diǎn)

2010-04-27 13:12:04

負(fù)載均衡算法

2023-10-31 16:38:02

注冊中心負(fù)載均衡器

2018-04-10 10:49:17

負(fù)載均衡算法服務(wù)器

2019-09-27 08:18:13

負(fù)載均衡核心Key

2010-04-28 12:24:42

網(wǎng)站負(fù)載均衡

2010-04-26 17:07:59

網(wǎng)絡(luò)負(fù)載均衡

2010-05-10 14:20:24

負(fù)載均衡技術(shù)

2010-04-26 14:44:36

負(fù)載均衡設(shè)備

2021-04-22 07:47:46

Linux進(jìn)程管理

2021-01-26 05:35:24

負(fù)載均衡系統(tǒng)設(shè)計(jì)

2017-07-03 08:08:25

負(fù)載均衡分類

2009-05-01 09:33:27

應(yīng)用交換負(fù)載均衡

2010-05-05 18:55:51

負(fù)載均衡算法

2010-05-10 14:11:41

負(fù)載均衡算法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號