Redis可靠性发布/订阅

62

我一直在考虑使用Redis Pub/Sub作为RabbitMQ的替代方案。

根据我的理解,Redis的发布/订阅会对每个订阅者保持持久连接,如果连接终止,所有未来的消息都将丢失并被抛弃。

一个可能的解决方案是使用列表(和阻塞等待)存储所有消息,并将发布/订阅作为通知机制。我认为这基本上可以解决我的问题,但我仍然担心故障情况。

  1. 当订阅者死亡并重新上线时,应如何处理其所有未决消息?
  2. 当异常消息通过系统时,如何处理这些异常? DeadLetter队列?
  3. 实现重试策略有标准做法吗?

3
您可以访问http://redis.io/commands/rpoplpush 查看可靠队列的Redis模式。 - hgf
我也遇到了同样的问题...我想要向客户发送位置更新...一旦他们断开连接,我不知道如何在客户端和服务器之间同步数据...你解决了这个问题吗?如果是的,怎么解决的? - Abhyudit Jain
3个回答

43

当一个订阅者(消费者)死亡时,你的列表将会继续增长直到客户端返回。 你的生产者可以在达到特定限制后修剪列表(从任一侧),但这是你需要在应用层面处理的事情。如果在每条消息中包含时间戳,你的消费者就可以根据消息的年龄采取行动,假设你有希望强制执行消息年龄的应用逻辑。

我不确定一个畸形的消息如何进入系统,因为与Redis的连接通常是TCP,并具有完整性保证。但如果发生这种情况,可能由于生产者层的消息编码错误,你可以通过保留一个队列-每个生产者接收消费者异常消息的机制来提供处理错误的通用机制。

重试策略将大大依赖于你的应用程序需求。 如果你需要100%的保证,即消息已被接收并处理,则应考虑使用Redis事务(MULTI/EXEC)来包装由消费者完成的工作,以便确保除非已完成其工作,否则客户端不会删除消息。如果你需要明确的确认,则可以在专用于生产者进程的队列上使用显式ACK消息。

不了解更多关于你的应用程序需求的信息,很难知道如何明智地选择。 通常,如果你的消息需要完全的ACID保护,则可能还需要使用Redis事务。 如果你的消息只有在及时性时才有意义,则可能不需要事务。听起来好像你不能容忍丢失消息,因此使用列表的方法是好的。如果你需要为消息实现优先级队列,则可以使用排序集合(Z-命令)存储你的消息,并将它们的优先级作为分值,以及一个轮询消费者。


6
如果您需要一个发布/订阅系统,订阅者不会在死亡时丢失消息,考虑使用Redis Streams而不是Redis Pub/sub。
Redis Streams有自己的架构和Redis Pub/sub的优缺点。使用Redis Streams,订阅者可以发出以下命令:
“我收到的最后一条消息是X,请给我下一条消息; 如果没有新消息,则等待一个到达。”
Antirez上面链接的文章是关于Redis Streams的良好介绍,其中包含更多信息。

3
我所做的是使用排序集合,以时间戳作为分数,以数据的键作为成员值。我使用最后一项的分数来检索下几个条目,然后获取键。工作完成后,我将zrem和del都包装在MULTI/EXEC事务中。
基本上就是Edward所说的,但我的消息可能非常大,所以要将键存储在排序集合中。
希望这可以帮到你!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接