本文主要介绍Nginx轮询算法的详细实现方法,通过示例代码详细介绍,对大家的学习或工作有一定的参考价值。有需要的朋友下面和边肖一起学习。
轮询算法介绍
很多人在工作中使用nginx,对nginx的配置也比较熟悉。今天主要想介绍nginx轮询算法的几个底层实现。
简单轮询算法
这个算法比较简单。例如,您有三台服务器。
第一个请求来了之后,第一个默认访问,第二个访问第二个,第三个访问第三个,第四个访问第一个,以此类推。下面是我的代码实现的一个简单算法:
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。
此时,前五个请求将访问第一个服务器,第六个请求将访问第二个服务器,第七个请求将访问第三个服务器。
以下是我给出的代码示例:
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()); } } }运行结果是
可以查看的第一个服务器执行五次,接下来的两个服务器依次执行一次,以此类推。也许你觉得这个算法还不错。其实这个算法有一个缺点。如果我的第一个服务器的权重太大,我可能需要对第一个服务器执行许多请求。这种情况分布不均,会导致某个服务器因为压力过大而崩溃。所以我后面会介绍第三种算法来解决这个问题。
平滑加权轮询算法
这个算法可能比较复杂,我第一次也不是很懂。后来看了相关资料,用自己的理解解释了一下。在这里,我的服务器配置和重量同上。
从上图可以看出,虽然第一个服务器的权重设置为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; } }这里代码的执行结果是:
可以看出,这里的执行结果与表中描述的结果是一致的。
摘要
可能第三种算法理解起来有点复杂。如果不能理解图的意思,可以先执行代码。调试器经过一步一步调试,还是比较好理解的。
这就是本文的全部内容。希望对大家的学习有帮助,支持我们。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)