0

今日は言葉が難しいので、あなたが私を助けてくれるように、これをはっきりと書き留めようとしています. いくつかのやり過ぎが ymmv の下に存在します。

table1 から約 48m のレコードを table2 に移行しています。どちらも InnoDB です。user_id を介して table1 からカリングされるレコードを特定できます (「user_id=3 によって入力されたレコードは、table1 から table2 に移動します」)。複数のコンシューマーを介してジョブを実行できるように、AMQP サーバーを介して移行プロセスを実行できるように拡張する必要がある、単一インスタンスのセットアップでコードを動作させるための最初のパスがあります (つまり、コンシューマーを実行しています)。コンシューマーがすべて同時に実行されているラウンド ロビン設定で、同時に同じジョブの 2 つのインスタンスで並行して /jobs を実行します。ジョブをすばやくノックアウトするために 10 人程度の消費者にスケールアップできるようにしたいと考えています。それ以外の場合は、単一のインスタンスがジョブを完了するのに約 15 日かかります。

このコードは、実行ごとにクエリ条件に一致する最も古い 2000 レコードを選択します。問題は、コードを実行してレコードを選択する 2 つのインスタンスがある場合、instance1 が ID の 1-2000 を取得し、ほぼ同時に開始された instance2 も 1-2000 を取得することです。 table1 から 0-2000 の移動が完了し、それらの ID は table1 に引き続き存在します。

わかりました、問題ありません。除外するレコードを記録するコントロール テーブルを追加します。これにより、instance1 が「レコード 1 ~ 2000 を持っています」と言うことができるため、instance2 が起動してクエリに行くと、「どの ID を除外する必要がありますか?」と表示されます。インスタンス 2 が ID の 2001 から 4001 を取得し、コントロール テーブルを更新して、インスタンス 2 の ID が 2001 から 4001 であることを知らせるように、「次の 2000 レコードをくれ」の一部としてコントロール テーブルを照会することに基づいています。 instance3 の場合、次の 2k レコードを要求する起動時に、ID の 1 から 4001 を省略する必要があることがわかります。

インスタンスがロックされた制御テーブルにエントリを書き込むとき、それは「[first_id_found] and [last_id_found]」または「5671 and 7671」として書き込まれます。テキストが sql BETWEEN 句に入るので、' and ' を使用します。

id が 1565 から 1567 の間でなく、id が 1568 から 1570 の間でなく、created_by=3 である table1 から ID を選択します。id asc limit 0、2000 で並べ替えます。

問題:

ロックが必要なテーブルはコントロール テーブルだけです。そのため、インスタンスがコントロール テーブルにアクセスできるようになると、除外するレコードを見つけることも、独自の除外レコードを書き込むこともできるようになります。ロックが解放されると、テーブルにアクセスする次のインスタンスは、control最新のデータを見つけます。

ただし、クエリが終了するまでロックをそのままにしておく必要がありますtable1。結果セットの最初と最後の ID を特定できるので、これらをcontrolテーブルに追加して、次に起動するインスタンスが何を除外するかを知ることができます。

制御ファイルはどちらtable1でもないことに注意してください。また、どちらもロックする必要がないためortable2を指定していないことに注意してください。また、他のプロセスがテーブルにアクセスしており、妨げたくないため、 or も必要ありません。他の実行中のプロセスからまたはへのアクセス。table1table2table1table2

したがって、疑似コードは次のようになります。

// lock control table
// find all control table records (multiple workers = possible multiple records) indicating which id ranges to omit
// build "table1.id not between x and y" strings for each control record found
// query table1 with "not between" into array via PDO::fetchAll() to get the ids of N records that no other instance is working with  <<-- the problem
// find first and last ids in result set
// add control table record to `params` field with value = "[first_id_found] and [last_id_found]"
// unlock control table
// process array

table1 にクエリを実行すると、レコードが返されません。不正解です。4,800 万件のレコードがあります。errorInfo() をチェックすると、次のエラー状態が表示されます。

「テーブル 'table1' は LOCK TABLES でロックされていませんでした」

ロックしたくないのですtable1が、LOCK TABLES が配置された後control、UNLO​​CK TABLES の前にクエリが実行されたため、使用するすべてのテーブルが必要なある種のトランザクション モードになっているようです。割り当てられたロック レベル。WTF、ドキュメントにはこれについて何も表示されません。

table1ロック範囲内にないのに、なぜこの問題が発生するのですか? 私はこの戦略と結婚していません。同じ機能をもたらす別のパターンがあれば、私はゲームだと思います。回避策?提案?

4

0 に答える 0