いくつかの単純な負荷分散アルゴリズムとそのJavaコード実装

いくつかの単純な負荷分散アルゴリズムとそのJavaコード実装

1. 負荷分散とは何ですか?

負荷分散(英語名は Load Balance)とは、複数のサーバーを対称的に構成したサーバーセットを指します。各サーバーは同等のステータスを持ち、他のサーバーの支援なしに独立して外部にサービスを提供できます。何らかの負荷分散技術により、外部から送信されたリクエストは対称構造のサーバーに均等に分散され、リクエストを受信したサーバーはクライアントのリクエストに独立して応答します。ロード バランシングにより、クライアント要求をサーバー アレイに均等に分散できるため、重要なデータへの高速アクセスが可能になり、大量の同時アクセス サービスの問題が解決されます。このクラスター テクノロジにより、最小限の投資でメインフレームに近いパフォーマンスを実現できます。

[[262208]]

負荷分散はソフトウェア負荷分散とハードウェア負荷分散に分かれます。前者はAlibabaの張文松博士が開発したLVSに代表され、後者はF5などのバランシングサーバーです。もちろん、これは言及しただけで、本質ではありません。

この記事では、「外部から送られてきたリクエストを対称構造で均等にサーバーに分配する」ためのさまざまなアルゴリズムについて説明し、各アルゴリズムの具体的な実装を Java コードで示します。では、本題に入りましょう。本題に入る前に、IP リストをシミュレートするクラスを記述してみましょう。

  1. パブリッククラス IpMap
  2. {
  3. // ルーティングする IP のリスト。キーはIP を表し、値は IP の重みを表します。
  4. 公共 静的ハッシュマップ<文字列、整数> serverWeightMap =
  5. 新しい HashMap<String, Integer >();
  6.  
  7. 静的 
  8. {
  9. serverWeightMap.put( "192.168.1.100" , 1);
  10. serverWeightMap.put( "192.168.1.101" , 1);
  11. // 重みは4
  12. serverWeightMap.put( "192.168.1.102" , 4);
  13. serverWeightMap.put( "192.168.1.103" , 1);
  14. serverWeightMap.put( "192.168.1.104" , 1);
  15. // 重みは3
  16. serverWeightMap.put( "192.168.1.105" , 3);
  17. serverWeightMap.put( "192.168.1.106" , 1);
  18. // 重みは2
  19. serverWeightMap.put( "192.168.1.107" , 2);
  20. serverWeightMap.put( "192.168.1.108" , 1);
  21. serverWeightMap.put( "192.168.1.109" , 1);
  22. serverWeightMap.put( "192.168.1.110" , 1);
  23. }
  24. }

02. ラウンドロビン

ポーリング方式はラウンドロビン方式で、そのコード実装はおおよそ次のようになります。

  1. パブリッククラス RoundRobin
  2. {
  3. プライベートスタティック 整数pos = 0;
  4.  
  5. 公共 静的文字列 getServer()
  6. {
  7. // サーバーの起動と停止による同時実行の問題を回避するためにマップを再構築します
  8. マップ<文字列、整数> serverMap =
  9. 新しい HashMap<String, Integer >();
  10. serverMap.putAll(IpMap.serverWeightMap);
  11.  
  12. // IPアドレスリストを取得
  13. <文字列>を設定します。keySet = serverMap.keySet();
  14. ArrayList<String> keyList = 新しいArrayList<String>();
  15. キーリストにすべてを追加します(キーセット)。
  16.  
  17. 文字列サーバー = null ;
  18. 同期(正)
  19. {
  20. (位置 >キーセットのサイズ())の場合
  21. 位置 = 0;
  22. サーバー = keyList.get(pos);
  23. 位置++;
  24. }
  25.  
  26. サーバーを返す
  27. }
  28. }

serverWeightMap のアドレス リストは動的であるため、マシンはいつでもオンラインになったり、オフラインになったり、クラッシュしたりする可能性があります。したがって、同時実行の問題を回避するために、メソッド内にローカル変数 serverMap が作成されます。serverMap の内容は、複数のスレッドによって変更されないように、スレッドにローカルにコピーされるようになりました。これにより、新たな問題が発生する可能性があります。レプリケーション後、serverWeightMap への変更は serverMap に反映されません。つまり、このサーバー選択ラウンドでは、負荷分散アルゴリズムは新しいサーバーまたはオフライン サーバーを認識しません。新しいアドレスを追加しても問題ありません。サーバーがオフラインまたはクラッシュしている場合は、存在しないアドレスにアクセスする可能性があります。したがって、サービス呼び出し元は、サーバーの選択と呼び出しの再開など、対応するフォールト トレラント処理を備えている必要があります。

現在のポーリング位置変数 pos については、サーバーの選択順序を保証するために、操作中にロックして、同時に 1 つのスレッドだけが pos の値を変更できるようにする必要があります。そうしないと、pos 変数が同時に変更された場合、サーバーの選択順序が保証されず、keyList 配列が境界を越える可能性もあります。

ラウンドロビン方式の利点は、リクエスト転送の絶対的なバランスを実現しようとすることです。

ポーリング方式の欠点は、リクエスト転送の絶対的なバランスを実現するために、かなりの代償を払わなければならないことです。POS 変数の変更の相互排他性を保証するために、重い悲観的ロック同期を導入する必要があり、これにより、このポーリング コードの同時スループットが大幅に低下します。

03. ランダム法

システムのランダム機能により、バックエンド サーバー リストのサイズに基づいて、バックエンド サーバーの 1 つがアクセス用にランダムに選択されます。確率統計の理論から、呼び出し回数が増えるにつれて、実際の効果は各バックエンド サーバーにトラフィックを均等に分散することにどんどん近づいていること、つまりポーリングの効果であることがわかります。

ランダム メソッドのコード実装は次のとおりです。

  1. パブリッククラス Random
  2. {
  3. 公共 静的文字列 getServer()
  4. {
  5. // サーバーの起動と停止による同時実行の問題を回避するためにマップを再構築します
  6. マップ<文字列、整数> serverMap =
  7. 新しい HashMap<String, Integer >();
  8. serverMap.putAll(IpMap.serverWeightMap);
  9.  
  10. // IPアドレスリストを取得
  11. <文字列>を設定します。keySet = serverMap.keySet();
  12. ArrayList<String> keyList = 新しいArrayList<String>();
  13. キーリストにすべてを追加します(キーセット)。
  14.  
  15. java.util.Random ランダム = new java.util.Random();
  16. int randomPos = random.nextInt(keyList.size ( ));
  17.  
  18. keyList.get(randomPos);を返します
  19. }
  20. }

全体的なコードのアイデアはポーリング メソッドと一致しています。まず serverMap を再構築し、次にサーバー リストを取得します。サーバーを選択する際は、Random の nextInt メソッドを使用して 0 ~ keyList.size() の範囲でランダムな値を取得し、サーバーリストからサーバーアドレスをランダムに取得して返します。確率統計の理論に基づくと、スループットが大きいほど、ランダム アルゴリズムの効果がポーリング アルゴリズムの効果に近くなります。

04. 送信元アドレスハッシュ方式

ソースアドレスハッシュの考え方は、クライアントがアクセスした IP アドレス値を取得し、ハッシュ関数を通じて値を計算し、この値を使用してサーバーリストのサイズに対してモジュロ演算を実行することです。結果は、アクセスされるサーバーのシリアル番号です。送信元アドレス ハッシュ アルゴリズムのコード実装は次のとおりです。

  1. パブリッククラスHash
  2. {
  3. 公共 静的文字列 getServer()
  4. {
  5. // サーバーの起動と停止による同時実行の問題を回避するためにマップを再構築します
  6. マップ<文字列、整数> serverMap =
  7. 新しい HashMap<String, Integer >();
  8. serverMap.putAll(IpMap.serverWeightMap);
  9.  
  10. // IPアドレスリストを取得
  11. <文字列>を設定します。keySet = serverMap.keySet();
  12. ArrayList<String> keyList = 新しいArrayList<String>();
  13. キーリストにすべてを追加します(キーセット)。
  14.  
  15. // Webアプリケーションでは、HttpServletのgetRemoteIpメソッドを通じて取得できます
  16. 文字列 remoteIp = "127.0.0.1" ;
  17. intハッシュコード = remoteIp.hashCode();
  18. int serverListSize = keyList.size ( );
  19. int serverPos = ハッシュコード % serverListSize;
  20.  
  21. keyList.get(serverPos);を返します
  22. }
  23. }

最初の2つの部分はポーリング方式とランダム方式と同じなので、詳細は説明しません。違いはルーティングの選択部分にあります。クライアントの IP、つまり remoteIp を通じて、そのハッシュ値を取得し、サーバー リストのサイズを法として計算します。その結果が、サーバー リスト内の選択されたサーバーのインデックス値になります。

ソース アドレス ハッシュ方式の利点は、バックエンド サーバー リストが変更されるまで、同じクライアント IP アドレスが同じバックエンド サーバーにハッシュされることが保証されることです。この機能に基づいて、サービス コンシューマーとサービス プロバイダーの間でステートフル セッションを確立できます。

ソース アドレス ハッシュ アルゴリズムの欠点は、クラスター内のサーバーが非常に安定していて、基本的にオンラインまたはオフラインにならない限り、サーバーがオンラインまたはオフラインになると、ソース アドレス ハッシュ アルゴリズムによってルーティングされたサーバーが、サーバーがオンラインまたはオフラインになる前にルーティングされたサーバーである確率が非常に低くなることです。セッションの場合はセッションが取得できず、キャッシュの場合は「雪崩」が発生する可能性があります。

05. 加重ラウンドロビン

サーバーによってマシン構成や現在のシステム負荷が異なる場合があり、ストレス耐性も異なります。構成が高く負荷が低いマシンには、より多くのリクエストを処理できるように高い重みが割り当てられ、構成が低く負荷が高いマシンには、システム負荷を軽減するために低い重みが割り当てられます。加重ラウンドロビン方式はこの問題を適切に処理し、重みに応じてリクエストの順序をバックエンドに分散します。加重ラウンドロビン方式のコード実装は次のとおりです。

  1. パブリッククラス WeightRoundRobin
  2. {
  3. プライベートスタティック 整数pos;
  4.  
  5. 公共 静的文字列 getServer()
  6. {
  7. // サーバーの起動と停止による同時実行の問題を回避するためにマップを再構築します
  8. マップ<文字列、整数> serverMap =
  9. 新しい HashMap<String, Integer >();
  10. serverMap.putAll(IpMap.serverWeightMap);
  11.  
  12. // IPアドレスリストを取得
  13. <文字列>を設定します。keySet = serverMap.keySet();
  14. イテレータ<String> iterator = keySet.iterator();
  15.  
  16. リスト<文字列> serverList = 新しい ArrayList<文字列>();
  17. (イテレータ.hasNext()) の間
  18. {
  19. 文字列サーバー = iterator.next ();
  20. int重み = serverMap.get(server);
  21. ( int i = 0; i < 重み; i++)の場合
  22. serverList.add (サーバー);
  23. }
  24.  
  25. 文字列サーバー = null ;
  26. 同期(正)
  27. {
  28. if (pos > serverList.size ())
  29. 位置 = 0;
  30. サーバー = serverList.get(pos);
  31. 位置++;
  32. }
  33.  
  34. サーバーを返す
  35. }
  36. }

ポーリング方式と似ていますが、サーバー アドレスを取得する前に重み計算コードが追加されます。重みに応じて、アドレスはサーバー アドレス リストに繰り返し追加されます。重みが大きいほど、サーバーが各ラウンドで受信するリクエストが多くなります。

06. 加重ランダム法

加重ラウンドロビン方式と同様に、加重ランダム方式でも、バックエンド サーバーのさまざまな構成と負荷条件に基づいて異なる重みが構成されます。違いは、順序ではなく重みに基づいてサーバーをランダムに選択することです。重み付けランダム法のコード実装は次のとおりです。

  1. パブリッククラス WeightRandom
  2. {
  3. 公共 静的文字列 getServer()
  4. {
  5. // サーバーの起動と停止による同時実行の問題を回避するためにマップを再構築します
  6. マップ<文字列、整数> serverMap =
  7. 新しい HashMap<String, Integer >();
  8. serverMap.putAll(IpMap.serverWeightMap);
  9.  
  10. // IPアドレスリストを取得
  11. <文字列>を設定します。keySet = serverMap.keySet();
  12. イテレータ<String> iterator = keySet.iterator();
  13.  
  14. リスト<文字列> serverList = 新しい ArrayList<文字列>();
  15. (イテレータ.hasNext()) の間
  16. {
  17. 文字列サーバー = iterator.next ();
  18. int重み = serverMap.get(server);
  19. ( int i = 0; i < 重み; i++)の場合
  20. serverList.add (サーバー);
  21. }
  22.  
  23. java.util.Random ランダム = new java.util.Random();
  24. int randomPos = random.nextInt(serverList.size ( ));
  25.  
  26. serverList.get(randomPos);を返します
  27. }
  28. }

このコードはランダム方式と重み付けポーリング方式を組み合わせたものと同じです。わかりやすいので説明は省きます。

07. 最小接続法

これまでの方法では、サービス コンシューマーのリクエスト時間のバランスの取れた分散を実現するために最善を尽くしてきました。もちろん、これは正しいです。複数のバックエンド サーバーのワークロードを均等に分散し、サーバーの使用率を最大化できます。しかし、これは本当にそうでしょうか。実際のところ、リクエスト時間のバランスは本当に負荷のバランスを表すことができるのでしょうか。これは考える価値のある質問です。

上記の問題を別の観点から見ると、リクエストの開始者ではなく、バックエンド サーバーの観点からシステム負荷を観察することを意味します。最小接続数方式はこのカテゴリに属します。

最小接続数アルゴリズムは、より柔軟でインテリジェントです。バックエンド サーバーの構成が異なるため、リクエストの処理速度は速くなったり遅くなったりする場合があります。バックエンド サーバーの現在の接続状態に基づいて、現在のリクエストを処理するために接続バックログが最も少ないサーバーを動的に選択し、バックエンド サーバーの利用効率を最大化し、各マシンに負荷を合理的に分散します。最小接続数は、サーバー接続数の集計と認識を伴うため、設計と実装がかなり面倒です。そのため、ここでは実装については説明しません。

<<:  人工知能がスマート交通の発展に与える影響

>>:  快手AIハッカソンは「AIの名の下に」みんなの幸福を向上させるために終了しました

ブログ    

推薦する

2022年にテクノロジー業界を変えるAIユニコーン企業トップ10

現在、人工知能は独立に向けて動き始めています。世界中の企業はこの学際的な分野に適応し、ほぼすべてのビ...

...

...

ニューロモルフィックコンピューティングを理解する: 基本原理から実験的検証まで

人間の脳は、効率的な生体エネルギーによって計算能力を部分的にサポートし、ニューロンを基本的な発火単位...

人工知能で最も人気のあるアルゴリズムトップ10をわかりやすく解説

機械学習は業界にとって革新的で重要な分野です。機械学習プログラムに選択するアルゴリズムの種類は、達成...

...

推薦システムで学ぶべき対照的な学習方法

みなさんこんにちは。私はDiaobaiです。今日は、レコメンデーションシステムで学ぶべき対照学習法に...

プログラマーの面接でよく聞かれる質問: スケジュールされたタスク スケジューラを設計し、どのようなアルゴリズムとデータ構造を使用するか

学生時代、私は Huya の面接を受けたことがあります。今でもはっきりと覚えている面接の質問がありま...

自動運転分野における機械学習アルゴリズムの応用に関する包括的なレビュー

機械学習は、車内外のセンサーからのデータを融合して、運転者の状態を評価し、運転シナリオを分類するため...

102歳の統計学の伝説、CRラオ氏が死去。彼の人生は「統計の世紀」を経験した

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

MITとHKUは、Transformerを超える精度を持つ物理モデルに基づく視覚推論フレームワークを提案

[[437809]]動的視覚推論、特にオブジェクト間の物理的な関係についての推論は、コンピューター ...

ボストン・ダイナミクスのロボット犬の初開封ビデオ:53万ドルで何を買ったのか?

53万元の犬を箱から取り出すのはどんな感じでしょうか?ボストン・ダイナミクス初の小売ロボット「スポ...

AIのおかげで、これら5つの業界の求人需要は大幅な成長傾向を示すだろう

編集者注: 人工知能と人間の仕事は、今日多くの人が話題にしているトピックであり、議論の焦点は主に、人...

...

...