RocketMQ 之 消息拉取

2,394 阅读2分钟

概述

Consumer 通过 PullMessageService 线程拉取消息。PullMessageServicepullRequestQueue 获取 拉取消息请求(PullRequest), 从而向 Broker 拉取消息。

消息拉取消息后,会把消息放入本地的 ProcessQueue. 再由消费者消费 ProcessQueue 中的数据。

消息拉取流程

流程图解

image.png

消息拉取

代码位置: DefaultMQPushConsumerImpl#pullMessage()

  1. Rebalance 结束后,会往 PullMessageServicepullRequestQueue 中添加一个 PullRequest

  2. PullMessageService 从队列中取出 1 个 PullRequest,然后向 Broker 拉取 32 条消息(默认)。Consumer 可通过 pullBatchSize 参数控制。

  3. 如果 ConsumerProcessQueue 消息大于 1000 条 或者 ProcessQueue 堆积的消息大小超过 100MB, 会触发流控,即延迟 50ms 再拉取消息。否则拉取一次消息,会立马又发生请求拉取消息。

Consumer 可通过调用 setPullThresholdForQueue(), setPullThresholdSizeForQueue()。设置触发流控阈值.

提醒
ProcessQueue 是以消费者组为单位的。

broker 端处理消息拉取

代码位置: PullMessageProcessor#processRequest()

  1. Broker 先从 ConsumerQueue 中根据拉取偏移量,拉取消息

  2. 如果消费者有根据 tag 过滤消息,则根据 ConsumerQueue ItemtagHashCode 快速过滤消息

  3. 根据 ConsumerQueue ItemoffsetCommitLog 中拉取消息

  4. 如果消费者消费太慢。 则建议 Consumer 下次拉取消息时,从 slave 拉取消息。消费太慢的判断依据是 (当前 CommitLog 的最大偏移量 - 拉取消息的最大偏移量) / 机器物理内存 > 40%

  5. 返回数据给消费端

Consumer 处理拉取到的消息

  1. Consumer 本地再次过滤消息。

  2. 如果是 tag 过滤,则比较 tag hashcode 的值。

  3. 过滤完消息后将 消息放入本地的 ProcessQueue

  4. 再往 pullRequestQueue 中存放 PullRequest, 准备下次拉取。

总结

  1. 默认用的 Push 模式拉消息. Push 是用 Pull 实现的, 即长轮询。

  2. 消息拉取时,Consumer 端有流控;默认的行为是:ProcessQueue 的消息数量超过 1000 条,或者消息大小超过 100MB 则延迟 50ms 拉消息。

  3. 消息过滤时,如果是 tag, Broker 端会先按照 tag hashcode 进行粗粒度的过滤;最后 Consumer 端再根据 tag 的值进行过滤。

  4. 拉取到消息后,并不是直接消费,而是放入本地的 ProcessQueue, 供后续的消费者线程去消费。