Redisでメッセージキューを実装する方法は?


29

キューイングにRedisを使用する理由

私は、Redisがキューイングシステムを実装するための良い候補になることができるという印象を受けています。これまで、MySQLデータベースをポーリングまたはRabbitMQで使用してきました。RabbitMQには多くの問題があります。クライアントライブラリは非常に貧弱でバグが多いため、修正に開発者の時間をかけすぎないように、サーバー管理コンソールにいくつかの問題があります。少なくとも、ミリ秒で把握したり、パフォーマンスを真剣に推進したりすることはないので、システムがキューをインテリジェントにサポートするアーキテクチャを備えている限り、おそらく良好な状態にあります。

さて、それが背景です。基本的に、非常に古典的でシンプルなキューモデルがあります。仕事を生成する複数のプロデューサーと、仕事を消費する複数のコンシューマーがあり、プロデューサーとコンシューマーの両方がインテリジェントにスケーリングできる必要があります。すべてのサブスクライバーに作業を消費さPUBSUBせたくないので、ナイーブが機能しないことがわかります。1人のサブスクライバーに作業を受け取りたいだけです。最初のパスでは、インテリジェントデザインのように見えます。BRPOPLPUSH

BRPOPLPUSHを使用できますか?

基本的な設計でBRPOPLPUSHは、1つの作業キューと進行状況キューがあります。コンシューマーが作業を受け取ると、アイテムをアトミックに進行キューにプッシュし、作業を完了するとそれが完了LREMします。これにより、クライアントが死んだ場合の作業のブラックホール化が防止され、監視が非常に楽になります。たとえば、大量のタスクがあるかどうかを通知するだけでなく、消費者がタスクを実行するのに長時間かかる問題があるかどうかを確認できます。

それは保証します

  • 仕事はちょうど1人の消費者に届けられる
  • 作業は進行キューで終了するため、消費者がブラックホールに陥ることはありません

欠点

  • 私が見つけた最高のデザインはPUBSUB、Redisのキューイングに関するほとんどのブログ投稿が焦点を当てているものであるように思われるため、実際には使用していません。だから、私は明白な何かを見逃しているように感じます。PUBSUBタスクを2回消費せずに使用する唯一の方法は、作業が到着したという通知をプッシュするだけで、消費者はそれをブロックしないようにできRPOPLPUSHます。
  • 一度に複数のワークアイテムを要求することはできません。これはパフォーマンスの問題のようです。私たちの状況にとっては大きなものではありませんが、この操作は高スループットまたはこの状況のた​​めに設計されたものではないことを明確に示しています
  • 要するに、私は愚かな何かを見逃していますか?

node.jsタグも追加します。これは、私が主に扱っている言語だからです。Nodeは、シングルスレッドでノンブロッキングな性質を考えると、実装のいくつかの単純化を提供するかもしれませんが、さらに、node-redisライブラリとソリューションを使用しています。

回答:


5

Node.jsのメッセージキューにRedisを使用する場合、そのモジュールを使用してもかまわない場合は、RSMQ(ノード用のRedisシンプルメッセージキュー)を試してください。この質問が行われた時点では利用できませんでしたが、今日では実行可能なオプションです。

質問で述べたように実際にキューを実際に実装したい場合は、RSMQのソースを読むことをお勧めします。RSMQが求めるのはまさに20画面のコードであるためです。

見る:


後でそれが本当に欠陥があるか壊れているか何かを知らない限り、私はこれを受け入れます。
-djechlin

22

これまでにいくつかの困難に直面しましたが、ここで文書化したいと思います。

再接続ロジックをどのように処理しますか?

これは難しい問題であり、メッセージキューの設計と実装において特に難しい問題です。消費者がオフラインの場合、メッセージはどこかにキューイングできる必要があるため、単純なpub-subでは不十分であり、消費者はリスニング状態で再接続する必要があります。 ポップをブロックすることは、非べき等のリスニング状態であるため、維持するのが難しい状態です。リスニングはべき等の操作である必要がありますが、ブロッキングポップに関して切断を処理する場合、操作が成功した直後または操作が失敗する直前に切断が発生したかどうかを非常によく考えることができます。これは乗り越えられませんが、望ましくありません。

さらに、リスニング操作はできる限りシンプルにする必要があります。 理想的には、次のプロパティが必要です。

  • リスニングはi等です。
  • コンシューマーは常にリッスンしており、調整ロジックはリッスンロジックコードの外部で処理されます。RabbitMQは、これをカプセル化して、消費者が保持できる未確認メッセージの数を制限できるようにします。
    特に、私は貧弱なデザインで、ブロッキングポップを再入力することは以前の操作の成功を条件とし、それはもろく、一生懸命に考える必要がありました。

私は今、Redis PUBSUB + RPOPLPUSHソリューションを支持しています。これにより、作業の通知が作業の消費から切り離されるため、クリーンなリスニングソリューションを除外できます。PUBSUBは、作業の通知のみを担当します。RPOPLPUSHのアトミックな性質は、消費と、1人の消費者への作業の委任を担当します。最初は、このソリューションはブロッキングポップに比べて不必要に複雑に思えましたが、今では複雑さはまったく不要ではないことがわかりました。難しい問題を解決していました。

ただし、この解決策はそれほど簡単ではありません。

  • 消費者は再接続の作業も確認する必要があります。
  • 消費者は、冗長性のために、とにかく新しい仕事のために投票をしたいと思うかもしれません。ポーリングが実際に成功した場合、これはPUBSUBでの消費とRPOPLPUSHでのポーリングの間でのみ発生するため、警告が発行されます。したがって、ポーリングの成功の多くは、サブスクリプションシステムの破損を示しています。

PUBSUB / RPOPLPUSH設計にもスケーリングの問題があることに注意してください。 すべてのコンシューマは、すべてのメッセージの軽量な通知を受け取ります。つまり、これには不必要なボトルネックがあります。チャンネルを使用して作業を分割することは可能だと思いますが、これはおそらくうまく機能するためのトリッキーなデザインです。


消費者をブロックする問題に私が従うかどうかわかりません。消費者が別の話になる可能性のある他のこともしているが、アプリケーション内の問題ではない場合は、消費者を処理する作業がない場合はブロックする必要がありますそして、キューのためにそんなに多くない?IEは、より大きなアプリ内でスレッドをブロックすることは、よりエレガントなソリューションではありません。この場合、スレッドは、キューからジョブを取得したときにアプリに通知できます。おそらく、合併症の原因となっているのはノードの使用だけです。
アーロン14

9
去年の8月からあなたがどこまで来たか興味があります。問題を満足のいくように解決できましたか?それらをどのように解決しましたか?
AaronM 14

3
AAA:@AaronMと同じように、あなたの進捗状況を聞きたいです。
ビヨン

同意した。これはどのように進行しましたか?RabbitMQをスタックから削除して、そこにあるRedisを使用するというアイデアが好きです。私の問題は、RSMQ(ノードlib)を使用してコンシューマを登録する方法です。
ra9r

@raiglstorferはそこで2年間働いていません。Pは自由に調査して投稿できます
...-djechlin

0

そのため、RedisでRabbitMQを使用することを選択した最大の理由は、障害シナリオとクラスタリングです。

この記事は本当にそれを最もよく説明しているので、リンクを提供するだけです:

https://aphyr.com/posts/283-jepsen-redis

Redisセンチネルおよび最近のRedisクラスタリングは、キューにとって不適切な選択となった多くの非常に基本的な障害シナリオを処理できません。

RabbitMQには独自の問題がありますが、本番環境では非常に堅実であり、優れたメッセージキューであると言われています。

これがウサギの投稿です:

https://aphyr.com/posts/315-jepsen-rabbitmq

CAPの定理(一貫性、可用性、パーティション処理)を見ると、3つのうち2つしか選択できません。世界の終わり。メッセージを失わないために、メッセージを失わないためにパーティション処理にignoreを使用します。ソースがUUIDを管理するため、重複を処理できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.