关于QMQ实现原理进行总结及实际使用中碰到的坑以及解决方案,
还需要思考一个问题就是QMQ如何避免消息重复消费,如何实现顺序消费问题
这些好好想想好好总结总结
1. QMQ
是一个可靠消息队列,基于QMQ可以实现业务解耦,将同步业务变成异步业务,大大提高程序的并发特性。
比如
A系统以来B系统,B系统依赖C系统,然而C有一个功能要调用A的某个功能,如果三者都通过接口进行依赖,就会产生循环依赖问题,后果比较严重,因此可以用qmq消息进行解耦。
系统之间的依赖关系还是 A->B->C
当C要调用A的某个功能时,给他发送一个QMQ消息即可,具体来说就是A订阅了C
的一个消息,这样系统中没有任何的C-A的依赖关系,也解决了我们的问题。
同时生产者消费者模式的这种异步处理方式也能提高我们系统的处理效率和并发性能。
2.
QMQ是基于消息主题的订阅来实现的,Producer端生产消息后,发送到broker服务器中存储,然后推送给订阅了该主题的consumer端。是采用的broker推送的机制,
qmq中consumegroup
和subject的概念,对于同一个主题的consumer来说,如果他们是同一个consumergroup中的,那么这些机器只有一个会接收到消息,如果说每个机器都需要接收到这个消息,
则通过不通过的group进行区分,这样做是基于这么一种情况考虑,当酒店下了一个订单,发送了一个酒店订单主题的消息,支付中心,订单中心,酒店这三个业务线同时订阅到该消息,实际情况是
这三个业务线都需要消费消息做不同的业务处理,因此配置consumer的时候可以设置不同的group,或者干脆不设置。酒店收到消息保存订单,支付中心也保存一笔,订单中心也保存一笔。
3. QMQ是如何实现负载均衡的,当消息积压后会有什么后果
首先QMQ
的broker,producer,和consumer这三者是通过zk进行协同的。producer,consumer,和broker都各自把自己的位置和消息注册在zk上,协同过程由zk
cluster保证可靠性。
当producer生产消息后,从zk 拉取对应的broker list
,把生产消息交给broker,broker接到消息后,从consumer
group中用负载均衡策略,把消息推送给其中一个机器。用这种方式实现负载均衡。
这是他们之间的协同关系。
4. QMQ的事务性消息的实现原理,首先是因为mysql支持在同一个db
instance上的两个数据库可以在一个事务中,因此实现方式就是当我们发送消息出去后,其实是把消息
放到和业务库同一个实例的的另一个数据库中,保证保存消息和业务操作在一个事务中(专用的事务管理器来实现跨db的事务一致性)。QMQ的broker的概念其实就是一个中间人角色
我们把消息发送出去了,其实是发送到QMQ
的broker中,然后broker向所有订阅了该主题的consumer端推送消息,consumer端接收到通知后,执行相关的消息消费逻辑,整个流程over
5. QMQ的幂等问题
所谓的幂等其实是每次接口或者业务的调用,参数一样,返回结果就必须一样。QMQ的producer可能由于网络问题导致消息发送重复,虽然QMQ尽量保证消息的可靠性,但是在业务处理中我们应该进行判重处理,实现业务逻辑处理的幂等,QMQ消息的特性是保证最少一次,也就是说可能出现重复,对于重复性问题要求严格的自己做业务上的判断。
6. QMQ 的顺序消费问题
本身QMQ并不支持顺序消费,kafka支持顺序消费,由于网络原因消息的投递有延迟及负载均衡策略,消息的消费顺序并不是以生产顺序一致,根据实际业务自己做判断,比如状态机,加上这个做判断然后决定先消费哪个后消费哪个,如果不满足状态机要求,我们可以抛异常,告诉QMQ消费失败,等待后续重发。
或者直接在qmq中添加版本号的控制,但是这种做法并不十分可取,因为在qmq和具体的业务逻辑耦合了。
7. QMQ
消息的异步消费,我们在消费消息的时候,需要做异步的操作,比如调用某个接口,而这个接口是异步的,而qmq需要知道当前消息是否成功消费,如果不做处理,qmq就默认消费成功了,
而真正的消费逻辑是异步的,可能已经报错了(因为新启的线程),这个时候需要进行手动ACK消息,把自动ack消息关闭,当异步操作完成后,进行手动ack,异步处理成功则发成功ack的处理