web-dev-qa-db-ja.com

Redis Pubsubおよびメッセージキュー

私の全体的な質問:PubSubにRedisを使用すると、パブリッシャーがサブスクライバーが読むことができるよりも速くチャンネルにメッセージをプッシュすると、メッセージはどうなりますか?

たとえば、私が持っているとしましょう:

  • 2 msg /秒のレートでメッセージを発行する単純なパブリッシャー。
  • 1 msg /秒のレートでメッセージを読む単純なサブスクライバー。

私の素朴な仮定は、サブスクライバーがRedisに発行されたメッセージの50%のみを見るということです。この理論をテストするために、2つのスクリプトを作成しました。

pub.py

queue = redis.StrictRedis(Host='localhost', port=6379, db=0)
channel = queue.pubsub()

for i in range(10): 
    queue.publish("test", i)
    time.sleep(0.5)

sub.py

r = redis.StrictRedis(Host='localhost', port=6379, db=0)
p = r.pubsub()
p.subscribe('test')

while True:
    message = p.get_message()
    if message:
        print "Subscriber: %s" % message['data']
    time.sleep(1)

結果

  • 実行したときsub.py最初に、直後にpub.py、 見つけた sub.pyは実際にすべてのメッセージ(1〜10)を次々に表示し、その間に1秒の遅延がありました。 Redisはメッセージをキューイングしています。さらにテストが必要です。
  • 実行したときpub.py最初に、5秒待ってからsub.py、 見つけた sub.pyは、メッセージの後半のみを表示しました(5〜10)。私はもともとこれを想定していましたが、以前の結果を考えると、メッセージがキューに入れられていると思い、次の結論に至りました...

結論

  • Redisサーバーは、各チャネルの各クライアントのメッセージをキューに入れるように見えます。
  • クライアントがリッスンしている限り、メッセージの読み取り速度は重要ではありません。接続されている限り、メッセージはそのチャネルのクライアントに対してキューに入れられたままになります。

残りの質問

  • これらの結論は有効ですか?
  • ある場合、クライアント/チャネルメッセージはどれくらいの間キューに入れられますか?
  • もしそうなら、redis-cli infoコマンドは、(クライアント/チャネルごとに)キューに入っているメッセージの数を確認しますか?
47
Marco Benvoglio

テストは有効ですが、結論は部分的に間違っています。

Redisはpub/subチャネルの何もキューに入れません。反対に、理想的にはイベントループの同じ反復で、パブリッシャソケットからアイテムを読み取り、すべてのサブスクライバソケットにアイテムを書き込む傾向があります。 Redisデータ構造には何も保持されません。

さて、あなたが示したように、まだ何らかのバッファリングがあります。これは、TCP/IPソケットとRedis通信バッファーの使用によるものです。

ソケットにはバッファーがあり、もちろん、TCPにはフロー制御メカニズムが付属しています。バッファーがいっぱいになったときのデータの損失を回避します。バッファがいっぱいになると、TCPは通信をブロックし、Redisがソケットに追加情報をプッシュするのを防ぎます。

Redisは、Redisプロトコルでフォーマットされたデータを生成するために、出力通信バッファー(ソケットの上部)も管理します。そのため、ソケットの出力バッファーがいっぱいになると、イベントループはソケットを書き込み不可としてマークし、データはRedis出力バッファーに残ります。

TCP接続がまだ有効である場合、データは非常に長い時間バッファに残ることができます。現在、ソケットとRedis出力バッファの両方がバインドされています。サブスクライバが本当に遅すぎる場合、大量のデータが蓄積されると、Redisは最終的にサブスクライバーとの接続を閉じます(安全メカニズムとして)。

デフォルトでは、pub/subの場合、Redisには接続バッファーごとに8 MBのソフト制限と32 MBのハード制限があります。出力バッファがハード制限に達するか、60秒を超えてソフト制限とハード制限の間に留まる場合、低速サブスクライバとの接続が閉じられます。

保留中のメッセージの数を知ることは簡単ではありません。ソケットバッファーおよびRedis出力バッファーの保留情報のサイズを調べることで評価できます。

Redis出力バッファーの場合、 CLIENT LISTコマンド (redis-cliから)を使用できます。出力バッファのサイズは、oblおよびollフィールドに返されます(バイト単位)。

ソケットバッファーの場合、Redisコマンドはありません。ただし、Linuxでは、/ proc/net/tcpファイルの内容を解釈するスクリプトを作成できます。例を参照してください here 。このスクリプトは、おそらくシステムに適合させる必要があります。

87
Didier Spezia