介绍Nacos在客户端选择节点时提供了一种基于权重的随机算法。通过源码分析,我们可以掌握其实现原理,方便其在实战中的应用。1.内容概要随机权重负载均衡算法的流程如下图所示:节点列表假设注册了5个节点,每个节点的权重如下。组织递增数组的目的是形成一个权重数组。数组的元素取值在[0~1]范围内,元素逐一递增。计算过程如下图所示。还要注意,不健康的节点或权重小于或等于0的节点将不会被选中。随机算法产生一个[0~1]范围内的随机数,通过二分法找到接近递增数组weights[]的索引,然后从注册的节点列表中返回该节点。2.源码分析NacosNamingService#selectOneHealthyInstance中提供了随机权重负载均衡算法,我们一起看看。@OverridepublicInstanceselectOneHealthyInstance(StringserviceName,StringgroupName,booleansubscribe)throwsNacosException{returnsselectOneHealthyInstance(serviceName,groupName,newArrayList(),subscribe);}@OverridepublicInstanceselectOneHealthyInstance(StringserviceName,StringgroupName,Listclusters,booleansubscribe)throwsNacosException{StringclusterString.=joinStringUtils(clusters,",");//注解@1if(subscribe){ServiceInfoserviceInfo=serviceInfoHolder.getServiceInfo(serviceName,groupName,clusterString);if(null==serviceInfo){serviceInfo=clientProxy.subscribe(serviceName,groupName,clusterString);}returnBalancer.RandomByWeight.selectHost(serviceInfo);}else{//注解@2ServiceInfoserviceInfo=clientProxy.queryInstancesOfService(serviceName,groupName,clusterString,0,false);returnBalancer.RandomByWeight.selectHost(serviceInfo);}}注解@1已订阅「从存档获取注册节点列表」,默认订阅为true。注意@2ProtectedstaticInstancegetHostByRandomWeight(Listhosts){NAMING_LOGGER.debug("entryrandomWithWeight");if(hosts==null||hosts.size()==0){NAMING_LOGGER。debug("hosts==null||hosts.size()==0");returnnull;}NAMING_LOGGER.debug("newChooser");List>hostsWithWeight=newArrayList>();for(Instancehost:hosts){if(host.isHealthy()){//注意@3hostsWithWeight.add(newPair(host,host.getWeight()));}}NAMING_LOGGER.debug("for(Hosthost:hosts)");ChooservipChooser=newChooser("www.taobao.com");//注意@4vipChooser.refresh(hostsWithWeight);NAMING_LOGGER.debug("vipChooser.refresh");//注解@5returnvipChooser.randomWithWeight();}注解@3不选择非健康节点,组装Pair列表,包括健康节点的权重和Host信息注解@4刷新需要的数据,包括三部分:对所有健康节点的权重求和,计算每个健康节点的权重比例,组织增量数组。publicvoidrefresh(){DoubleoriginWeightSum=(double)0;//注意@4.1for(Pairitem:itemsWithWeight){doubleweight=item.weight();//忽略itemwhichweightiszero.seetest_randomWithWeight_weight0inChooserTest//权重小于等于0将被移除if(weight<=0){continue;}items.add(item.item());//如果值为无穷大if(Double.isInfinite(weight)){weight=10000.0D;}//如果值不是数字Valueif(Double.isNaN(weight)){weight=1.0D;}//累计权重和originWeightSum+=weight;}//注意@4.2double[]exactWeights=newdouble[items.size()];intindex=0;for(Pairitem:itemsWithWeight){doublesingleWeight=item.weight();//忽略itemwhichweightiszero.seetest_randomWithWeight_weight0inChooserTestif(singleWeight<=0){continue;}//每个节点权重的比例exactWeights[index++]=singleWeight/originWeightSum;}//注意@4.3weights=newdouble[items.size()];doublerandomRange=0D;for(inti=0;iref=this.ref;//Annotation@5.1doublerandom=ThreadLocalRandom.current().nextDouble(0,1);//注解@5.2intindex=Arrays.binarySearch(ref.weights,random);//注解@5.3if(index<0){index=-index-1;}else{//注意@5.4returnref.items.get(index);}//返回选中的元素if(index>=0&&index