JAVA面试题分享三百四十六:说说Rocketmq推模式、拉模式?

经典的推模式/拉模式

首先,明确一下业务场景

这里谈论的推拉模式,指的是 Consumer 和 Broker 之间,不是 producer与broker之间。

经典的推模式

经典的推模式,指的是消息从 Broker 推向 Consumer。

Consumer 被动的接收消息,由 Broker 来主导消息的发送。作为代理人,Broker 接受完消息之后,可以立马推送给 Consumer。

Consumer等着就行,消息会有broker主动推过来。所以 Consumer 的处理策略很简单。

推模式的缺点:Consumer可能就“消化不良/OOM”。

当 Broker 推送消息的速率大于Consumer消费速率时,Consumer可能就“消化不良”,出现内存积压,内存溢出,OOM,因为根本消费不过来啊。

所以,经典的推模式,适用于消息量不大、Consumer消费能力强的场景。

经典的拉模式

经典的拉模式,指的是 Consumer 主动向 Broker 请求拉取消息。

上面讲到,经典的推模式,适用于消息量不大、Consumer消费能力强的场景。如果Consumer消费能力弱, 那么就改变方向好了, 由推改完拉。

拉的话,主动权就在Consumer身上了, 能消化多少,吃多少。

假设当前Consumer 消化不过来、消费不过来了,它可以根据一定的策略,暂停拉取甚至停止拉取,或者间隔拉取都行。

凡事有利必有弊。

拉模式的缺点:消息延迟+消息积压。 如果Consumer 隔个 2天采取拉取一批,消息就很有可能延迟,甚至出现严重的消息延迟。而且Broker 服务端大概率会消息积压。

推拉模式,如何选型?

选择推模式的消息队列中间件,主要有ActiveMQ

选择推模式的消息队列中间件,主要有RocketMQ 和 Kafka

虽然RocketMQ 和 Kafka都选择了拉模式。也就是允许消息延迟 + 允许消息积压。

所以,选择RocketMQ 和 Kafka,就需要做好消息积压的监控。

 

Rocketmq 的推模式和拉模式

Rocketmq 的客户端,也定义了两个模式:推模式和拉模式

但是实际上,RocketMQ 中的 PushConsumer 推模式,仅仅是披着拉模式的方法,本质还是拉模式。

RocketMQ 中的 PushConsumer 推模式

接下来,我们首先看看RocketMQ 中的 PushConsumer 推模式。

一个消费者至少需要涉及队列自动负载、消息拉取、消息消费、位点提交、消费重试等几个部分。

MQClientInstance 客户端实例,会开启多个异步并行服务:

  • 负载均衡服务 rebalanceService :再平衡服务.

    专门进行 queue分区的 再平衡,再分配,然后发布拉取消息的请求 pullRequest 实例。

  • 消息拉取服务 pullMessageService:专门负责拉取消息。

    从请求队列 pullRequestQueue 队列 获取一个一个的 pullRequest,

    通过内部实现类DefaultMQPushConsumerImpl 拉取 消息。

    注意,拉取的消息,放在另一个队列 messageQueue 缓存,拉取之前,会进行流控检查,如果这个队列满了(>1000个消息或者 >100M内存) 则延迟50ms再拉取, 当然,下一次执行拉取之前,同样也会进行流控检查

  • 消息消费线程:ConsumeMessageOrderlyService  有序消息消费, 或者 并行消息。 从messageQueue  拉取消息,进行消费。

上面设计3类线程,在3类线程之间,通过两个队列进行 同步:

  • 拉取消息的请求队列 pullRequestQueue

  • 缓存消息的队列  messageQueue

Rocketmq 的推模式,本质是一种拉模式, 只是为了让客户端不会  累死, 在拉取之前进行流控。

//   接下来就是消费者的拉取流量控制,阈值为 1000个消息, 或者 100M
// 消费者消费的太慢了,broker推送的太快了,进行 Flow control

if (cachedMessageCount > this.defaultMQPushConsumer.getPullThresholdForQueue()) {

    // 将pullRequest放入队列,只不过是经过后台的定时线程池延50 ms 迟放入,进行 Flow control
    // 流量控制, 减缓拉取消息的速度
    //     * Flow control threshold on queue level, each message queue will cache at most 1000 messages by default,
    //     * Consider the {@code pullBatchSize}, the instantaneous value may exceed the limit
    //     */
    //    private int pullThresholdForQueue = 1000;

    this.executePullRequestLater(pullRequest, PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL);
    if ((queueFlowControlTimes++ % 1000) == 0) {
        log.warn(
&nbs
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

之乎者也·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值