美文网首页kafka消息中间件
聊聊消息中间件Push模型和Pull模型优缺点

聊聊消息中间件Push模型和Pull模型优缺点

作者: longxingxiu | 来源:发表于2019-03-17 11:22 被阅读60次

目录

一 、常用消息中间件支持模型
二、消费端Push模型优缺点
三、消费端Pull模型优缺点
四、两种模型在实际场景中的优缺点分析
五、常见消息中间Push和Pull实现实战和客户端源码分析

这篇文章前,先抛出个问题

  • 1 所谓的推拉模型仅仅是指消费端模型吗?是否需要broker支持这种模型呢?

当然不是,如果没有服务端Broker支持,它如何知道消费端当前选取的消息消费模型,准确讲推拉模型是指消息的消费模型,需要服务端Broker支持,也需要消费端Client支持。(通常服务端Broker和消费端Client都是互相配合工作的,一起开发,一起作用的)。

 
 

一、常用消息中间件支持模型

中间件 push模型 pull模型
RabbitMQ 支持 支持
Kafka --- 支持(只有)
RabbitMQ 支持 支持

\color{red}{我们通常所说的push模型和pull模型都是指的消息的消费模型。}

二、两种模型优缺点对比

Push 和 Pull 的区别

  • 所谓 Push 模型,即当 Producer 发出的消息到达后,服务端马上将这条消息投递给 Consumer;
  • 而 Pull 则是服务端收到这条消息后什么也不做,只是等着 Consumer 主动到自己这里来读,即 Consumer 这里有一个“拉取”的动作。

举个例子:
消息=食物;服务端Broker=老爸;消费端 = 儿子

  • 如果采用Push模型:
    优点:老爸一拿到食物就给儿子吃【食物送达及时】
    缺点:儿子已经吃跑了,老爸还强塞儿子吃,可能导致儿子被撑死【儿子不堪重负,撑死了】

  • 如果采用Pull模型
    优点:儿子饿了,主动找老爸要食物,不饿的时候不要。【儿子根据饥饿程度获取食物】
    缺点:儿子饿了,发消息给老爸给我点食物,等老爸收到消息已经过了十分钟了,儿子等不及了饿死了。【食物没有及时送给儿子】

\color{red}{所以说两种模型各有利弊,根据业务需求和实际业务量来选择。}

Push模型优缺点

  • Push模型优点
    实时(因为服务端Broker一旦收到消息,就会发送给消费者,不管消费这准备好没有,消费者是死是活,缓存到消费端的BlockingQueue中

  • Push缺点
    [1]、消息保存在服务端broker,容易造成消息堆积。(如何理解呢?为什么会存在服务端呢? 因为服务端Broker在和消费端第一次建立通信时就明确了该消费者的消费喜好,他选择的就是Push模型,那就不管三七二十一都发给你的缓存队列中去)。
    [2]、服务端broker需要维护每次传输状态,遇到问题需要重试。(如何理解,为什么push模型broker要维护传输状态?Pull模型不需要吗?)
    [3]、服务端broker需要依据订阅者消费能力做流控(流转机制)。(这个好理解,消费能力差时就不能疯狂塞消息给消费端,流转机制怎么做呢? RabbitMQ的做法是可以在消费者新建时,设置Qos,对服务端Borker提前表明消费端的消费能力,这样服务端最多推送指定数量的消息给消费者。)

Pull模型优缺点

  • Pull模型优点
    [1] 保存在消费端,获取消息方便。(什么保存在消费端
    [2] 传输失败,不需要重试。(如何理解?
    [3] 消费端可以根据自身消费能力决定是否pull(流转机制) (这个好理解

  • Pull缺点
    默认的端短询方式的实时性依赖于pull间隔时间,间隔越大,实时性越低,长轮询方式和push一致。(默认的端轮训指的是什么? 指的当长时间没有消息时,消费端实现的间隔时间去服务端轮训消息的过程)

三、两种模型在实际场景中的优缺点分析

选择 Push 还是 Pull

简要分析下 Push 和 Pull模型,在不同场景下各自存在的利弊。

场景 1:Producer 的速率大于 Consumer 的速率

对于 Producer 速率大于 Consumer 速率的情况,有两种可能性需要讨论:

  • 第一种是Producer 本身的效率就要比 Consumer 高(比如说,Consumer 端处理消息的业务逻辑可能很复杂,或者涉及到磁盘、网络等 I/O操作);
  • 另一种则是 Consumer 出现故障,导致短时间内无法消费或消费不畅。

Push方式由于无法得知当前 Consumer 的状态(\color{red}{Push模型不管消费者有没有消费,都会往消费订阅者推动并缓存到消费者队列中}),所以只要有数据产生,便会不断地进行推送,在以上两种情况下时,可能会导致 Consumer 的负载进一步加重,甚至是崩溃(比如生产者是 flume 疯狂抓日志,消费者是 HDFS+hadoop,处理效率跟不上)。除非Consumer 有合适的反馈机制能够让服务端知道自己的状况。(也可以 通过消费端限流方案,比如RabbitMQ消费者设置Qos,服务端Borker就会限制对消费端的发送流程,但是这个流量设置就需要衡量,不能太大也不能太小)

而采取 Pull 的方式问题就简单了许多,由于 Consumer 是主动到服务端拉取数据,此时只需要降低自己访问频率就好了。举例:如前端是 flume 等日志收集业务,不断往 CMQ 生产消息,CMQ 往后端投递,后端业务如数据分析等业务,效率可能低于生产者。

场景 2:强调消息的实时性

  • 采用 Push 的方式时,一旦消息到达,服务端即可马上将其推送给服务端,这种方式的实时性显然是非常好的;
  • 而采用 Pull 方式时,为了不给服务端造成压力(尤其是当数据量不足时,不停的轮询显得毫无意义),需要控制好自己轮询的间隔时间,但这必然会给实时性带来一定的影响。(Pull不会频繁拉取,设置一定间隔)。

场景 3:Pull 的长轮询

Pull 模式有什么问题呢?由于主动权在消费方,消费方无法准确地决定何时去拉取最新的消息。如果一次 Pull 取到消息了还可以继续去 Pull,如果没有 Pull 取到消息则需要等待一段时间再重新 Pull。

但等待时间就很难判定了。你可能会说,我可以有xx 动态拉取时间调整算法,但问题的本质在于,有没有消息到来这件事情决定权不在消费方。也许 1 分钟内连续来了 1000 条消息,然后半个小时没有新消息产生,可能你的算法算出下次最有可能到来的时间点是31分钟之后,或者 60 分钟之后,结果下条消息 10 分钟后到了,是不是很让人沮丧?

当然也不是说延迟就没有解决方案了,业界较成熟的做法是从短时间开始(不会对 CMQ broker 有太大负担),然后指数级增长等待。比如开始等 5ms,然后 10ms,然后 20ms,然后 40ms……直到有消息到来,然后再回到 5ms。即使这样,依然存在延迟问题:假设 40ms 到 80ms 之间的 50ms 消息到来,消息就延迟了 30ms,而且对于半个小时来一次的消息,这些开销就是白白浪费的。

总之就是消费端长时间没有消息消费的话,消费端轮训时间间隔如果太长,可能在轮训间隔中让部分消息延时消费,如果轮训时间太短,则频繁的请求在消耗服务端Broker,broker要应答消费端的请求(线程开销等)而造成服务端Broker的负担。

在腾讯云的 CMQ 里,有一种优化的做法-长轮询,来平衡 Pull/Push 模型各自的缺点。

基本方式是:消费者如果尝试拉取失败,不是直接 return,而是把连接挂在那里 wait,服务端如果有新的消息到来,把连接拉起,返回最新消息。

场景 4:部分或全部 Consumer 不在线

在消息系统中,Producer 和 Consumer 是完全解耦的,Producer 发送消息时,并不要求Consumer 一定要在线,对于 Consumer 也是同样的道理,这也是消息通信区别于 RPC 通信的主要特点;但是对于 Consumer不在线的情况,却有很多值得讨论的场景

  • 首先,在 Consumer 偶然宕机或下线的情况下,Producer 的生产是可以不受影响的,Consumer 上线后,可以继续之前的消费,此时消息数据不会丢失;但是如果 Consumer 长期宕机或是由于机器故障无法再次启动,就会出现问题,即服务端需不需要为 Consumer 保留数据,以及保留多久的数据等等。(消费端宕机,服务端Broker数据堆积)

  • 采用 Push 方式时,因为无法预知 Consumer 的宕机或下线是短暂的还是持久的,如果一直为该 Consumer 保留自宕机开始的所有历史消息,那么即便其他所有的 Consumer 都已经消费完成,数据也无法清理掉,随着时间的积累,队列的长度会越来越大,此时无论消息是暂存于内存还是持久化到磁盘上(采用 Push 模型的系统,一般都是将消息队列维护于内存中,以保证推送的性能和实时性,这一点会在后边详细讨论),都将对 MQ 服务端造成巨大压力,甚至可能影响到其他 Consumer 的正常消费,尤其当消息的生产速率非常快时更是如此;但是如果不保留数据,那么等该 Consumer 再次起来时,则要面对丢失数据的问题。

折中的方案是:MQ 给数据设定一个超时时间,当 Consumer 宕机时间超过这个阈值时,则清理数据;但这个时间阈值也并太容易确定。

  • 在采用 Pull 模型时,情况会有所改善;服务端不再关心 Consumer 的状态,而是采取“你来了我才服务”的方式,Consumer 是否能够及时消费数据,服务端不会做任何保证(也有超时清理时间)。

参考文章:
1 、选择 Push 还是 Pull(腾讯消息中间件CMQ技术文档)
2、 RabbitMQ之Consumer消费模式(Push & Pull)(厮大文章,抓包说明Push模型不会等待消费者是否消费完成前一个消息,就会发送第二个消息)。

相关文章

  • 聊聊消息中间件Push模型和Pull模型优缺点

    目录 一 、常用消息中间件支持模型二、消费端Push模型优缺点三、消费端Pull模型优缺点四、两种模型在实际场景中...

  • Push or Pull?

    采用Pull模型还是Push模型是很多中间件都会面临的一个问题。消息中间件、配置管理中心等都会需要考虑Client...

  • 消息队列的pull与push

    采用Pull模型还是Push模型是很多中间件都会面临的一个问题。消息中间件、配置管理中心等都会需要考虑Client...

  • 中间件-MetaQ

    MetaQ是一款分布式、队列模型的消息中间件。基于发布订阅模式,有Push和Pull两种消费方式,支持严格的消息顺...

  • NSQ学习:流控的实现

    消息中间件的pull与push 消息中间件的实现无非两种套路,一种让客户端pull,典型的比如kafka便是如此,...

  • 消息中间件的模型总结

    推拉模型 首先推拉模型是针对 消息中间件的实现和策略,而非客户端及调用方。 推模型: 是有中间件将消息主动推送给...

  • RocketMQ消费者

    官方文档 概要 MQ中Pull和Push的两种消费方式 Push方式:由消息中间件主动地将消息推送给消费者;采用P...

  • 阿里资深架构师带你认识,MetaQ 消息中间件

    MetaQ MetaQ 是一款分布式、队列模型的消息中间件。分为 Topic 与 Queue 两种模式,Push ...

  • kafka和flume的区别与

    (1)kafka和flume都是日志系统。kafka是分布式消息中间件,自带存储,提供push和pull存取数据功...

  • 消息中间件push和pull模式

    一、概念 MQ的消费模式分两种:push和pull。 所谓push就是服务端主动推送消息给客户端,而pull则是客...

网友评论

    本文标题:聊聊消息中间件Push模型和Pull模型优缺点

    本文链接:https://www.haomeiwen.com/subject/yfmemqtx.html