web-dev-qa-db-ja.com

ZeroMQ / ZMQプッシュ/プルパターンの有用性

ZeroMQPush/Pull(彼らはPipelineと呼んでいます)ソケットタイプを試してみると、このパターンの有用性を理解するのに苦労しています。 「ロードバランサー」として請求されます。

単一のサーバーが多数のワーカーにタスクを送信すると、プッシュ/プルはすべてのクライアント間でタスクを均等に配布します。 3クライアントと30タスク、各クライアントは10タスクを取得します。client1はタスク1、4、7、... client2、2、5、...などを取得します。けっこうだ。文字通り。

ただし、実際には、タスクの複雑さやクライアントの計算リソース(または可用性)が不均一に混在していることが多く、このパターンはひどく壊れます。すべてのタスクは事前にスケジュールされているようで、サーバーはクライアントの進捗状況や、利用可能かどうかを把握していません。 client1がダウンした場合、残りのタスクは他のクライアントに送信されず、client1のキューに残ります。 client1がダウンしたままの場合、それらのタスクは処理されません。逆に、クライアントのタスク処理が速い場合、他のクライアントに対してスケジュールされたままであるため、それ以上のタスクを取得せず、アイドル状態のままになります。

REQ/REPを使用することは、可能な解決策の1つです。タスクは利用可能なリソースにのみ与えられます。

だから私は何かが欠けていますか? Push/Pullはどのように効果的に使用されますか?このソケットタイプでクライアント、タスクなどの非対称性を処理する方法はありますか?

ありがとう!

簡単なPythonの例:

# server

import zmq
import time

context = zmq.Context()
socket = context.socket(zmq.Push)
#socket = context.socket(zmq.REP)   # uncomment for Req/Rep

socket.bind("tcp://127.0.0.1:5555")

i = 0
time.sleep(1)   # naive wait for clients to arrive

while True:
  #msg = socket.recv()    # uncomment for Req/Rep
  socket.send(chr(i))
  i += 1 
  if i == 100:
    break

time.sleep(10)   # naive wait for tasks to drain

# client

import zmq
import time
import sys

context = zmq.Context()

socket = context.socket(zmq.PULL)
#socket = context.socket(zmq.REQ)    # uncomment for Req/Rep

socket.connect("tcp://127.0.0.1:5555")

delay = float(sys.argv[1])

while True:
  #socket.send('')     # uncomment for Req/Rep
  message = socket.recv()
  print "recv:", ord(message)
  time.sleep(delay)

コマンドラインで遅延パラメーター(1、1、0.1)を使用して3つのクライアントを起動し、次にサーバーを起動して、すべてのタスクが均等に分散される様子を確認します。次に、クライアントの1つを強制終了して、残りのタスクが処理されないことを確認します。

示されている行のコメントを外して、Req/Repタイプのソケットに切り替え、より効果的なロードバランサーを監視します。

41
CNK

これはロードバランサーではありません。これは誤った説明であり、しばらくの間0MQドキュメントにとどまりました。負荷分散を行うには、可用性についてワーカーからいくつかの情報を取得する必要があります。プッシュは、ディーラーと同様、ラウンドロビンディストリビューターです。素早い速度とシンプルさで役立ちます。チャタリングは必要ありません。パイプラインにタスクを送り込むだけで、ネットワークが処理できる限り迅速に、利用可能なすべてのワーカーにスプレーされます。

このパターンは、非常に多数の小さなタスクを実行している場合や、従業員が頻繁に出入りする場合に役立ちます。このパターンは、新しいタスクを使用可能なワーカーにのみ送信する単一のキューが必要なため、完了に時間がかかる大規模なタスクには適していません。また、クライアントが多くのタスクを送信してからワーカーが接続すると、最初のワーカーが1,000個程度のメッセージを取得し、他のワーカーはまだ接続に忙しいというアンチパターンの影響を受けます。

いくつかの方法で、独自の上位ルーティングを作成できます。ガイドのLRUパターンを見てください。この中で、ワーカーはブローカーに明示的に「準備完了」と伝えます。また、クレジットベースのフロー制御を行うこともできます。これは、実際の負荷分散状況で私がすることです。これは、LRUパターンの一般化です。 http://hintjens.com/blog:15 を参照してください

60
Pieter Hintjens