一、为什么要保证顺序
消息队列中的若干消息如果是对同一个数据进行操作,这些操作具有前后的关系,必须要按前后的顺序执行,否则就会造成数据异常。
例如,业务上产生三条消息,分别是对数据的增加、修改、删除,而如果没有保证顺序消费,结果可能是删除、修改、增加,本来数据最终要删除、结果变成增加。
二、RabbitMQ顺序消费模式
一个Queue,有多个Consumer去消费,这样就会造成顺序的错误,Consumer从MQ里面读取数据是有序的,但是每个Consumer的执行时间是不固定的,无法保证先读到消息的Consumer一定先完成操作,这样就会出现消息并没有按照顺序执行,造成数据顺序错误。
解决方案:
一个Queue对应一下Consumer,把需要保证顺序的message都发送到一个Queue当中,关闭autoack,prefetchCount=1,每次只消费一条信息,处理过后进行手工ack,然后接收下一条message,只是由一个Consumer进行处理。
多数业务场景下,可以做局部顺序,创建多个队列,同一业务id的消息发送到同一个消息队列,这样队列数增加,消费者数量也会增加 了。
拆分多个Queue,每个Queue一个Consumer,就是多一些Queue而已。
首先,我们在 RabbitMQ 中会建立有相同前缀的队列,后面跟着队列编号。然后,集群中的不同应用会分别监听这两个有着不同编号的队列。当在 A 发送信息时,我们会对信息做一次简单的哈希:
m = hash(id) mod n
这里,id 是订单的标识。n 是集群中 B 所在业务系统部署的数量。最终的 m 是我们需要发送到的目的队列编号。
假设,hash(id) 的结果为 2000,n 为 2,经过计算 m = 0。此时,A 就会把他和 B 的对话信息都发送到 chat00 的队列里。B 收到消息后,就会依次显示给终端用户。这样,聊天乱序的问题就解决了。
三、kafka顺序消费模式
具有顺序的数据写入到了不同的partition里面,不同的消费者去消费,但是每个consumer的执行时间是不固定的,无法保证先读到消息的consumer一定先完成操作,这样就会出现消息并没有按照顺序执行,造成数据顺序错误。
解决方案:
确保顺序消息发送到同一个partition,一个topic,一个partition,一个consumer,内部单线程消费。
来源:
https://www.toutiao.com/i6936741307201274401/