Detailed explanation of the underlying implementation method of Nginx polling algorithm

Detailed explanation of the underlying implementation method of Nginx polling algorithm

Introduction to the polling algorithm

Many people use nginx at work and are familiar with its configuration. Today I would like to introduce several underlying implementations of the nginx polling algorithm.

Simple polling algorithm

This algorithm is relatively simple. For example, you have three servers.

First Server 192.168.1.1
Second Server 192.168.1.2
The third server 192.168.1.3

After the first request comes in, the first server is accessed by default. The second request comes in to access the second server. The third request comes in to access the third server. The fourth request comes in to access the first server, and so on. The following is my code to implement a simple algorithm:

public class SimplePolling {

  /**
   * key is ip
   */
  public static List <String> ipService = new LinkedList <>();
  static {
    ipService.add("192.168.1.1");
    ipService.add("192.168.1.2");
    ipService.add("192.168.1.3");
  }
  public static int pos = 0;
  public static String getIp(){
    if(pos >= ipService.size()){
      //Prevent index from going out of bounds pos = 0;
    }
    String ip = ipService.get(pos);
    pos++;
    return ip;

  }

  public static void main(String[] args) {
    for (int i = 0; i < 4; i++) {
      System.out.println(getIp());

    }
  }
}

The simulation was performed 4 times and the results were

insert image description here

At this time, if I have a server with better performance (such as 192.168.1.1), I want this server to handle more requests. At this time, the probability of weights is involved, and this algorithm cannot be implemented. Please see the upgraded version of the polling algorithm I will describe later.

Weighted Round Robin

At this time, I need to set the weights of my first three servers, such as 5 for the first server, 1 for the second server, and 1 for the third server.

First Server 192.168.1.1 5
Second Server 192.168.1.2 1
The third server 192.168.1.3 1

At this time, the first 5 requests will access the first server, the sixth request will access the second server, and the seventh request will access the third server.

Here is the code example I gave:

public class WeightPolling {

  /**
   * key is ip, value is weight*/
  public static Map<String, Integer> ipService = new LinkedHashMap<>();
  static {
    ipService.put("192.168.1.1", 5);
    ipService.put("192.168.1.2", 1);
    ipService.put("192.168.1.3", 1);
  }
  public static int requestId = 0;
  public static int getAndIncrement() {
    return requestId++;
  }

  public static String getIp(){
    //Get the total weight int totalWeight =0;
    for (Integer value : ipService.values()) {
      totalWeight+= value;
    }
    //Get the current polling value int andIncrement = getAndIncrement();
    int pos = andIncrement% totalWeight;
    for (String ip : ipService.keySet()) {
      if(pos < ipService.get(ip)){
        return ip;
      }
      pos -= ipService.get(ip);
    }
    return null;
  }

  public static void main(String[] args) {
    for (int i = 0; i < 7; i++) {
      System.out.println(getIp());
    }
  }

}

The result of running this time is

insert image description here

It can be seen that the first server executed 5 times, and the next two servers executed once, and so on. Maybe you think this algorithm is not bad. In fact, this algorithm has a disadvantage. If I set the weight of the first server too high, I may need to execute many requests to the first server. In this case, the distribution is uneven, which may cause excessive pressure on one server and cause it to crash. So I will introduce a third algorithm to solve this problem later.

Smooth Weighted Round Robin Algorithm

This algorithm may be complicated. I didn't quite understand it the first time I saw it. After reading relevant information, I combined my own understanding to explain it to you with pictures and text. The server configuration and weights I used as examples here are the same as above.

ask Current weight = own weight + current weight after selection Total weight Current maximum weight Returned IP After selection, the current weight = the current maximum weight - the total weight
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 7 192.168.1.1 {0,0,0}

It can be seen from the above figure that although the weight of the first server is set to 5, the fifth request is not always executed by the first server. Instead, the execution is distributed, and the scheduling sequence is very uniform. In addition, after the seventh scheduling, the current weight returns to {0, 0, 0}, and the state of the instance is consistent with the initial state, so the scheduling operation can be repeated subsequently.

Some people may not clearly understand the meaning of the previous picture, so I will give a brief description here:

1. First of all, the total weight will not change. By default, it is the sum of the currently set weights.

2. When the first request comes in, I initialize the current weight selected value by default to {0,0,0}, so the current weight value is {5+0,1+0,1+0}, where 5,1,1 is the weight set for each server we set earlier.

3. Here we can conclude that the maximum weight of the first request is 5. Then return to the first server ip

4. Then we set the current weight after selection, which is the current maximum weight minus the total weight (5-7). The unselected weight remains unchanged. At this time, the value of the current weight selected weight is {5-7,1,1}

5. When the second request comes, we continue to execute steps 2, 3, and 4 above.

If you still don't understand, I will provide my own algorithm implemented in Java code below:

public class Polling {

  /**
   * key is ip, value is weight*/
  public static Map<String,Integer> ipService = new LinkedHashMap<>();
  static {
    ipService.put("192.168.1.1",5);
    ipService.put("192.168.1.2",1);
    ipService.put("192.168.1.3",1);
  }
  private static Map<String,Weight> weightMap = new LinkedHashMap <>();

  public static String getIp(){
    //Calculate the total weight int totalWeight = 0;
    for (Integer value : ipService.values()) {
      totalWeight+=value;
    }
    //First determine whether weightMap is empty if (weightMap.isEmpty()) {
      ipService.forEach((ip,weight)->{
        Weight weights = new Weight(ip, weight,0);
        weightMap.put(ip,weights);
      });
    }
    //Set the current weight for the object in the map weightMap.forEach((ip,weight)->{
      weight.setCurrentWeight(weight.getWeight() + weight.getCurrentWeight());
    });

    //Judge whether the maximum weight is greater than the current weight. If it is empty or less than the current weight, assign the current weight to the maximum weight. Weight maxWeight = null;
    for (Weight weight : weightMap.values()) {
      if(maxWeight == null || weight.getCurrentWeight() > maxWeight.getCurrentWeight()){
        maxWeight = weight;
      }
    }
    //Finally, subtract the total weight from the current maximum weight maxWeight.setCurrentWeight(maxWeight.getCurrentWeight() - totalWeight);
    //return return maxWeight.getIp();
  }

  public static void main(String[] args) {
    //Simulate polling 7 times to get IP
    for (int i = 0; i < 7; i++) {
      System.out.println(getIp());
    }
  }

}

class Weight{
  /**
   * ip
   */
  private String ip;
  /**
   * Set the weight */
  private int weight;
  /**
   * Current weight */
  private int currentWeight;

  public Weight(String ip, int weight,int currentWeight) {
    this.ip = ip;
    this.weight = weight;
    this.currentWeight = currentWeight;
  }

  public String getIp() {
    return ip;
  }

  public void setIp(String ip) {
    this.ip = ip;
  }

  public int getWeight() {
    return weight;
  }

  public void setWeight(int weight) {
    this.weight = weight;
  }

  public int getCurrentWeight() {
    return currentWeight;
  }

  public void setCurrentWeight(int currentWeight) {
    this.currentWeight = currentWeight;
  }
}

The result of executing the code here is:

insert image description here

It can be seen that the execution results here are consistent with the results described in the table.

Summarize

The third algorithm may be a little complicated to understand. If you don’t understand the meaning of the chart, you can execute the code first. It is easy to understand after debugging step by step with the debugger.

The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM.

You may also be interested in:
  • Example of how to enable Brotli compression algorithm for Nginx
  • Example of enabling Brotli algorithm compression in Nginx
  • Nginx uses the Gzip algorithm to compress messages
  • A brief understanding of several scheduling algorithms for Nginx seven-layer load balancing
  • Nginx load balancing algorithm and failover analysis
  • C# implements Nginx smooth weighted polling algorithm
  • In-depth analysis of nginx's four scheduling algorithms and advanced
  • Detailed explanation of the implementation process of Nginx enabling Brotli compression algorithm

<<:  Install redis and MySQL on CentOS

>>:  WeChat applet implements jigsaw puzzle game

Recommend

Solution to the problem that docker logs cannot be retrieved

When checking the service daily, when I went to l...

14 practical experiences on reducing SCSS style code by 50%

Preface Sass is an extension of the CSS3 language...

Detailed explanation of Apache website service configuration based on Linux

As an open source software, Apache is one of the ...

Introduction to installing JDK under Linux, including uninstalling OpenJDK

1. View openjdk rpm -qa|grep jdk 2. Delete openjd...

Installation tutorial of mysql 8.0.11 compressed version under win10

This article shares the installation tutorial of ...

How to use Linux locate command

01. Command Overview The locate command is actual...

Create a custom system tray indicator for your tasks on Linux

System tray icons are still a magical feature tod...

Common array operations in JavaScript

Table of contents 1. concat() 2. join() 3. push()...

Detailed steps to install xml extension in php under linux

Installing XML extension in PHP Linux 1. Enter th...

The whole process of upgrading Angular single project to multiple projects

Table of contents Preface Development Environment...

Vue elementUI implements tree structure table and lazy loading

Table of contents 1. Achieve results 2. Backend i...