写在前面
作者一直想深入的去研究一款消息队列MQ,例如 延迟消费,广播消息,失败重试等机制.
奈何市面上的MQ中间件太多了,如kafka,activeMQ,rocketMQ....所以也一直在纠结该以哪款为入手点,对新人友好?
想起作者曾深入的研究了xuxueli大佬的分布式调度系统(XXL-JOB),然后进入XXL社区,刚好发现了的另一个开源项目,即分布式消息队列(XXL-MQ).
简而言之四个字,以小见大,懂得都懂
复制代码
提出问题
1 消费端是如何进行消息消费的,消费端与MQ中心的数据流程是怎么样的?
2 如何控制超时消费,重试消费?
复制代码
数据流程图
流程总结
1 消费端程序启动时,初始化MQ连接配置Bean XxlMqSpringClientFactory
该XxlMqSpringClientFactory类继承了Spring框架的拓展类ApplicationContextAware
2 进入ApplicationContextAware的setApplicationContext()方法,并开始初始化XxlMqClientFactory
3 扫描项目中实现MqConsumer接口的类,即扫描所有topic类,并将信息存放在内存
List<ConsumerThread>中
4 根据不同ConsumerThread 的topic 启动对应的后台轮询线程,即拉取MQ消息的线程ConsumerThread.execute()
5 进行到ConsumerThread 线程中,查看线程拉取MQ消息方法xxlMqlBroker.pullMessages()
6 xxlMqlBroker此时被XxlRpcReferenceBean动态代理掉了,因此进入XxlRpcReferenceBean动态代理类
7 组装远程调用参数XxlRpcRequest,并底层通过netty 向MQ中心发起通信
8 MQ netty收到此次通信请求,并解析参数XxlRpcRequest,索引定位到目标执行方法Spring serviceBean Method
9 反射执行目标方法XxlMqBrokerImpl.pullNewMessage(),获取到MQ中心的消息,并neety通信返回结果至消费端
10 消费端判断此次消息是否有超时限制,有则通过FutureTask.get()辅助工具类,限制超时
无则直接通过反射底层执行topic消费方法即IMqConsumer.consume()
11 此次消费结束,消费端调用callbackMessage(msg)函数,将消费情况进行反馈,即为后续的失败重试机制做准备
复制代码
源码过程Debug图解
1 消费端程序启动时,初始化MQ连接配置Bean XxlMqSpringClientFactory
该XxlMqSpringClientFactory类继承了Spring框架的拓展类ApplicationContextAware
复制代码
2 进入ApplicationContextAware的setApplicationContext()方法,并开始初始化XxlMqClientFactory
复制代码
3 扫描项目中实现MqConsumer接口的类,即扫描所有topic类,并将信息存放在内存 List<ConsumerThread>中
复制代码
4 根据不同ConsumerThread 的topic 启动对应的后台轮询线程,即拉取MQ消息的线程ConsumerThread.execute()
复制代码
5 进行到ConsumerThread 线程中,查看线程拉取MQ消息方法xxlMqlBroker.pullMessages()
复制代码
6 xxlMqlBroker此时被XxlRpcReferenceBean动态代理掉了,因此进入XxlRpcReferenceBean动态代理类
复制代码
7 组装远程调用参数XxlRpcRequest,并底层通过netty 向MQ中心发起通信
复制代码
8 MQ netty收到此次通信请求,并解析参数XxlRpcRequest,索引定位到目标执行方法Spring serviceBean Method
复制代码
9 反射执行目标方法XxlMqBrokerImpl.pullNewMessage(),获取到MQ中心的消息,并neety通信返回结果至消费端
得到查询的sql语句
SELECT *
FROM xxl_mq_message t
WHERE t.topic = 'topic_1'
AND t.group = 'DEFAULT'
AND t.status = 'NEW'
AND t.effectTime < NOW()
AND ((t.shardingId = 0
AND MOD(t.id, 2) = 0)
OR (t.shardingId > 0
AND MOD(t.shardingId, 2) = 0))
ORDER BY t.id ASC
LIMIT 100
复制代码
10 消费端判断此次消息是否有超时限制,有则通过FutureTask.get()辅助工具类,限制超时
无则直接执行topic消费方法即IMqConsumer.consume()
复制代码
11 此次消费结束,消费端调用callbackMessage(msg)函数,将消费情况进行反馈,即为后续的失败重试机制做准备
复制代码
写在最后
个人思考 如何去考虑消息的顺序性消费
复制代码