我试图了解RabbitMQ的最佳用途,以满足以下问题。
由于上下文我不关心此用例的性能(此流量的峰值TPS为2 TPS),但我担心恢复能力。
我将RabbitMQ安装在集群中并忽略死信队列基本流程是我有一个服务接收请求,创建一个持久消息,它在事务中排队到一个持久队列(此时我&#39 ;很高兴请求被保护到磁盘)。然后我有另一个进程正在侦听一条消息,它读取(不使用auto ack),做了很多事情,将一条新消息写入事务中的另一个交换队列(现在再次感到高兴的是这条消息被保护到磁盘)。假设事务成功完成,它会手动将消息回送给原始使用者。
此时我唯一的失败场景是我在提交事务以写入第二个队列和返回ack之间出现故障。这将导致消息可能被处理两次。我还能做些什么来填补这个空白,或者我必须想办法处理重复的消息。
作为上下文的最后一点,服务是用java编写的,所以使用java客户端库。
保罗菲茨。答案 0 :(得分:2)
首先,我建议您查看本指南here,其中包含有关您主题的大量有效信息。
来自RabbitMQ指南:
在制片人
使用确认时,生产者从频道或连接中恢复 失败应重新传输任何确认的消息 尚未收到经纪人的通知。有可能 消息重复在这里,因为经纪人可能已经发送了一个 从未到达生产者的确认(由于网络故障, 等等)。 因此消费者应用程序需要执行 重复数据删除或以幂等方式处理传入的消息。
消费者
如果网络出现故障(或节点崩溃),可以发送消息 重复,消费者必须准备好处理它们。 如果 可能,最简单的方法是确保你的 消费者以幂等方式处理消息而不是明确地处理消息 处理重复数据删除。
所以,重点是不可能以任何方式保证你的“失败”情况不会发生。您将始终必须处理网络故障,磁盘故障,在此处放置故障等。
您需要做的是依靠消息传递架构并实现您的消息的“ idempotency ”(这意味着即使您处理消息两次也不会发生任何事情)错了,检查this)。 如果您不能提供某种“已处理的消息”列表(例如,您可以在每条消息中使用guid)并在每次收到消息时检查此列表;在这种情况下你可以简单地丢弃它们。
为了更加“理论化”,来自Brave New Geek的this帖子非常有趣:
在分布式系统的环境中,你不能拥有 准确的一次消息传递。
希望有所帮助:)