前言简介
Rocketmq使用长轮询的方式实现了push功能。其实可以说是pull模式的一种例外场景 主要包括几个组件:
-
DefaultMQPushConsumerImpl:拉消息的类型。
-
ProcessQueue:保存拉出来的消息。
-
PullMessageService:执行拉消息服务。
-
ConsumeMessageService:消费消息服务。
-
ReblanceService:负载均衡服务。
push执行流程: www.processon.com/view/link/6…
但由于push模式采用长轮训的方式实现,所以在大流量的情况下会出现消息处理繁忙的情况,这种情况怎么避免呢? 下面来谈谈
流控是怎么实现的
push 模式执行细节: www.processon.com/view/link/6…
流控的目的:防止拉的太快,消费的太慢。主要从三个方面检测:
-
从某个消费队列拉取的等待消费的消息数量。如果超过阀值,延迟50ms后再次拉取消息。阀值默认是1000。如果设置了topic级别的阀值(默认没有限制),在队列负载均衡以后会重新计算,具体为topic级别的阀值除以当前负责的消费队列数量。主要配置变量:
DefaultMQPushConsumerImpl.pullThresholdForQueue和DefaultMQPushConsumerImpl.pullThresholdForTopic。 -
从某个消费队列拉取的等待消费的消息大小(只考虑body)。同样,超过阀值就会延迟50ms后再次拉取消息。阀值默认是100M。如果topic设置了级别(默认没有限制),队列负载均衡以后会重新计算队列的限制,具体为topic级别的阀值除以当前负责的消费队列数量。主要配置变量:
DefaultMQPushConsumerImpl.pullThresholdSizeForQueue和DefaultMQPushConsumerImpl.pullThresholdSizeForTopic。 -
在并发消费模式下,从某个消费队列拉取的等待消费的消息中,在消费队列中的最大位置和最小位置之间差别。如果超过阀值,也会延迟50ms后再拉取消息。默认是2000,这里可能会存在误判。因为,有条件拉取消息的时候,是有可能出现同一个消费队列中拉到的两个消息在队列中的位置距离很远。
需要思考的点:
NO_NEW_MSG/NO_MATCHED_MSG即没有新消息或待匹配消息的情况下,correctTagsOffset的逻辑为什么需要考虑有没有消息?如果还有消息说明本地还没有消息没被消费,此时更新的offset是服务端返回的,存在比没有被消费的消息偏移量大的情况。OFFSET_ILLEAGL即offset不完整的情况下为什么要过10s以后才去更新offsetstore,保存offset,在reblance中移除process queue中的消息?出现这个问题是因为NO_MATCHED_LOGIC_QUEUE/NO_MESSAGE_IN_QUEUE/OFFSET_OVERFLOW_BADLY/OFFSET_TOO_SMALL这四种情况,而这些情况可能发生在服务端在恢复数据的时候,因此考虑是暂停消费这个队列。如果drop之后不延迟,就会有可能又去拉取消息了。