我一直在寻找使用Redis Pub / Sub作为RabbitMQ的替代品。
根据我的理解,Redis的pub / sub与每个订阅者保持持久连接,如果连接终止,所有将来的消息都将丢失并丢弃在地板上。
一种可能的解决方案是使用列表(和阻塞等待)将所有消息和pub / sub存储为通知机制。我认为这让我大部分都在那里,但我仍然对失败案件有一些担忧。
当订户(消费者)死亡时,您的列表将继续增长,直到客户返回。一旦达到特定限制,您的生产者可以修剪列表(从任何一方),但这是您需要在应用程序级别处理的内容。如果在每条消息中包含时间戳,则您的消费者可以根据消息的年龄采取行动,假设您具有要在消息时间上强制执行的应用程序逻辑。
我不确定格式错误的消息将如何进入系统,因为与Redis的连接通常是TCP及其完整性保证。但是如果发生这种情况,可能是由于生产者层的消息编码中的错误,您可以通过保持接收消费者异常消息的每个生产者队列来提供处理错误的一般机制。
重试策略在很大程度上取决于您的应用程序需求。如果您需要100%保证已收到并处理了邮件,那么您应该考虑使用Redis事务(MULTI / EXEC)来包装使用者完成的工作,这样您就可以确保客户端不会删除邮件,除非它已经完成了它的工作。如果需要显式确认,则可以在专用于生产者进程的队列上使用显式ACK消息。
如果不了解您的应用需求,很难知道如何明智地选择。通常,如果您的消息需要完整的ACID保护,那么您可能还需要使用redis事务。如果您的消息仅在及时发布时才有意义,则可能不需要进行交易。听起来好像你不能容忍丢弃的消息,所以你使用列表的方法是好的。如果需要为邮件实现优先级队列,则可以使用排序集(Z命令)来存储邮件,使用其优先级作为分数值,以及轮询使用者。
我所做的是使用排序集,使用时间戳作为分数,使用数据键作为成员值。我使用最后一项的分数来检索接下来的几项,然后获得密钥。完成工作后,我将zrem和del包装在MULTI / EXEC事务中。
基本上是爱德华所说的,但是将密钥存储在有序集合中,因为我的消息可能非常大。
希望这可以帮助!
如果您想要一个pub / sub系统,订阅者在死亡时不会丢失消息,请考虑使用Redis Streams而不是Redis Pub / sub。
Redis Streams拥有自己的架构和Redis Pub / sub的优缺点。使用Redis Streams,订阅者可以发出命令:
我收到的最后一条消息是X,现在给我下一条消息;如果没有新消息,则等待一个消息到达。
上面链接的Antirez的文章是Redis流的一个很好的介绍,有更多的信息。
警告:此功能仅存在于Redis的不稳定(beta)版本中。