消息消费方式 : 拉取、推送
消费者启动流程
1.初始化MQClientInstance
2.初始化消息进度 : 集群模式,消费进度保存在Broker上;广播模式,消费进度保存在消费端
从何处开始消费,可选值:
1)CONSUME_FROM_LAST_OFFSET:上一次消费偏移量
2)CONSUME_FROM_FIRST_OFFSET:从头开始
3)CONSUME_FROM_TIMESTAMP:从某个时间点开始
消费进度存储
其实现类为:OffsetStore offsetStore。消费者需要记录消息消费的进度:
1)广播模式:广播模式由于每个消费者都需要消费消息,故消息的进度(最后消费的偏移量可以保存在本地)。
2)集群模式:由于集群中的消费者只要一个消费消息即可,故消息的消费进度,需要保存在集中点,故 RocketMQ存储在Broker所在的服务器。
广播消费偏移量 保存在本地; 集群模式,消费偏移offset保存在broker的机器
消息消费过程
消息的消费过程,就是从服务器拉取,然后消费者进行消费,再根据业务反馈是否成功消费来推动消费进度,也就是消息的消费进度并不是保存在服务端(比如 commitlog 文件中),而是保存在消费端(可以是本地(广播模式)、broker端(集群模式))具体的代码实现:
2.2 消息消费者启动关键流程
1) 构建 RebalanceImpl
2)PullAPIWrapper 对象构建
3)消费进度加载
5)MQClientInstance 启动,进入消息消费
6. 每隔30S尝试更新主题路由信息
7. 每隔30S 进行Broker心跳检测
8. 默认每隔5秒持久化ConsumeOffset
一个应用程序,一个消费组,只需要一个DefaultMQPushConsumerImpl,,在一个应用中,使用多线程创建多个
消费者,尝试去消费同一个组,没有效果,只会有一个消费者在消费。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DefaultMQPushConsumerImpl pullMessage 关键代码:
1、首先获取PullRequest的 处理队列ProcessQueue,然后更新该消息队列最后一次拉取的时间。
2、如果消费者 服务状态不为ServiceState.RUNNING,或当前处于暂停状态,默认延迟3秒再执行(PullMessageService.executePullRequestLater)
3、流量控制,两个维度,消息数量达到阔值(默认1000个),或者消息体总大小(默认100m)
4、获取主题订阅信息
5、如果是集群消费模式,从内存中获取MessageQueue的commitlog偏移量。
6、构建拉取消息系统Flag: 是否支持comitOffset,suspend,subExpression,classFilter
7、根据brokerName, brokerId从MQClientInstance中获取broker地址
接下来,以异步调用为例,分析拉取到消息后的回调处理逻辑。
代码入口:PullCallback pullCallback = new PullCallback(),见DefaultMQPushConsumerImpl 288行
1、首先对PullResult进行处理,主要完成如下3件事:
1)对消息体解码成一条条消息
2)执行消息过滤
3)执行回调
2、根据拉取结果分别采取不同的策略
1)拉取到消息,首先放入到处理队列中;然后是消费消息服务提交
第一步,将消息放入消费队列中:就是将拉取的消息,放入到ProcessQueue的msgTreeMap容器中。
第二步,消费消息服务提交
该方法重点已经标明,如果此次拉取的消息条数大于ConsumeMessageBatchMaxSize,则分批消费
线程池的常驻线程数:consumeThreadMin
线程池的最大线程数:consumeThreadMax
线程池中的线程名:ConsumeMessageThread_
这里就明确了一个点,一个消费者非顺序消费者,内部使用一个线程池来并非消费消息,一个线程一批次最大处理consumeMessageBatchMaxSize条消息。
再总结一下非顺序消费(并非消费)的主要思路:
1、将待消费的消息存入ProcessQueue中存储,并执行消息消费之前钩子函数
2、修改待消费消息的主题(设置为消费组的重试主题)
3、分页消费(每次传给业务消费监听器的最大数量为配置的
sconsumeMessageBatchMaxSize
4、执行消费后钩子函数,并根据业务方返回的消息消费结果(成功,重试)【ACK】确认信息,然后更新消息进度,从ProcessQueue中删除相应的消息
8.如果从节点数据包含下一次拉取的偏移量,设置下一次拉取任务的brokerId
9.如果commitLog 标记可用,并且当前节点为主节点,则更新消息消费进度
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RocketMQ的push模式
我们都知道RocketMQ在消费端有push和pull两种模式,pull模式需要我们手动调用consumer拉消息,而push模式则只需要我们提供一个listener即可实现对消息的监听,而实际上,RocketMQ的push模式是基于pull模式实现的,它没有实现真正的push。