目录
- 生产端控制消息有序
- 消费端控制消息有序
- 总结
- Reference
消息的有序性指的是一个生产者生产的消息消费顺序和生产顺序一致,例如使用binlog+mq进行数据同步的时候,对于单条记录的增加、和修改和删除应该保持有序,消费消息时如果消息变成删除、修改和删除,则导致同步数据不一致。对于最简单的消息模型,一个生产者+一个消息队列+一个消费者,由于队列具有先进先出(FIFO,first in first out)特性,这样的消息模型消息时有序的。
消息从生产到消费有两个传输阶段,第一个阶段是从生产者到消息队列,第二个节点是从消息队列推送到消费端,为了使用保证消息MQ中消息有序,需要在两阶段进行控制。
生产端控制消息有序
对于RabbitMQ一个topic对应一个channel,从生产者到消费者不会出现顺序问题。
对于kafaka,一个topic的消息进行分片,存储在不同的队列里面,这样就无法利用队列的FIFO特性,保证消费消息时的有序性。
如果要保证一个topic中的所有消息有序,只能讲将kafaka的partition设置为1;
同时kafaka还支持局部有序,在生产消息时为每条消息指定partition key,分区key相同 消息会落入同一个分区中。对于每个消息,可以根据消息的整体内容,或者消息中某个字段,计算消息要落入的分片key,例如在使用binlog+mq同步mysql数据时,对每条记录的主键id号进行hash计算,确定要落入的分片。
消费端控制消息有序
对于rabbitMQ,一个队列对应一个消费者,消息消费是有序的,不会出现什么问题,当出现多个消费者时,依然会出现同一类消息消费顺序打乱的情况。
方法1:是只使用一个消费者,但这样会影响消费的速度,尤其是当下游消费速度很慢的情况,极有可能造成消息的积压,真正项目中也很少使用。
方法2:对一个topic的中消息使用多个队列来存储,并且将同一个类消息放在同一个队列中,一个队列中消息依然对应一个消费者,由于每个topic消息分散存储在多个队列中,每个队列中消息数量不会太多,引起消息积压的概率较小。缺点,每个topic都需要创建多个队列,需要维护大量的队列。
对于kafka,一个pation对应一个consumer,但是当comsumer使用了多线程技术,等价于一个队列对应多个consumer。
解决办法:
在消费者消费消息的时候,对消息进行分类,同一类的的消息使用同一个内存队列进行存储。缺点:使用大量内存队列存储消息会占用太多内存,影响应用整体性能。
总结
RabbitMQ消息模型简单,生产消息端是有序的。kafka一个topic中的消息对应多个patition,要保证一个topic中消息的有序,就只能设置一个patition。
在大多数业务场景中只需要保证局部有序,通过对每条消息计算partitionkey,让同一类消息落在同一个patition中。
在多consumer情况下,例如多线程情况,对消息可以进一步细化,保证同一类消息被同一个消费线程消费。
note:以上谈论mq有序性,都是针对生产者、消息队列和和消费者都是单机情况,集群情况下还需要考虑消息的分发和路由。
Reference