详解Nginx轮询算法底层实现的方法

详解Nginx轮询算法底层实现的方法,第1张

详解Nginx轮询算法底层实现的方法

本文主要介绍Nginx轮询算法的详细实现方法,通过示例代码详细介绍,对大家的学习或工作有一定的参考价值。有需要的朋友下面和边肖一起学习。

轮询算法介绍

很多人在工作中使用nginx,对nginx的配置也比较熟悉。今天主要想介绍nginx轮询算法的几个底层实现。

简单轮询算法

这个算法比较简单。例如,您有三台服务器。

第一台服务器 192.168.1.1 第二台服务器 192.168.1.2 第三台服务器 192.168.1.3

第一个请求来了之后,第一个默认访问,第二个访问第二个,第三个访问第三个,第四个访问第一个,以此类推。下面是我的代码实现的一个简单算法:

publicclassSimplePolling{ /** *key是ip */ publicstaticList<String>ipService=newLinkedList<>(); static{ ipService.add("192.168.1.1"); ipService.add("192.168.1.2"); ipService.add("192.168.1.3"); } publicstaticintpos=0; publicstaticStringgetIp(){ if(pos>=ipService.size()){ //防止索引越界 pos=0; } Stringip=ipService.get(pos); pos++; returnip; } publicstaticvoidmain(String[]args){ for(inti=0;i<4;i++){ System.out.println(getIp()); } } }

模拟执行4次,结果为


这时候如果我有一个性能更好的服务器(比如192.168.1.1),我想让这个服务器多处理一点请求,那么就涉及到了得到权重的概率,这个算法就无法实现。请参阅稍后描述的更新轮询算法。

加权轮询算法

此时,我需要设置我面前所有三台服务器的权重,比如第一套5,第二套1,第三套1。

第一台服务器 192.168.1.1 5 第二台服务器 192.168.1.2 1 第三台服务器 192.168.1.3 1

此时,前五个请求将访问第一个服务器,第六个请求将访问第二个服务器,第七个请求将访问第三个服务器。

以下是我给出的代码示例:

publicclassWeightPolling{ /** *key是ip,value是权重 */ publicstaticMap<String,Integer>ipService=newLinkedHashMap<>(); static{ ipService.put("192.168.1.1",5); ipService.put("192.168.1.2",1); ipService.put("192.168.1.3",1); } publicstaticintrequestId=0; publicstaticintgetAndIncrement(){ returnrequestId++; } publicstaticStringgetIp(){ //获取总的权重 inttotalWeight=0; for(Integervalue:ipService.values()){ totalWeight+=value; } //获取当前轮询的值 intandIncrement=getAndIncrement(); intpos=andIncrement%totalWeight; for(Stringip:ipService.keySet()){ if(pos<ipService.get(ip)){ returnip; } pos-=ipService.get(ip); } returnnull; } publicstaticvoidmain(String[]args){ for(inti=0;i<7;i++){ System.out.println(getIp()); } } }

运行结果是


可以查看的第一个服务器执行五次,接下来的两个服务器依次执行一次,以此类推。也许你觉得这个算法还不错。其实这个算法有一个缺点。如果我的第一个服务器的权重太大,我可能需要对第一个服务器执行许多请求。这种情况分布不均,会导致某个服务器因为压力过大而崩溃。所以我后面会介绍第三种算法来解决这个问题。

平滑加权轮询算法

这个算法可能比较复杂,我第一次也不是很懂。后来看了相关资料,用自己的理解解释了一下。在这里,我的服务器配置和重量同上。

请求 当前重量=自身重量+选择后的当前重量。 总重量 当前最大重量 Ip返回者 选择当前重量=当前最大重量-总重量。 1 {5,1,1} 7 5 192.168.1.1 {-2,1,1} 2 {3,2,2} 7 3 192.168.1.1 {-4,2,2} 3 {1,3,3} 7 3 192.168.1.2 {1,-4,3} 4 {6,-3,4} 7 6 192.168.1.1 {-1,-3,4} 5 {4,-2,5} 7 5 192.168.1.3 {4,-2,-2} 6 {9,-1,-1} 7 9 192.168.1.1 {2,-1,-1} 7 {7,0,0} 7 192.168.1.1 {0,0,0}

从上图可以看出,虽然第一个服务器的权重设置为5,但是第五个请求并不总是由第一个服务器执行,而是分散的。调度顺序非常统一,第七次调度后当前权重回到{0,0,0}。实例的状态与初始状态一致,因此后续的调度 *** 作可以一直重复。

可能有些人还不能清楚的理解前面那张图的意思。我在这里给你一个大概的描述:

1.首先,总权重不会改变,默认是当前设置的权重之和。

2.当第一个请求进来的时候,我将当前权重的选择值默认初始化为{0,0,0},所以当前权重为{5+0,1+0,1+0},其中5,1,1是我们面前每个服务器设置的权重。

3.这里我们可以得出结论,第一个请求的最大权重是5。然后返回第一个服务器ip

4.然后我们设置选择后的当前权重,这里是当前最大权重减去总权重(5-7),没有选择的权重保持不变。此时,我们得到当前权重{5-7,1,1}的选定权重的值。

5.当第二个请求到来时,我们继续上面的步骤2、3和4。

如果你在这里还不明白,我会在下面提供我自己用java代码实现的算法:

publicclassPolling{ /** *key是ip,value是权重 */ publicstaticMap<String,Integer>ipService=newLinkedHashMap<>(); static{ ipService.put("192.168.1.1",5); ipService.put("192.168.1.2",1); ipService.put("192.168.1.3",1); } privatestaticMap<String,Weight>weightMap=newLinkedHashMap<>(); publicstaticStringgetIp(){ //计算总的权重 inttotalWeight=0; for(Integervalue:ipService.values()){ totalWeight+=value; } //首先判断weightMap是否为空 if(weightMap.isEmpty()){ ipService.forEach((ip,weight)->{ Weightweights=newWeight(ip,weight,0); weightMap.put(ip,weights); }); } //给map中得对象设置当前权重 weightMap.forEach((ip,weight)->{ weight.setCurrentWeight(weight.getWeight()+weight.getCurrentWeight()); }); //判断最大权重是否大于当前权重,如果为空或者小于当前权重,则把当前权重赋值给最大权重 WeightmaxWeight=null; for(Weightweight:weightMap.values()){ if(maxWeight==null||weight.getCurrentWeight()>maxWeight.getCurrentWeight()){ maxWeight=weight; } } //最后把当前最大权重减去总的权重 maxWeight.setCurrentWeight(maxWeight.getCurrentWeight()-totalWeight); //返回 returnmaxWeight.getIp(); } publicstaticvoidmain(String[]args){ //模拟轮询7次取ip for(inti=0;i<7;i++){ System.out.println(getIp()); } } } classWeight{ /** *ip */ privateStringip; /** *设置得权重 */ privateintweight; /** *当前权重 */ privateintcurrentWeight; publicWeight(Stringip,intweight,intcurrentWeight){ this.ip=ip; this.weight=weight; this.currentWeight=currentWeight; } publicStringgetIp(){ returnip; } publicvoidsetIp(Stringip){ this.ip=ip; } publicintgetWeight(){ returnweight; } publicvoidsetWeight(intweight){ this.weight=weight; } publicintgetCurrentWeight(){ returncurrentWeight; } publicvoidsetCurrentWeight(intcurrentWeight){ this.currentWeight=currentWeight; } }

这里代码的执行结果是:


可以看出,这里的执行结果与表中描述的结果是一致的。

摘要

可能第三种算法理解起来有点复杂。如果不能理解图的意思,可以先执行代码。调试器经过一步一步调试,还是比较好理解的。

这就是本文的全部内容。希望对大家的学习有帮助,支持我们。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/774641.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-03
下一篇 2022-05-03

发表评论

登录后才能评论

评论列表(0条)

保存