您如何处理消息队列中乱序的消息?

Posted

技术标签:

【中文标题】您如何处理消息队列中乱序的消息?【英文标题】:How do you address messages coming out of order in a message queue? 【发布时间】:2020-02-17 02:22:25 【问题描述】:

我曾经在一次采访中被问到,你会如何处理消息队列中乱序的消息。已经有一段时间了,我还没有找到明确的答案,我想知道该领域的专家是否可以帮助我回答这个问题以解决我自己的好奇心。

我了解某些消息队列提供完全一次和 FIFO 保证。我也知道流系统中事件时间和处理时间的概念。例如,在 Kafka 等基于日志的消息队列中,由于存在偏移量和消息持久性(我可能错了),可能不太可能发生混合排序。我还考虑过使用时间戳,要求每个消息发送者在发送消息之前记录消息的时间,但由于时钟偏差,这充满了不一致。

考虑到所有这些,我想知道一个地址如何在 AMQP、JMS 或 RabbitMQ 等传统消息传递系统中混合排序,其中十几个 IOT 设备可能正在发送消息,而我作为消费者希望在正确的顺序。

【问题讨论】:

【参考方案1】:

如果您的系统正在使用队列,提供有序消息保证,则只需使用该通道(如 kakfa 的单分区,某些设置下的 AMQP)。 但是,如果您的系统使用的队列不提供严格排序,那么一般的想法是客户端可以单调在它发送的每条消息中附加增加[1]个数字(或时间戳)排队。这构成了生产者打算发送给其接收者的序列的基础。

如何获得单调递增的值:

使用时间戳: 带有 CLOCK_MONOTONIC[2] 的 POSIX clock_gettime() 函数提供了获取单调递增时间戳的选项,生产者可以使用该选项将时间戳放在每条消息上。当接收方看到收到的消息的时间戳早于最新消息时,接收方可以识别出乱序消息。

使用序列号: 在发送每条消息之前,您可以简单地增加一个原子计数器并将计数器值附加到每条消息,以便接收者可以了解预期的排序。这将形成严格递增的序列。该方法与 Lamport 的逻辑时钟[3] 非常相似,它为生产者提供虚拟时钟。

在接收方处理乱序消息: 这几乎是特定于应用程序的,但通常当消息无序到达时,您有 2 个选项: a) 丢弃旧消息,例如接收者必须显示股票的最新价值的情况。 b) 有缓冲区来重新排序,比如在 TCP 连接中(例如,zookeeper 使用 TCP 作为 FIFO 排序的队列 [4-5])

工具: 如果您没有为消息添加时间戳,则将所有消息从生产者发送到 Apache kafka 单个分区按顺序,因为这将确保接收者可以按顺序接收消息。

如果您使用的消息传递系统不能保证有序传递(例如某些设置下的 AMQP[6]),那么您可以考虑为每条消息添加额外的单调递增数字/时钟。

[1]https://en.wiktionary.org/wiki/monotonic_increasing#targetText=Adjective,contrast%20this%20with%20strictly%20increasing

[2]https://linux.die.net/man/2/clock_gettime

[3]https://en.wikipedia.org/wiki/Lamport_timestamps#Lamport's_logical_clock_in_distributed_systems

[4]https://cwiki.apache.org/confluence/download/attachments/24193445/zookeeper-internals.pdf?version=1&modificationDate=1295034038000&api=v2

[5]http://www.tcs.hut.fi/Studies/T-79.5001/reports/2012-deSouzaMedeiros.pdf

[6]RabbitMQ - Message order of delivery

【讨论】:

感谢您的精彩全面的回答,这结束了我脑海中不断出现的不和谐。我知道分布式系统中的逻辑时钟,但在这个用例中从未考虑过它!我很感激。【参考方案2】:

我可以回答关于 Apache Kafka 的问题。 Apache Kafka 通过分区保证主题的严格顺序,这意味着每个分区都是以严格顺序附加的不可变消息序列。 因此,以防万一,多个分区消费者可能会消费来自多个分区的消息,这些分区不能严格按顺序排列。我们可以考虑以下 2 个选项来实现严格的顺序。

    如果按顺序查找 1 个生产者消息,则每个主题仅使用 1 个分区。所以生产者会按顺序在同一个分区上发布,消费者会按照严格的顺序消费。

    生产者向多分区发布消息,因此在消费者组中使用多消费者,但使用分配给每个消费者的特定分区来消费来自特定分区的消息将保证每个消费者每个分区的严格顺序

【讨论】:

感谢您的回答,虽然它没有完全回答我的问题,但它为 Kafka 功能方面的问题提供了不同的视角。如果由于网络分区导致消息乱序,Kafka 是否会对主题分区中的消息重新排序,或者它只是保持接收消息的原始顺序?

以上是关于您如何处理消息队列中乱序的消息?的主要内容,如果未能解决你的问题,请参考以下文章

消息队列消息积压了该如何处理

消息队列如何处理重复消息

系统学习消息队列分享(七) 如何处理消费过程中的重复消息?

系统学习消息队列分享(八) 息积压了该如何处理?

成为架构师课程系列消息队列:秒杀时如何处理每秒上万次的下单请求?

MQ——消息积压如何处理