写在前面
作者一直想深入的去研究一款消息队列MQ,例如 延迟消费,广播消息,失败重试等机制.
奈何市面上的MQ中间件太多了,如kafka,activeMQ,rocketMQ....所以也一直在纠结该以哪款为入手点,对新人友好?
想起作者曾深入的研究了xuxueli大佬的分布式调度系统(XXL-JOB),然后进入XXL社区,刚好发现了的另一个开源项目,即分布式消息队列(XXL-MQ).
简而言之四个字,以小见大,懂得都懂
提出问题
先思考两个通用MQ问题
1 生产者Producer 如何将消息发送至XXL-MQ消息中心的?中间源码
2 XXL-MQ消息中心如何接收,落盘接收到的消息
数据流程图
流程总结
1 生产者Producer调用XxlMqProducer.produce()方法开始发送消息
2 进行消息基础校验,属性丰富等validMessage(mqMessage)
3 将消息存放在生产者内存队列newMessageQueue
4 后台线程clientFactoryThreadPool不断消费内存队列,xxlMqBroker.addMessages()方法准备向MQ中心发送消息
5 xxlMqBroker被xxlRpcReferenceBean启动时动态代理,此时进入xxlRpcReferenceBean的动态代理类方法中
6 xxlRpcReferenceBean组装消息发送请求参数xxlRpcRequest
7 生产者底层netty通信传输,将此次请求传输至XXL-MQ中心netty
8 XXL-MQ中心 netty收到通信请求,并解析请求参数xxlRpcRequest,索引定位Spring serviceBean method 即此次请求目标执行方法上
9 目标方法被执行即 XxlMqBrokerImpl.addMessages(list),将消息存放至XXl-MQ中心内存队列newMessageQueue
10 XXL_MQ 后台线程executorService不断消费内存队列newMessageQueue,并最终进行数据落盘,入库Mysql
源码过程Debug图解
1 生产者Producer调用XxlMqProducer.produce()方法开始发送消息
2 进行消息基础校验,属性丰富等validMessage(mqMessage)
3 将消息存放在生产者内存队列newMessageQueue
4 后台线程clientFactoryThreadPool不断消费内存队列,xxlMqBroker.addMessages()方法准备向MQ中心发送消息
XxlMqClientFactory
5 xxlMqBroker被xxlRpcReferenceBean启动时动态代理,此时进入xxlRpcReferenceBean的动态代理类方法中
6 xxlRpcReferenceBean组装消息发送请求参数xxlRpcRequest
7 生产者底层netty通信传输,将此次请求传输至XXL-MQ中心netty
8 XXL-MQ中心 netty收到通信请求,并解析请求参数xxlRpcRequest,索引定位Spring serviceBean method 即此次请求目标执行方法上
9 目标方法被执行即 XxlMqBrokerImpl.addMessages(list),将消息存放至XXl-MQ中心内存队列newMessageQueue
10 XXL_MQ 后台线程executorService不断消费内存队列newMessageQueue,并最终进行数据落盘,入库Mysql
拓展
广播消息与普通消息发送的区别
广播消息在发送时会查看当前消息分组Group有多少,例如有三个Group1,Group2,Group3,然后将当前消息的属性group设置成对应值,然后进行三次不同的发送
如图
延迟消息与普通消息发送的区别
首先在XXL-MQ的设计中,消息有一个属性effectTime(即表示消息的生效时间, new Date()立即执行, 否则在生效时间点之后开始执行)
一般延迟消息应用于以下场景 ***支付**订单,10分钟后未支付则取消订单
所以例如需要设置一个5分钟后的延迟消息,则将属性effectTime进行对应 +5分钟
关于消息消费过程,靓仔们也可以看下我的另一篇文章记一次XXL-MQ消息消费失败的排查过程
写在最后
站在巨人的肩膀看世界,感谢xuxueli大佬的开源项目XXL开源社区
我是杨少,祝你幸福