Nginxポーリングアルゴリズムの基本的な実装方法の詳細な説明

Nginxポーリングアルゴリズムの基本的な実装方法の詳細な説明

ポーリングアルゴリズムの紹介

多くの人が職場で nginx を使用しており、その設定に精通しています。今日は、nginx ポーリング アルゴリズムの基礎となる実装をいくつか紹介したいと思います。

シンプルなポーリングアルゴリズム

このアルゴリズムは比較的単純です。たとえば、サーバーが 3 台あるとします。

最初のサーバー192.168.1.1
セカンドサーバー192.168.1.2
3番目のサーバー192.168.1.3

最初のリクエストが到着すると、デフォルトで最初のサーバーにアクセスします。2 番目のリクエストは、2 番目のサーバーにアクセスするために到着します。3 番目のリクエストは、3 番目のサーバーにアクセスするために到着します。4 番目のリクエストは、最初のサーバーにアクセスするために到着します。以下は、単純なアルゴリズムを実装するためのコードです。

パブリッククラスSimplePolling {

  /**
   * キーはip
   */
  パブリック静的リスト <String> ipService = 新しい LinkedList <>();
  静的{
    ipService.add("192.168.1.1");
    ipService.add("192.168.1.2");
    ipService.add("192.168.1.3");
  }
  パブリック静的int pos = 0;
  パブリック静的文字列 getIp(){
    if(pos >= ipService.size()){
      //インデックスが範囲外にならないようにする pos = 0;
    }
    文字列 ip = ipService.get(pos);
    位置++;
    IP を返します。

  }

  パブリック静的voidメイン(String[] args) {
    (int i = 0; i < 4; i++) の場合 {
      System.out.println(getIp());

    }
  }
}

シミュレーションは4回実行され、結果は

ここに画像の説明を挿入

このとき、より性能の良いサーバー(192.168.1.1 など)があれば、このサーバーでより多くのリクエストを処理したいと考えています。このとき、重みの確率が関係しており、このアルゴリズムは実装できません。後で説明するポーリング アルゴリズムのアップグレード バージョンを参照してください。

加重ラウンドロビン

このとき、最初の 3 つのサーバーの重みを、最初のサーバーには 5、2 番目のサーバーには 1、3 番目のサーバーには 1 のように設定する必要があります。

最初のサーバー192.168.1.1 5
セカンドサーバー192.168.1.2 1
3番目のサーバー192.168.1.3 1

このとき、最初の 5 つのリクエストは最初のサーバーにアクセスし、6 番目のリクエストは 2 番目のサーバーにアクセスし、7 番目のリクエストは 3 番目のサーバーにアクセスします。

私が示したコード例は次のとおりです。

パブリッククラス WeightPolling {

  /**
   * キーは ip、値は weight*/
  パブリック静的 Map<String, Integer> ipService = new LinkedHashMap<>();
  静的{
    ipService.put("192.168.1.1", 5);
    ipService.put("192.168.1.2", 1);
    ipService.put("192.168.1.3", 1);
  }
  パブリック静的intリクエストId = 0;
  パブリック静的int getAndIncrement() {
    requestId++ を返します。
  }

  パブリック静的文字列 getIp(){
    // 総重量を取得します int totalWeight =0;
    (整数値: ipService.values()) {
      合計重量+=値;
    }
    //現在のポーリング値を取得します int andIncrement = getAndIncrement();
    int pos = andIncrement% totalWeight;
    (文字列ip:ipService.keySet()) {
      ipService.get(ip) が pos より小さい場合
        IP を返します。
      }
      pos -= ipService.get(ip);
    }
    null を返します。
  }

  パブリック静的voidメイン(String[] args) {
    (int i = 0; i < 7; i++) の場合 {
      System.out.println(getIp());
    }
  }

}

今回走った結果は

ここに画像の説明を挿入

最初のサーバーが 5 回実行され、次の 2 つのサーバーが 1 回実行された、というように実行されたことがわかります。おそらく、このアルゴリズムは悪くないと思うでしょう。実は、このアルゴリズムには欠点があります。最初のサーバーの重みを高く設定しすぎると、最初のサーバーに多くのリクエストを実行する必要がある場合があります。この場合、分散が不均一になり、1 つのサーバーに過度の負荷がかかり、クラッシュする可能性があります。そこで、この問題を解決するための 3 番目のアルゴリズムを後で紹介します。

滑らかな重み付けラウンドロビンアルゴリズム

このアルゴリズムは複雑かもしれません。初めて見たときはよくわかりませんでした。関連情報を読んだ後、自分の理解を組み合わせて、画像とテキストで説明しました。ここで例として使用したサーバー構成と重みは上記と同じです。

聞く現在の体重 = 自分の体重 + 選択後の現在の体重総重量現在の最大重量返された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 7 192.168.1.1 {0,0,0}

上図から、第 1 サーバーの重みが 5 に設定されているにもかかわらず、5 番目のリクエストが必ずしも第 1 サーバーによって実行されるわけではないことがわかります。代わりに、実行は分散され、スケジューリングのシーケンスは非常に均一です。また、7 回目のスケジューリング後、現在の重みは {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 番目のリクエストが来たら、上記の手順 2、3、4 を引き続き実行します。

それでもまだ理解できない場合は、以下に Java コードで実装した独自のアルゴリズムを示します。

パブリッククラスポーリング{

  /**
   * キーは ip、値は weight*/
  パブリック静的 Map<String,Integer> ipService = new LinkedHashMap<>();
  静的{
    ipService.put("192.168.1.1",5);
    ipService.put("192.168.1.2",1);
    ipService.put("192.168.1.3",1);
  }
  プライベート静的 Map<String,Weight> weightMap = new LinkedHashMap <>();

  パブリック静的文字列 getIp(){
    // 総重量を計算します int totalWeight = 0;
    (整数値: ipService.values()) {
      合計重量+=値;
    }
    //まずweightMapが空かどうかを判定します。if (weightMap.isEmpty()) {
      ipService.forEach((ip,weight)->{
        重み weights = new Weight(ip, weight,0);
        weightMap.put(ip,weights);
      });
    }
    //マップ内のオブジェクトの現在の重みを設定します weightMap.forEach((ip,weight)->{
      weight.setCurrentWeight(weight.getWeight() + weight.getCurrentWeight());
    });

    // 最大重量が現在の重量より大きいかどうかを判断します。空または現在の重量より小さい場合は、現在の重量を最大重量に割り当てます。 Weight maxWeight = null;
    (重量 weight : weightMap.values()) の場合 {
      if(maxWeight == null || weight.getCurrentWeight() > maxWeight.getCurrentWeight()){
        maxWeight = 重量;
      }
    }
    //最後に、現在の最大重量から合計重量を減算します。maxWeight.setCurrentWeight(maxWeight.getCurrentWeight() - totalWeight);
    //戻り値 maxWeight.getIp();
  }

  パブリック静的voidメイン(String[] args) {
    //IPを取得するために7回のポーリングをシミュレートする
    (int i = 0; i < 7; i++) の場合 {
      System.out.println(getIp());
    }
  }

}

クラス ウェイト{
  /**
   * IPアドレス
   */
  プライベート文字列 ip;
  /**
   * 重量を設定する */
  プライベート int 重み;
  /**
   * 現在の体重 */
  プライベート int 現在の重量;

  パブリックウェイト(文字列ip、intウェイト、int現在のウェイト) {
    ip は ip です。
    this.weight = 重量;
    this.currentWeight = 現在の重量;
  }

  パブリック文字列 getIp() {
    IP を返します。
  }

  パブリック void setIp(String ip) {
    ip は ip です。
  }

  パブリック int getWeight() {
    重量を返します。
  }

  パブリック void setWeight(int 重量) {
    this.weight = 重量;
  }

  パブリック int getCurrentWeight() {
    現在の重量を返します。
  }

  パブリック void setCurrentWeight(int currentWeight) {
    this.currentWeight = 現在の重量;
  }
}

ここでコードを実行した結果は次のようになります。

ここに画像の説明を挿入

ここでの実行結果は、表に記載されている結果と一致していることがわかります。

要約する

3 番目のアルゴリズムは、少し複雑でわかりにくいかもしれません。チャートの意味がわからない場合は、まずコードを実行してください。デバッガーでステップごとにデバッグすると、簡単に理解できます。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Nginx で Brotli 圧縮アルゴリズムを有効にする方法の例
  • Nginx で Brotli アルゴリズム圧縮を有効にする例
  • NginxはGzipアルゴリズムを使用してメッセージを圧縮します
  • Nginx 7層負荷分散のいくつかのスケジューリングアルゴリズムの簡単な理解
  • Nginx の負荷分散アルゴリズムとフェイルオーバー分析
  • C# は Nginx のスムーズな重み付けポーリング アルゴリズムを実装します
  • nginxの4つのスケジューリングアルゴリズムと高度な機能の詳細な分析
  • Brotli圧縮アルゴリズムを有効にするNginxの実装プロセスの詳細な説明

<<:  CentOS に Redis と MySQL をインストールする

>>:  WeChatアプレットがジグソーパズルゲームを実装

推薦する

nginx を介して方向プロキシを実装するプロセスの図

この記事は主に、nginx を介して方向プロキシを実装するプロセスを紹介します。この記事のサンプル ...

ウェブサイトのコンテンツの100~1%はナビゲーションである

ウェブサイトでは、コンテンツの(100-1)%がナビゲーションです1. ジェシー・ジェームズ・ギャレ...

CSS を使用して要素のスクロールバーを非表示にするサンプルコード

どの要素でもスクロールできるようにしながら、スクロールバーを非表示にするにはどうすればよいでしょうか...

MySQL 5.7.27 winx64 のインストールと設定方法のグラフィックチュートリアル

この記事では、MySQL 5.7.27 winx64のインストールと設定方法を参考までに紹介します。...

vue3 再帰コンポーネントカプセル化の全プロセス記録

目次序文1. 再帰コンポーネント2. 右クリックメニューコンポーネント要約する序文今日、プロジェクト...

美しいHTMLコードの書き方

美しい HTML コードの外観 美しい HTML コードの書き方。外国人が書いた記事: 美しい HT...

ウェブページのグリッドデザインを考える

<br />元のアドレス: http://andymao.com/andy/post/8...

JS は複数のタブを切り替えるカルーセルを実装します

カルーセルアニメーションは、ページの外観とインタラクティブなパフォーマンスを向上させることができます...

CentOS7 で docker を使用して Apollo 構成センターをデプロイする実装

Apollo オープンソース アドレス: https://github.com/ctripcorp/...

TypeScript の関数

目次1. 関数の定義1.1 JavaScript の関数1.2 TypeScriptの関数2. オプ...

ショッピングカートのスライド削除効果を実装するReactネイティブサンプルコード

基本的にすべてのeコマースプロジェクトにはショッピングカートの機能があります。これはreact-na...

WeChatアプレットでQRコードを識別するために長押しする実装プロセス

序文公式アカウントのQRコードは長押しで認識できることは皆さんご存じですが、ミニプログラムに対する制...

Docker環境を構築する簡単な方法

まず、Docker とは何かを理解しましょう。 Docker は、アプリケーションをデプロイするため...

MySQL マスタースレーブレプリケーションのいくつかのレプリケーション方法の概要

非同期レプリケーションMySQL レプリケーションは、デフォルトでは非同期です。マスター スレーブ ...

MySQLの日付と時刻の間隔計算の分析例

この記事では、例を使用して、MySQL の日付と時刻の間隔計算について説明します。ご参考までに、詳細...