複数のdelayed_jobを実行するレール - テーブルをロックします
-
01-10-2019 - |
質問
おい。バックグラウンド処理にはdelayed_jobを使用します。私は8つのCPUサーバー、MySQLを持っています、そして私は7つのdelaed_jobプロセスを開始します
RAILS_ENV=production script/delayed_job -n 7 start
Q1:2つ以上のdelayed_jobプロセスが同じプロセスの処理を開始する可能性があるのではないかと思います(データベースDelayed_jobsで同じ記録列)。 Delayed_jobプラグインのコードを確認しましたが、ロックディレクティブをあるべき方法で見つけることができません(ロックテーブルまたは選択...更新用)。
lock_by列の更新を実行する前に、各プロセスはデータベーステーブルをロックする必要があると思います。 Locked_byフィールドを更新するだけでレコードをロックします(delayed_jobs set locked_by ...)。それは本当に十分ですか?ロックは必要ありませんか?なんで?更新は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: 7つのdelayed_jobsは8cpuサーバーにとって良い数字ですか?なぜはい/そうではありません。
thx 10x!
解決
あなたの質問に対する答えは、「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番目の質問に:それは依存します。 8 CPUサーバーで。この仕事に専念しているのは、8人の労働者が良い出発点であるため、労働者は単一のスレッドであるため、すべてのコアに対して1つを実行する必要があります。セットアップに応じて、多かれ少なかれ労働者の方が優れています。それはあなたの仕事に大きく依存します。 mutipleコアの仕事の利点を取りますか?それとも、ほとんどの場合、外部リソースを待っていますか?さまざまな設定を実験し、関連するすべてのリソースをご覧ください。