0


私はジレンマを抱えています、多分あなたは私を助けることができます.

ワーク キューとして機能するテーブルがあります。レコードが挿入され、処理する必要があります。レコードが処理されると、キューから削除されます。いくつかの制限があります:

  • 任意の時点で 1 つのエンティティのみがレコードを処理できます (「エンティティ」とは、スレッド、または同じデータベースに接続する別のコンピューターを意味します)
  • エンティティはやや動的です。それらは変更される可能性があります (エンティティの数または特性のいずれか)
  • エンティティは 1 つのトランザクションでレコードを処理します
  • 処理は並行して行われる必要があります (entity1 が batch1 を選択した場合、entity2 は、entity1 が処理を完了するのを待たずに、batch2 を並行して処理できる必要があります)。
  • エンティティが処理するレコードを選択すると、これが属するレコードの「バッチ」全体が他のエンティティによって選択されてはなりません。「バッチ」と言うとき、テーブルが (論理的に) 次のように構成されていることを意味します。
    • 行 1 (バッチ 1)
    • 行 2 (バッチ 1)
    • 行 3 (バッチ 2)
    • 行 4 (バッチ 2)
    • 行 5 (バッチ 2)
    • .... 等々。

したがって、entity1 と entity2 の両方がテーブルから処理スライスを選択したいとします。entity1 が row1 を選択すると、entity2 は batch1 以外のもの (row1 と row2 以外のもの) を選択できます。

実際の処理が何であるかは問題ではないため、処理部分を抽象化しましょう。mysql データベースのみを使用して、処理の並列性を維持しながら、エンティティが互いに衝突するのを防ぐ方法を知りたいと思っています。

私の観点からは、非常に一般的な 2 つの方向性が見えます。

  1. 特定のエンティティがバッチをピッキングしたことを示す、ある種のステータス フィールドを使用します。これは将来のピッキングから除外する必要があります。このアイデアには、バッチを選択したエンティティがクラッシュした場合に、他のエンティティによる処理を再開するのが少し難しいという欠点があります。
  2. mysql ロックを使用すると、順次ではなく並列処理を確保することが困難になるという欠点があります。たとえば、entity1 に対して select... for update を実行できます。ただし、entity2 は同じ select... for update を実行できません。これは、必要なバッチを取得する前に最初のエンティティの処理が完了するまで待機するためです。

私は知りたいです:

  • コーディング作業が最小になる方向
  • ここで見逃している他の指示はありますか (エンティティはデータベースを介して以外は互いに通信できないことに注意してください)
  • この種の問題の標準パターンがあれば
  • この種の問題について議論している記事を教えていただければ幸いです。
  • この問題を解決する最も効率的な方法は何ですか。

ここで私が持っているのは、データベースは処理のために異なるエンティティ間でテーブルを分割する必要があり、それを行う最善の方法を知りたいということです。この問題に対処するのは私が初めてだとは思いません。あなたの考えを知りたいです。また、レコードはかなり単純な基準 (たとえば、batchId) によってバッチに分割できることに注意してください。

よろしく、
アンドレイ。

4

2 に答える 2

1

うーん、あなたが説明していることから、dbレコードロックがあなたが望むことをどのように行うのかわかりません。Dbロックは、「このレコードが利用できない場合は待機する」と言っており、「このレコードが利用できない場合は別のレコードを選択する」とは言っていません。

質問:バッチが処理されるとき、それは「完了」ですか?つまり、ノードAがバッチ1の処理を開始するとします。次に、ノードBが実行されますが、どのように実行しても、バッチ1が稼働中であることがわかり、バッチ2で開始されます。その後ノードAが終了します。次に、ノードCが登場します。バッチ1は現在処理されていません。ノードCはバッチ1を取得する必要がありますか?または、バッチ1が完了し、バッチ2が機能しているので、バッチ3に進む必要がありますか?バッチが実行された場合、レコードが過去にアクセスされたことを記憶しておらず、現在何が起こっているかだけを記憶しているため、dbロックは明らかに機能しません。

他の誰かがもっと賢い解決策を持っているかもしれませんが、ステータスフラグを使ってこれを行う必要があると思います。私は言うだろう:

バッチごとに1つのレコードを使用して、個別のバッチテーブルを作成します。バッチテーブルを指す外部キーをワークキューテーブルに配置します。そうすれば、データを正規化しておくことができます。

バッチテーブルで、作業中および作業中でない値を含むステータスフラグを追加します。または未処理、作業中、および処理済み。(バッチが完全に「完了」するかどうかによって異なります。)また、作業中の場合はこのバッチを処理しているエンティティを識別し、そうでない場合はnullを識別する「処理エンティティ」フィールドを作成します。(ステータスが作業中と作業中でない場合、このフィールドは作業中フラグを兼ねることができます:null =作業中ではなく、null =作業中ではありません。)

エンティティがバッチの処理を開始すると、processing-entityフィールドがエンティティIDに設定されます。終了すると、フィールドがnullにリセットされます。エンティティが処理するバッチを探しているとき、「processing_entityがnullである場所」を選択します(もちろん、他の条件とともに)。

次に、フラグを設定したままエンティティがクラッシュしていないことを確認するために、エンティティが起動するたびに、処理中であることを示すバッチレコードがあるかどうかを確認します。もしそうなら、それはクラッシュしたに違いないので、フラグをリセットし、クリーンアップを行います。

これは、エンティティのセットが固定されている場合にのみ機能します。たとえば、エンティティがサーバーである場合、またはスレッドプールからのスレッドである場合です。スレッドが任意に出入りできるスレッドである場合は、スレッドが再起動して未完了の作業が残っていることを確認できないため、機能しません。

私が使用した別の方法は、処理を開始したときを示すタイムスタンプをバッチレコードに入れることです。次に、時々実行される別のプロセスがあり、タイムスタンプをチェックして、妥当な最大時間と比較します。たとえば、プロセスに数秒かかることがわかっていて、タイムスタンプが1時間前のものが表示された場合、プロセスは停止またはハングしているため、適切にクリーンアップを実行する必要があります。これには、最大時間が何であるかを言うことができる必要があるというキャッチがあります。

于 2012-05-07T21:25:31.653 に答える
1

これに対する私の過去の解決策は、テーブルの列「batch_id」を「一意の番号」で更新し、その一意のバッチ番号を使用してテーブルから選択することでした。

したがって、あなたの場合、エンティティ 1 が表示されます。

エンティティ 2 がやって来て、固有の番号「15791579」でプロセスを繰り返し (したがって、バッチ 1 を更新できません)、バッチ 2 などを選択します。

于 2013-03-15T18:48:47.577 に答える