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

目录

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

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

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

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

 
 

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

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

\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模型不会等待消费者是否消费完成前一个消息,就会发送第二个消息)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容

  • “概念”其本身也是一个概念,是一个很抽象的词,它不像猫或狗等实物,你能看得见摸得着,在生活中往往被很多人忽视了,没...
    思道明理阅读 911评论 0 3
  • 位于佛山的亚洲艺术公园,是以岭南水乡为突出特征的文脉,以水上森林为突出特征的绿脉以及以龙舟竞渡为突出特征的水脉,彰...
    默默Elain阅读 506评论 2 3
  • 这是校园时光的落幕,也是社会舞台的揭幕;这是青春一群人的散场,也是成年后一个人的遇见,遇见未知的自己,未知或好、或...
    赵大仙儿666阅读 510评论 0 1