主要思路有两种:
- 1、单线程消费来保证消息的顺序性;
- 2、对消息进行编号,消费者处理时根据编号判断顺序。
举个例子,一个mysql binlog同步的系统,压力还是非常大的,日同步数据要达到上亿。mysql→mysql,常见的一点在于数大数据team,就需要同步一个mysql库过来,对公司的业务系统的数据做各种复杂的操作。
我们在mysql里增删改一条数据,对应出来增删改3条binlog,接着这三条binlog发送到MQ里面,到消费出来一次执行起码的能保证是按照这个顺序执行的,不然机会错误。
rabbitmq:一个queue,多个consumer。
可能出现的位置错乱:
kafka:一个topic,一个partition,一个consumer,内部多线程。
可能出现的数据错乱:
解决方案
RabbitMQ
- 拆分多个 queue,每个 queue 一个 consumer,并设置prefetch_count=1,就是多一些 queue 而已,确实是麻烦点;或者就一个 queue 但是对应一个 consumer,然后这个 consumer 内部用内存队列做排队,然后分发给底层不同的 worker 来处理。
Kafka
- 一个 topic,一个 partition,一个 consumer,内部单线程消费,单线程吞吐量太低,一般不会用这个。
- 写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue(对消息的key做hash);然后对于 N 个线程,每个线程分别消费一个内存 queue 即可,这样就能保证顺序性。
rocketMq
我们只需要想办法让同一个订单的 binlog 进入到同一个 MessageQueue 中就可以了。因为同一个 MessageQueue 内的消息是一定有序的,一个 MessageQueue 中的消息只能交给一个 Consumer 来进行处理,所以 Consumer 消费的时候就一定会是有序的。
activeMq
如图,activeMq 里面有 messageGroups 属性,能够指定 JMSXGroupID,消费者会消费指定的 JMSXGroupID。即保证了顺序性,又解决负载均衡的问题。
消息接收端整流
携带不同序号的消息到达接收端后,消息客户端本地整流的方式可以根据具体业务的特点来实现,目前业界比较常见的实现方式比较简单,步骤如下:
- 下推消息时,连同消息和序号一起推送给接收方;
- 接收方收到消息后进行判定,如果当前消息序号大于前一条消息的序号就将当前消息追加在会话里;
- 否则继续往前查找倒数第二条、第三条等,一直查找到恰好小于当前推送消息的那条消息,然后插入在其后展示。