在一次采访中,有人问我如何处理消息队列中乱序的消息。已经有一段时间了,我还没有找到确切的答案,我想知道该领域的专家是否可以帮助我回答这个问题,以解决自己的好奇心。
我了解到某些消息队列仅提供一次和FIFO保证。我也知道流系统中事件时间和处理时间的概念。例如,在基于日志的消息队列(如Kafka)中,由于存在偏移量和消息持久性,混合排序的可能性较小(我可能错了)。我还考虑过使用时间戳,要求每个消息发件人在发送之前记录消息的时间,但是由于时钟偏斜,这会造成不一致。
鉴于所有这些,我想知道一个地址如何在传统的消息传递系统(例如AMQP,JMS或RabbitMQ)中混合排序,在该系统中可能有十几个IOT设备正在发送消息,而我作为消费者想在它们中协调它们。正确的顺序。
答案 0 :(得分:1)
我可以回答有关Apache Kafka的问题。 Apache Kafka通过分区保证主题上的严格顺序,这意味着每个分区都是按严格顺序附加的不可变消息序列。 因此,如果一个以上的分区使用者可能会使用来自多个分区的消息,而这些消息不能严格按照顺序进行。我们可以考虑使用以下2个选项来实现严格的顺序。
答案 1 :(得分:1)
如果您的系统正在使用队列,则提供有序消息保证,然后只需使用该通道即可(例如kakfa的单个分区,在某些设置下为AMQP)。 但是,如果您的系统正在使用的队列不提供严格排序,则通常的想法是,客户端可以随发送的每封邮件单调增加[1]个数字(或时间戳)排队。这构成了生产者打算发送给接收者的顺序的基础。
如何单调增加价值:
使用时间戳记: 带有CLOCK_MONOTONIC [2]的POSIX clock_gettime()函数提供了获得单调递增时间戳的选项,生产者可以使用该时间戳为每条消息添加时间戳。当接收者看到接收到的消息的时间戳早于最新消息时,可以识别出乱序的消息。
使用序列号: 在发送每条消息之前,您可以简单地增加一个原子计数器并将计数器值附加到每条消息上,以便接收者可以知道预期的顺序。这将形成严格增加的顺序。该方法与Lamport的逻辑时钟[3]非常相似,后者为生产者提供了虚拟时钟。
在接收方处理乱序消息: 这几乎是特定于应用程序的,但是通常,当消息乱序到达时,您有两个选择: a)丢弃旧消息,例如在接收者必须显示股票的最新价值的情况下。 b)具有缓冲区以对排序进行重新排序,例如在TCP连接中(例如zookeeper使用TCP作为FIFO排序队列[4-5])
工具: 如果您不为消息添加时间戳,则将所有消息按顺序从生产者发送到Apache kafka 单分区 ,因为这将确保接收者可以按顺序接收消息。 / p>
如果您使用的消息传递系统不能保证有序交付(例如某些设置下的AMQP [6]),则可以考虑为每条消息添加其他单调递增的数字/时钟。
[2] https://linux.die.net/man/2/clock_gettime
[3] https://en.wikipedia.org/wiki/Lamport_timestamps#Lamport的s_logical_clock_in_distributed_systems
[5] http://www.tcs.hut.fi/Studies/T-79.5001/reports/2012-deSouzaMedeiros.pdf