Python Redis-Pubsub与消息队列

Python Redis-Pubsub与消息队列,python,redis,redis-cli,Python,Redis,Redis Cli,我的总体问题是:使用Redis for PubSub,当发布者将消息推送到频道的速度超过订阅者的阅读速度时,消息会发生什么变化 例如,假设我有: 一个简单的发布者以2 msg/秒的速度发布消息 一个简单的订阅者以每秒1 msg的速率读取消息 我天真的假设是订阅者只能看到50%的消息发布到Redis上。为了验证这个理论,我写了两个脚本: pub.py queue = redis.StrictRedis(host='localhost', port=6379, db=0) channel = q

我的总体问题是:使用Redis for PubSub,当发布者将消息推送到频道的速度超过订阅者的阅读速度时,消息会发生什么变化

例如,假设我有:

  • 一个简单的发布者以2 msg/秒的速度发布消息
  • 一个简单的订阅者以每秒1 msg的速率读取消息
我天真的假设是订阅者只能看到50%的消息发布到Redis上。为了验证这个理论,我写了两个脚本:

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)
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

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)
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
    ,然后在运行
    sub.py
    之前等待5秒时,我发现
    sub.py
    只显示了消息的后半部分(5-10)。我本来会假设这一点,但考虑到我之前的结果,我会认为消息是排队的,这导致我得出以下结论
结论

  • Redis server似乎为每个客户端、每个通道的消息排队
  • 只要客户机在侦听,它读取消息的速度就无关紧要。只要它是连接的,消息将保持排队等待该客户机,该通道
剩余问题

  • 这些结论有效吗
  • 如果是,客户端/通道消息将保持排队多长时间
  • 如果是,是否有
    redis cli info
    命令来查看队列中有多少消息(针对每个客户端/通道)

测试是有效的,但结论部分是错误的

Redis不在发布/订阅频道上排队。相反,它倾向于从发布者套接字读取项目,然后在所有订阅者套接字中写入项目,理想情况下是在事件循环的同一迭代中。Redis数据结构中没有任何内容

现在,正如您所演示的,仍然存在某种缓冲。这是由于使用了TCP/IP套接字和Redis通信缓冲区

套接字具有缓冲区,当然,TCP还带有一些流控制机制。它避免了在缓冲区已满时丢失数据。如果订户速度不够快,数据将在其套接字缓冲区中累积。当它已满时,TCP将阻止通信,并阻止Redis在套接字中推送更多信息

Redis还管理输出通信缓冲区(位于套接字上),以生成使用Redis协议格式化的数据。因此,当套接字的输出缓冲区已满时,事件循环将套接字标记为不可写,数据将保留在Redis输出缓冲区中

如果TCP连接仍然有效,数据可以在缓冲区中保留很长时间。现在,套接字和Redis输出缓冲区都已绑定。如果订阅者的速度实在太慢,并且积累了大量数据,Redis将最终关闭与订阅者的连接(作为一种安全机制)

默认情况下,对于发布/订阅,Redis的软限制为8MB,硬限制为32MB,每个连接缓冲区。如果输出缓冲区达到硬限制,或者在软限制和硬限制之间保持60秒以上,则与慢速订户的连接将关闭

知道挂起消息的数量并不容易。可以通过查看套接字缓冲区和Redis输出缓冲区中挂起信息的大小来评估它

对于Redis输出缓冲区,可以使用(来自Redis cli)。输出缓冲区的大小在obl和oll字段中返回(以字节为单位)


对于套接字缓冲区,没有Redis命令。但是,在Linux上,可以构建一个脚本来解释/proc/net/tcp文件的内容。请看一个例子。此脚本可能需要根据您的系统进行调整。

“问题有新答案-请单击此处加载”-您键入的速度比我快,并给出了一个惊人的答案:)抱歉:-)我被问题所激励!回答得很好!是否可以完全禁用Redis缓冲区,仅接收新事件的实际数据(例如,证券交易所市场更新),即使之前的数据有所丢失,也可以确保数据是最新的?不,不可能。缓冲区中的内容已经在Redis协议中编码,不能在任意位置任意剪切。它可能需要重新分析缓冲区的内容。@Didier Spezia,Redis 4.0.7中的“C”源代码文件包含控制1)TCP何时会阻止通信并阻止Redis在套接字中推送更多信息的逻辑。2) 如果订阅者的速度实在太慢,并且积累了大量数据,Redis何时最终会关闭与订阅者的连接?非常感谢。