10

おい。バックグラウンド処理にはdelayed_jobを使用しています。8 つの CPU サーバー、MySQL があり、7 つのdelayed_job プロセスを開始します

RAILS_ENV=production script/delayed_job -n 7 start 

Q1: 2 つ以上のdelayed_job プロセスが同じプロセス (データベースdelayed_jobs の同じレコード行) の処理を​​開始する可能性があるかどうか疑問に思っています。delayed_job プラグインのコードを確認しましたが、あるべき方法でロック ディレクティブを見つけることができません (ロック テーブルまたは SELECT...FOR UPDATE がありません)。

各プロセスは、lock_by 列で UPDATE を実行する前にデータベース テーブルをロックする必要があると思います。locked_by フィールドを更新するだけでレコードをロックします (UPDATEdelayed_jobs SET locked_by...)。本当にそれで十分ですか?ロックは必要ありませんか?なんで?UPDATE は SELECT より優先度が高いことは知っていますが、この場合は効果がないと思います。

マルチスレッドの状況についての私の理解は次のとおりです。

Process1: Get waiting job X. [OK]
Process2: Get waiting jobs X. [OK]
Process1: Update locked_by field. [OK]
Process2: Update locked_by field. [OK]
Process1: Get waiting job X. [Already processed]
Process2: Get waiting jobs X. [Already processed]

場合によっては、より多くのジョブが同じ情報を取得して、同じプロセスの処理を開始できると思います。

Q2: 8CPU サーバーの場合、delayed_jobs の 7 は適切な数ですか? はい/いいえ。

10倍!

4

1 に答える 1

11

あなたの質問に対する答えは、「lib / delayed_job/job.rb」の168行目にあると思います。

self.class.update_all(["locked_at = ?, locked_by = ?", now, worker], ["id = ? and (locked_at is null or locked_at < ?)", id, (now - max_run_time.to_i)])

ここで、行の更新は、他のワーカーがまだジョブをロックしていない場合にのみ実行され、テーブルが更新されているかどうかがチェックされます。あなたのDBMSは単一のクエリの実行が他のクエリからの影響から分離されることを保証するので、テーブルロックまたは同様のもの(ちなみにあなたのアプリのパフォーマンスを大幅に低下させるでしょう)は必要ありません。この例では、Process2はジョブXのロックを取得できません。これは、以前にロックされていなかった場合にのみ、ジョブテーブルを更新するためです。

あなたの2番目の質問に:それは異なります。8CPUサーバー。これはこのジョブ専用です。ワーカーはシングルスレッドであるため、コアごとに1つ実行する必要があるため、8人のワーカーが出発点として適しています。設定に応じて、多かれ少なかれ労働者が優れています。それはあなたの仕事に大きく依存します。複数のコアを活用して仕事をしますか?それとも、あなたの仕事はほとんどの時間外部リソースを待っていますか?さまざまな設定を試し、関連するすべてのリソースを確認しました。

于 2010-04-25T12:03:10.597 に答える