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



我有一个Java应用程序,它将事件发布到RabbitMQ。它有一个非常重要的特性:必须始终保持消息顺序。消费者可以处理重复的消息,但不能处理消息2在消息1之前排队的情况。

我最近读了很多关于RabbitMQ的文章,我觉得只有一个解决方案:将通道设置为confirm模式(https://www.rabbitmq.com/confirms.html-基本上,它迫使broker确认发布(并逐个发布。我的意思是,消息2只有在RabbitMQ确认(通过异步ACK响应(消息1实际上得到了很好的接收和持久化之后才发布。

我在一个概念实现中尝试过,虽然这很好,但速度非常慢,毫不夸张。这是有道理的:毕竟,我们现在将消息速率限制为每次1条消息。

因此,这引出了我的问题:是否有其他更高性能的方法来确保始终保留消息排序(在RabbitMQ中或通过不同的方法(?

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

RabbitMQ的客户端按照您发送的相同顺序排队。当用户宕机时,你会收到网络拆分或用户NACK消息,他们可以重新订购;即使这样,RMQ也试图通过在相同的位置或接近相同的位置重新排队来保持它们处于相同的近似顺序。

你可以按照你的建议去做一次接收一条消息,因为如果您接收了一条消息,但在从broker确认之前崩溃,那么当您的服务返回时,它会在相同的位置弹出。

这假设您在任何给定时间都只有一个单个服务实例,从队列中消耗。如果你有一个像Kubernetes或Mesos这样的调度器来生成你的服务实例,那么这本身就是一个分布式系统问题。

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

我已经在这里编写了一个更全面的指南作为注释代码https://github.com/haf/rmq-publisher-confirms-hopac/blob/master/src/Server/Shared/RabbitMQ.fs--使用批处理可以重新排序。此外,如果您的幂等性将连续序列号构建到其逻辑中,则可以开始进行批处理,并且每个事件都将是幂等的,尽管它们被重新消耗。

最新更新