6

http 経由で多数のサプライヤの 1 つにメッセージを送信するシステムを再開発しています。オリジナルは perl スクリプトで、再開発でも perl を使用する可能性があります。

古いシステムでは、多数の perl スクリプトがすべて同時に実行され、各サプライヤーに 5 つずつありました。メッセージがデータベースに入れられると、ランダムなスレッド番号 (1 から 5) とサプライヤーが選択され、テーブル/行をロックする必要がなくなり、メッセージが 2 回処理されないようになりました。さらに、データベースには「Fair Queue Position」フィールドがあり、大きなメッセージの送信中に小さなメッセージの送信が遅延しないようにしていました。

1 分間に数件のメッセージしかない場合もあれば、数十万件のメッセージがダンプされる場合もあります。すべてのスクリプトを常に実行してメッセージをチェックするのはリソースの浪費のように思えるので、それを行うためのより良い方法があるかどうか、または古い方法が受け入れられるかどうかを調べようとしています。

私の考えは、現在、トラフィックの量に応じて、必要な数の子プロセスを (制限まで) 実行してフォークする 1 つのスクリプトを作成するという考えにありますが、それぞれが公平なキューイングが維持されている間、メッセージは 1 回だけ処理されます。

現在のところ、親スクリプトが DB を更新して、どの子プロセスがそれを処理する必要があるかを示していると思いますが、これは元の方法よりも効率が低下するのではないかと懸念しています。私は fork コードを書いた経験がほとんどありません (最後に行ったのは約 15 年前です)。

メッセージキューを処理する最善の方法に関するガイドへの考えやリンクは大歓迎です!

4

3 に答える 3

8

Thread::Queue などを使用できます: Perl 用のマルチプロセッシング モジュールはありますか?

古いシステムがこのように Perl で書かれていれば、そのほとんどの部分を再利用できます。

非動作例:

use strict;
use warnings;

use threads;
use Thread::Queue;

my $q = Thread::Queue->new();    # A new empty queue

# Worker thread
my @thrs = threads->create(sub {
                            while (my $item = $q->dequeue()) {
                                # Do work on $item
                            }
                         })->detach() for 1..10;#for 10 threads
my $dbh = ...
while (1){
  #get items from db
  my @items = get_items_from_db($dbh);
  # Send work to the thread
  $q->enqueue(@items);
  print "Pending items: "$q->pending()."\n";
  sleep 15;#check DB in every 15 secs
}
于 2012-10-31T17:19:07.483 に答える
6

RabbitMQ のようなメッセージ キュー サーバーを使用することをお勧めします。

1 つのプロセスが作業をキューにフィードし、複数のワーカー プロセスでキューを消費することができます。

このアプローチの利点:

  • 仕事を待っているときに労働者がブロックする(ビジーな待機はありません)
  • 必要に応じて、より多くのワーカー プロセスを手動で起動できます
  • ワーカー プロセスは特別な親プロセスの子である必要はありません
  • RabbitMQ は、作業を受け入れる準備ができているすべてのワーカーに作業を分散します
  • ワーカーが ACK を返さない場合、RabbitMQ は作業をキューに戻します。
  • データベースに作業を割り当てる必要はありません
  • すべての「エージェント」(ワーカー、プロデューサーなど)は独立したプロセスです。つまり、他のプロセスに影響を与えることなく、エージェントを強制終了または再起動できます。

数のワーカーを動的にスケールアップまたはスケールダウンするには、次のようなものを実装できます。

  1. 労働者が一定時間働かないと自動的に死亡するようにする
  2. 別のプロセスにキューの長さを監視させ、キューが大きくなりすぎた場合はより多くのワーカーを生成します
于 2012-10-31T16:28:49.243 に答える
1

専用のジョブ サーバーにはbeanstalkdを使用し、Perl スクリプトではBeanstalk::Clientを使用してジョブをキューに追加および削除することをお勧めします。

RabbitMQ と比較して、beanstalkd のインストールとセットアップが簡単であることがわかるはずです。また、使用可能なワーカー間でジョブを分散し、失敗したジョブを埋めて後で再試行できるようにし、ジョブを後で実行するようにスケジュールし、その他多くの基本的な機能も処理します。ワーカーの場合、フォークやスレッドについて心配する必要はありません。利用可能なサーバーの数だけ、必要な数のワーカーを起動するだけです。

独自の db-backed ソリューションを展開するよりも、RabbitMQ または Beanstalk の方が優れています。これらのプロジェクトは、キューイングに必要な詳細の多くをすでに解決しており、必要な機能をまだ実現していない可能性があります。また、新しいジョブのポーリングをより効率的に処理する必要があります。これは、スリープしてデータベースから選択して、他にやるべき作業があるかどうかを確認するよりも効率的です。

于 2012-10-31T21:16:19.977 に答える