这几天在看RocketMQ的知识,跟踪了下源码,弄清楚了MQ生产和消费消息的流程,这里记录下MQ消费消息的过程。

1:RebalanceService线程构造PullRequest并将request放入pullRequestQueue,而PullRequest的具体信息来源于topicSubscribeInfoTable

python rocketmq 消费位置 rocketmq消费过程_多线程

python rocketmq 消费位置 rocketmq消费过程_返回结果_02

2:PullRequest放入pullRequestQueue后由PullMessageService线程从pullRequestQueue阻塞取出然后将请求构造成PullMessageRequestHeader,然后交给MQClient发送请求,发送请求就不必跟下去了底层就是通过Netty通信,如果要看Netty是如何通信的可以看我之前写关于Dubbo的provider和consumer交互的博客。如果是异步发送的话在构造PullMessageRequestHeader之前将会new一个PullCallback,用于处理返回结果(见下面第二张图)。

python rocketmq 消费位置 rocketmq消费过程_返回结果_03

python rocketmq 消费位置 rocketmq消费过程_多线程_04

python rocketmq 消费位置 rocketmq消费过程_发送消息_05

 

 

python rocketmq 消费位置 rocketmq消费过程_发送消息_06

3:在broker端,经过Netty接收消息并对消息解码后,把pull请求交给PullMessageThread_X处理。通过CommitLog获取结果,而commitLog则是在之前存入消息的MappedFile中获取对应的消息。

python rocketmq 消费位置 rocketmq消费过程_发送消息_07

python rocketmq 消费位置 rocketmq消费过程_发送消息_08

python rocketmq 消费位置 rocketmq消费过程_发送消息_09

4:broker返回结果后会通过之前提到的PullCallback的onSuccess方法来处理响应(见上面第2点的第二张图)并将响应构造成一个ConsumeRequest(注意这个request实现了Runable接口的)然后交给consumeExecutor处理,consumeExecutor会执行request的Run方法,并最终将响应交给在consumer中注册的MessageListenerConcurrently实例去处理(见下图3)。

python rocketmq 消费位置 rocketmq消费过程_多线程_10

python rocketmq 消费位置 rocketmq消费过程_多线程_11

python rocketmq 消费位置 rocketmq消费过程_发送消息_12

5:消息生成从producer传送到broker保存的过程就相对要简单些,一样地在producer端需要根据topicPublishInfo中的信息选择一个broker的特定队列,然后构造SendMessageRequestHeader最终交给MQClient发送消息。

python rocketmq 消费位置 rocketmq消费过程_返回结果_13

python rocketmq 消费位置 rocketmq消费过程_发送消息_14

python rocketmq 消费位置 rocketmq消费过程_发送消息_15

python rocketmq 消费位置 rocketmq消费过程_多线程_16

6:broker通过Netty接受消息并解码后,将消息交给SendMessageThread_X线程来处理请求,在将消息写入MappedFile之前为了防止多线程同时向MappedFile写消息,所以用了一个putMessageLock锁,注意下图最下面的红色的框中,当MappedFile写完后,系统将会再创建一个MappedFile继续写消息。

python rocketmq 消费位置 rocketmq消费过程_多线程_17

7:向MappedFile写入消息后还有两个重要的操作就是通知刷盘,和HA处理。下图二是刷盘的代码,其实异步刷盘的操作很简单只是通过wakeup()方法通知定时刷盘服务可以刷盘了。普通消息(非事务消息)的定时刷盘服务由FlushRealTimeService来完成的。

python rocketmq 消费位置 rocketmq消费过程_发送消息_18

python rocketmq 消费位置 rocketmq消费过程_发送消息_19

8 上面7介绍了一个消息正常的生命周期,那么非正常的处理有哪些呢?在broker启动时会启动一个清理过期请求的服务,其会清理四种类型的请求,如果你收到了[TIMEOUT_CLEAN_QUEUE]broker busy, start flow control for a while, period in queue: %sms, size of queue: %d 这种消息,那么肯定就是消息在队列中过期被清理掉了(见下面第三张图)默认的SendQueue的过期时间是200ms其可以通过配置waitTimeMillsInSendQueue=200来改变过期时间。

python rocketmq 消费位置 rocketmq消费过程_多线程_20

python rocketmq 消费位置 rocketmq消费过程_发送消息_21

python rocketmq 消费位置 rocketmq消费过程_多线程_22