作为一名java程序员,求职面试时,关于消息中间件的问题时常会遇到,张工是一名java程序员,最近到某知名互联网公司面试,面试官提出这样的一个问题:
如何保证消息的顺序性?
张工一时间没有回答上来,面试官:你都工作三年了,怎么连保证消息的顺序性都不会啊。被面试官这么一说,张工都不好意思了。
其实面试官问这个问题无非就是考察两点:
考察你对消息顺序是否了解?如何保证消息的有序性?比如有这样一个需求,需要对MySql数据库的binlog日志进行采集,就是数据从一个mysql库同步到另一个mysql库。
要是有这样的一个操作:在mysql里对一条数据进行增删改操作,对应就有增删改3条binlog日志,接着这三条binlog发送到消息队列里,再通过Kafka或是RabbitMQ消费出来依次执行,这时就要保证消息的有序性了,要不然本来是增加、修改、删除这样的顺序;结果变成删除、修改、增加,顺序错乱了,本来这个数据同步过来最后应该是被删除了,结果顺序搞错了导致最后这个数据保留下来了,这个数据同步就出问题了。
我们来看看顺序错乱的两个场景:
Kafka:比如说我们建了一个topic,有三个partition。生产者在写的时候,其实可以指定一个key,比如说我们可以指定了某个订单id作为key,那么这个订单相关的数据,会被分发到同一个partition中去,而且这个partition中的数据一定是有顺序的。消费者从partition中取出来数据的时候,也一定是有顺序的。到这一步,顺序并没有问题。但是,接着我们在消费者里可能会搞多个线程来并发处理消息。因为如果消费者是单线程消费处理,而处理比较耗时的话,多个线程并发跑的话,这时顺序就有可能错乱了。RabbitMQ:一个queue,多个consumer。比如:生产者向RabbitMQ里发送了三条数据,顺序依次是A/B/C,压入的是RabbitMQ的一个内存队列。有三个消费者分别从MQ中消费这三条数据中的一条,结果消费者2先执行完操作,把B存入数据库,然后是A/C。这明显出错了。解决方案
Kafka
N个内存queue,具有相同key的数据都到同一个内存queue;然后对于N个线程,每个线程分别消费一个内存queue,这样就能保证顺序性了。
RabbitMQ
拆分多个queue,每个queue对于一个consumer,这样多了一些queue,并没有问题,就是比较麻烦;或者就一个queue对应一个consumer,然后这个consumer内部用内存队列做排队,然后交给底层不同的worker去处理。总结:
关于消息队列,平时工作中要注意总结和积累,查漏补缺,不断完善自己的知识体系。
由于笔者水平有限,文中纰漏之处在所难免,权当抛砖引玉,不妥之处,请大家批评指正。
-END-