10

次のユースケースがあります: 複数のクライアントが共有 Redis リストにプッシュします。別のワーカー プロセスがこのリストを排出する必要があります (プロセスと削除)。確認のために待機/マルチ実行が用意されており、これはスムーズに進みます。

パフォーマンス上の理由から、「ドレイン」プロセスをすぐに呼び出したくはありませんが、最初のクライアントが (その後空の) リストにプッシュした瞬間から x ミリ秒後に開始します。

これは分散アンダースコア/ロダッシュデバウンス関数に似ており、最初のアイテムが入った瞬間にタイマーが実行を開始します (つまり、「末尾」ではなく「先頭」)。

フォールトトレラントな方法でこれを確実に行うための最良の方法を探しています。

現在、私は次の方法に傾いています:

  1. andメソッドでRedis Setを使用します。これにより、次のことが可能になります。 NXpx
    • 値 (ミューテックス) を専用のキースペースに設定する (まだ存在しない場合)。これがnx引数の使用目的です
    • x ミリ秒後にキーの有効期限が切れます。これがpx引数の使用目的です
  2. このコマンドは1、値を設定できた場合、つまり以前に値が存在しなかった場合に戻ります。それ以外の場合は返し0ます。A1は、現在のクライアントが、Redis リストが排出されてからプロセスを実行した最初のクライアントであることを意味します。したがって、
  3. このクライアントは、x ミリ秒で実行されるようにスケジュールされた分散キューにジョブを配置します。
  4. x ミリ秒後、ジョブを受け取るワーカーは、リストを排出するプロセスを開始します。

これは紙の上では機能しますが、少し複雑に感じます。これを分散フォールトトレラントな方法で機能させる他の方法はありますか?

ところで: Redis と分散キューは既に配置されているため、この問題でそれを使用することが余分な負担になるとは考えていません。

4

1 に答える 1

7

申し訳ありませんが、通常の応答には、大量のテキスト/理論が必要です。あなたの良い質問は、あなたがすでに良い答えを書いているからです:)

まず、用語を定義する必要があります。アンダースコア/ロダッシュに関する「デバウンス」は、David Corbacho の記事の説明で学習する必要があります。

Debounce : 「複数のイベントを 1 つにまとめる」と考えてください。あなたが家に帰り、エレベーターに乗り込み、ドアが閉まっていると想像してみてください...そして突然、あなたの隣人がホールに現れ、エレベーターに飛び乗ろうとします。丁寧に!そして彼のためにドアを開けてください:あなたはエレベーターの出発をデバウンスしています. 同じ状況が第三者と再び発生する可能性があることを考慮してください...おそらく出発が数分遅れます。

スロットル: バルブと考えてください。実行の流れを調整します。特定の時間内に関数を呼び出すことができる最大回数を決定できます。エレベーターの例えで言えば、10 秒間人を入れるほど丁寧ですが、その遅延が過ぎたら、行かなければなりません。

debounce最初の要素がリストにプッシュされるので、あなたは尋ねています:

そのため、エレベーターとの類推によって。エレベーターが最初の人に来てから10分後にエレベーターが上がるはずです. エレベーターに何人が詰め込まれたかは関係ありません。

分散フォールト トレラント システムの場合、これは一連の要件と見なす必要があります。

  1. 新しいリストの処理は、最初の要素の挿入 (つまり、リストの作成) 後、X 時間以内に開始する必要があります。
  2. ワーカーのクラッシュによって何も壊れてはなりません。
  3. デッドロックフリー。
  4. 最初の要件は、ワーカーの数 (1 か N かに関係なく) を満たす必要があります。

つまり、(分散方法で)知っておく必要があります-ワーカーのグループを待つ必要があるか、リスト処理を開始できます。「分散」と「フォールトトレラント」というフレーズを発するとすぐに。これらの概念は常に友達とつながります。

  1. 原子性 (例: ブロッキングによる)
  2. 予約

実際には

実際には、システムをもう少し複雑にする必要があるのではないかと心配しています (おそらく、書いていないだけで、すでに持っているかもしれません)。

あなたの方法:

  1. SET NX PX を介したミューテックスによる悲観的ロック。NX一度に 1 つのプロセスだけが作業を行うこと (原子性) が保証されます。は、このPXプロセスで何かが発生した場合に、Redis によってロックが解放されることを保証します (デッド ロックに関するフォールト トレラントの一部)。
  2. すべてのワーカーは (リスト キーごとに) 1 つのミューテックスをキャッチしようとするため、1 つだけが満足して、X 時間後にリストを処理します。このプロセスにより、mutex の TTL を更新できます (当初の予定よりも時間が必要な場合)。プロセスがクラッシュした場合、ミューテックスは TTL 後にロック解除され、他のワーカーによって取得されます。

私のおすすめ

RPOPLPUSHを中心に構築された Redisのフォールト トレラントな信頼できるキュー処理:

  • 処理から特別なリストへの RPOPLPUSH アイテム (リストごとのワーカーごと)。
  • 処理項目
  • 特別なリストからアイテムを削除

要件 したがって、ワーカーがクラッシュした場合、特別なリストからメイン リストに壊れたメッセージをいつでも返すことができます。また、Redis は RPOPLPUSH/RPOP の原子性を保証します。つまり、しばらく待つのは問題のある作業員グループだけです。

そして、2つのオプション。最初 - 多くのクライアントと少ないワーカーがワーカー側でロックを使用している場合。そのため、ワーカーでミューテックスをロックしてみてください。成功した場合は、処理を開始してください。

およびその逆。LPUSH/RPUSH を実行するたびに SET NX PX を使用します (多くのワーカーといくつかのプッシュ クライアントがある場合に、「ポップする前に N 時間待機する」ソリューションを使用するため)。したがって、プッシュは次のとおりです。

SET myListLock 1 PX 10000 NX 
LPUSH myList value

そして、各ワーカーは myListLock が存在するかどうかを確認するだけで、処理ミューテックスを設定してドレインを開始する前に、少なくともキー TTL を待機する必要があります。

于 2015-12-24T14:20:19.410 に答える