web-dev-qa-db-ja.com

信頼性のあるRedis Pub / Sub

RabbitMQの代わりにRedis Pub/Subを使用することを検討してきました。

私の理解では、Redisのpub/subは各サブスクライバーへの永続的な接続を保持しており、接続が終了すると、その後のメッセージはすべて失われ、フロアにドロップされます。

考えられる解決策の1つは、リスト(およびブロック待機)を使用して、通知メカニズムとしてすべてのメッセージとpub/subを格納することです。私はこれでほとんどの方法が得られると思いますが、私はまだ失敗のケースについていくつかの懸念を持っています。

  1. サブスクライバーが死亡し、オンラインに戻ったときにどうなりますか?保留中のすべてのメッセージをどのように処理する必要がありますか?
  2. 不正なメッセージがシステムを介して届いた場合、それらの例外をどのように処理しますか? DeadLetter Queue?
  3. 再試行ポリシーを実装するための標準的な方法はありますか?
46
Edward Chan

サブスクライバー(コンシューマー)が死亡すると、クライアントが戻るまで、リストは増え続けます。特定の制限に達すると、プロデューサーはリストを(どちら側からでも)トリミングできますが、これはアプリケーションレベルで処理する必要があるものです。各メッセージ内にタイムスタンプを含めると、メッセージの経過時間に適用したいアプリケーションロジックがあると仮定して、コンシューマーはメッセージの経過時間に基づいて行動できます。

Redisへの接続は通常、TCPとその整合性が保証されているため、システムに不正なメッセージがどのように入力されるかはわかりません。しかし、これが発生した場合、おそらくメッセージエンコーディングのバグが原因です。プロデューサーレイヤーでは、コンシューマーの例外メッセージを受け取ったプロデューサーごとにキューを保持することにより、エラーを処理するための一般的なメカニズムを提供できます。

再試行ポリシーは、アプリケーションのニーズに大きく依存します。メッセージが受信および処理されたことを100%保証する必要がある場合は、Redisトランザクション(MULTI/EXEC)を使用してコンシューマーによって行われた作業をラップすることを検討する必要があります。これにより、クライアントがメッセージを削除しないようにすることができます。それはその仕事を完了しました。明示的な確認応答が必要な場合は、プロデューサプロセス専用のキューで明示的なACKメッセージを使用できます。

アプリケーションのニーズについて詳しく知らなければ、賢明な選択方法を知ることは困難です。一般に、メッセージに完全なACID保護が必要な場合は、おそらくredisトランザクションも使用する必要があります。メッセージがタイムリーな場合にのみ意味がある場合、トランザクションは必要ない場合があります。ドロップされたメッセージを許容できないように思えるので、リストを使用するアプローチは優れています。メッセージに優先度キューを実装する必要がある場合は、並べ替えられたセット(Zコマンド)を使用して、ポーリングコンシューマとともに、優先度をスコア値として使用してメッセージを保存できます。

35
Will Pierce

私がしたことは、タイムスタンプをスコアとして使用し、データのキーをメンバー値として使用して、ソートされたセットを使用することです。最後のアイテムのスコアを使用して、次のいくつかのアイテムを取得し、キーを取得します。作業が完了したら、zremとdelの両方をMULTI/EXECトランザクションでラップします。

基本的にエドワードが言ったことですが、私のメッセージはかなり大きくなる可能性があるため、ソートされたセットにキーを保存するというひねりが加えられています。

お役に立てれば!

3

サブスクライバーが死んだときにメッセージが失われないpub/subシステムが必要な場合は、Redis Pub/subの代わりに Redis Streams の使用を検討してください。

Redis Streamsには独自のアーキテクチャとRedis Pub/subの長所/短所があります。 Redis Streamsを使用すると、サブスクライバーは次のコマンドを発行できます。

最後に受け取ったメッセージはXでしたが、次のメッセージを教えてください。新しいメッセージがない場合は、メッセージが到着するまで待ちます。

上にリンクされているAntirezの記事は、詳細情報を含むRedisストリームの良い紹介です。

警告:この機能は、現在のところ不安定版(ベータ版)のRedisにのみ存在します。

0