如何保证RabbitMQ(或任何其他异步消息队列服务)中的消息顺序

时间:2018-11-22 19:46:06

标签: rabbitmq message-queue

我有一个Java应用程序,它将事件发布到RabbitMQ。它具有一个非常重要的特征:必须始终保留消息顺序。消费者可以处理重复项,但是可以说,消息2在消息1之前排入队列。

最近,我一直在阅读有关RabbitMQ的很多文章,并且我觉得只有解决方案:将频道设置为confirm模式(https://www.rabbitmq.com/confirms.html-基本上,它迫使经纪人承认出版物)并一一出版。一一一加,我的意思是消息2仅在RabbitMQ确认(通过异步ACK响应)消息1实际上受到良好接收并持续存在之后才发布。

我在概念上实现了这一点,虽然效果很好,但速度却很慢,而且并不夸张。这是有道理的:毕竟,我们现在将消息速率一次限制为1条消息。

所以这引出我的问题:还有其他性能更高的方法来确保始终保留消息顺序(在RabbitMQ中还是通过其他方法)?

尽管我担心的是RabbitMQ,但我相信这个问题可能适用于任何类型的异步消息队列服务。

1 个答案:

答案 0 :(得分:0)

RabbitMQ的客户以您发送的相同顺序排队。当订户崩溃,网络分裂或订户NACKs消息可以重新排序时;甚至 RMQ尝试通过在相同位置或接近相同位置重新排队来使它们保持相同的近似顺序。

您可以按照建议进行操作; 一次接收一条消息,因为如果您接收一条消息,但是在您从代理确认之前崩溃了,那么当您的服务恢复到同一位置时,它将弹出。 / p>

这假设您在任何给定时间只有一个单个服务实例,并从队列中消耗资源。如果您拥有像Kubernetes或Mesos这样的调度程序,则又会产生一个分布式系统问题。

另一种解决方案是通过根据消息的逻辑时间戳/序列号对消息进行“重新排序”,以确保接收服务中的处理顺序。

我在https://github.com/haf/rmq-publisher-confirms-hopac/blob/master/src/Server/Shared/RabbitMQ.fs处以注释代码的形式编写了更为详尽的指南-通过批处理,您可以重新排序。此外,如果您的幂等性将连续的序列号构建为其逻辑,那么您就可以开始进行批处理,并且每个事件即使重新消耗也将是幂等的。