我一直在考虑使用Redis Pub/Sub作为RabbitMQ的替代方案。
根据我的理解,Redis的发布/订阅会对每个订阅者保持持久连接,如果连接终止,所有未来的消息都将丢失并被抛弃。
一个可能的解决方案是使用列表(和阻塞等待)存储所有消息,并将发布/订阅作为通知机制。我认为这基本上可以解决我的问题,但我仍然担心故障情况。
- 当订阅者死亡并重新上线时,应如何处理其所有未决消息?
- 当异常消息通过系统时,如何处理这些异常? DeadLetter队列?
- 实现重试策略有标准做法吗?
我一直在考虑使用Redis Pub/Sub作为RabbitMQ的替代方案。
根据我的理解,Redis的发布/订阅会对每个订阅者保持持久连接,如果连接终止,所有未来的消息都将丢失并被抛弃。
一个可能的解决方案是使用列表(和阻塞等待)存储所有消息,并将发布/订阅作为通知机制。我认为这基本上可以解决我的问题,但我仍然担心故障情况。
当一个订阅者(消费者)死亡时,你的列表将会继续增长直到客户端返回。 你的生产者可以在达到特定限制后修剪列表(从任一侧),但这是你需要在应用层面处理的事情。如果在每条消息中包含时间戳,你的消费者就可以根据消息的年龄采取行动,假设你有希望强制执行消息年龄的应用逻辑。
我不确定一个畸形的消息如何进入系统,因为与Redis的连接通常是TCP,并具有完整性保证。但如果发生这种情况,可能由于生产者层的消息编码错误,你可以通过保留一个队列-每个生产者接收消费者异常消息的机制来提供处理错误的通用机制。
重试策略将大大依赖于你的应用程序需求。 如果你需要100%的保证,即消息已被接收并处理,则应考虑使用Redis事务(MULTI/EXEC)来包装由消费者完成的工作,以便确保除非已完成其工作,否则客户端不会删除消息。如果你需要明确的确认,则可以在专用于生产者进程的队列上使用显式ACK消息。
不了解更多关于你的应用程序需求的信息,很难知道如何明智地选择。 通常,如果你的消息需要完全的ACID保护,则可能还需要使用Redis事务。 如果你的消息只有在及时性时才有意义,则可能不需要事务。听起来好像你不能容忍丢失消息,因此使用列表的方法是好的。如果你需要为消息实现优先级队列,则可以使用排序集合(Z-命令)存储你的消息,并将它们的优先级作为分值,以及一个轮询消费者。