惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
量子位
A
Arctic Wolf
L
Lohrmann on Cybersecurity
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
WordPress大学
WordPress大学
V
Vulnerabilities – Threatpost
博客园 - Franky
C
Cyber Attacks, Cyber Crime and Cyber Security
The Cloudflare Blog
Last Week in AI
Last Week in AI
The Hacker News
The Hacker News
I
Intezer
J
Java Code Geeks
P
Privacy International News Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Secure Thoughts
Cisco Talos Blog
Cisco Talos Blog
阮一峰的网络日志
阮一峰的网络日志
S
Securelist
Security Latest
Security Latest
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
小众软件
小众软件
Jina AI
Jina AI
有赞技术团队
有赞技术团队
人人都是产品经理
人人都是产品经理
博客园_首页
酷 壳 – CoolShell
酷 壳 – CoolShell
T
The Exploit Database - CXSecurity.com
雷峰网
雷峰网
T
Tenable Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Privacy & Cybersecurity Law Blog
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 【当耐特】
T
Threat Research - Cisco Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
MongoDB | Blog
MongoDB | Blog
D
DataBreaches.Net
N
News | PayPal Newsroom
Google Online Security Blog
Google Online Security Blog
K
Kaspersky official blog
H
Help Net Security
宝玉的分享
宝玉的分享
罗磊的独立博客
Webroot Blog
Webroot Blog
月光博客
月光博客
B
Blog RSS Feed
Recorded Future
Recorded Future

李锋镝的博客

LiteLLM 本地代理搭建 Claude-HUD 使用文档 Kratos+ —— Kratos 主题二次开发记录 译文:如何将单体应用拆解为微服务 codebase-memory-mcp 极简完整使用指南 Claude Haiku 4.5、Claude Sonnet 4.6、Claude Opus 4.7 区别以及各自的新特性 SchedulingConfigurer详解 踩坑60+次后,我终于搞懂 Claude Skill 怎么写才会真的触发 Everything Claude Code 详细使用文档 配置Jackson使用字段而不是getter/setter来序列化和反序列化 这个域名注册整整十年了,十年时间,真快啊 Claude Code全维度实战指南:从入门到精通,解锁AI编程新范式 Apollo配置中心中的protalDB的作用是什么 org.apache.ibatis.plugin.Interceptor类详细介绍及使用 岁末 Excel2016右键新建工作表,打开时提示“因为文件格式或文件扩展名无效。请确定文件未损坏,并且文件扩展名与文件的格式匹配。”的解决办法 wordpress增加说说功能 玩博客的人是不是越来越少了? Java 为什么有这么多 “O”? 别再背线程池的七大参数了,现在面试官都这么问 2024年11月1号 农历十月初一 我的第一个WordPress插件:Dylan Custom Plugin上线了 推荐一款比较养眼的Xshell配色方案 hnswlib installation failed 开工啦~ 阳了... MybatisCodeHelperPro激活 @Async注解的坑 新买的笔记本发货啦…… 这个中秋节感觉过的好累啊 IDEA下载源码报:Cannot connect to the Maven process. Try again later. 看病难~取药难~~ 笑死、腹肌……根本不可能有腹肌的~~ 居家办公了~ C# 11 的这个新特性,我愿称之最强! IntelliJ IDEA 2020.3.x永久白嫖(Windows/Mac) IDEA无限试用方法【2020.3最新亲测有效】 SpringBoot使用注解的方式构建Elasticsearch查询语句,实现多条件的复杂查询 UUID太长怎么办?快来试试NanoId 忽然发现,在校大学生可以免费领一年有道云笔记会员~ 醒醒~补个税了 使用itext和freemarker来根据Html模板生成PDF文件,加水印、印章 来来来,用python画一个冰墩墩儿 SpringBoot整合GraphQL入门教程 办理居住证困难重重啊! 妈呀,昨天晚上睡觉做了一晚上的梦,可累死我了 感觉Typecho很简洁啊…… WordPress的自动更新好烦啊 BeanCopier工具类(性能优化工具类) 内存屏障浅析 居住证可算是申请通过了…… 试了下壁挂炉供暖 关于重阳节 居住证签注... Spring Boot 2.x使用PostgreSQL数据库 十一节后开工头一天,修了个耳机…… 玉楼春·尊前拟把归期说 nginx反向代理配置去除前缀 1931→2021! Navicat Premium数据库账号密码解密 百度的索引量数据现在有点儿太夸张了吧? 哇塞~这个小姐姐实在太惊艳了…… 关于8月29号下午博客故障的一些记录 如何形象的描述反应式编程中的背压(Backpressure)机制? 基于Java8的Either类 海琴烟~~~ JMX监控权限认证配置 IntelliJ IDEA 2019.3.3 永久激活 破解[Windows] SpringBoot整合Elasticsearch详细步骤以及代码示例(附源码) SpringBoot整合Elasticsearch游标查询(scroll) GitLab创建新项目,初次提交命令和流程 吐槽下Google浏览器~ 从零搭建Spring Cloud Gateway网关(一) 从零搭建Spring Cloud Gateway网关(二)—— 打印请求响应日志 博客有logo啦 你的答案 数据库事务的一点简单总结 Spring Boot发展史(Spring Boot介绍) 【漫画】戏说外行对程序员的误会有多深 【收藏】从面试官角度观察到的程序员技能瓶颈,同时给出突破瓶颈的建议 Git中.gitignore文件不起作用的解决办法 背影 - 朱自清 jmap命令(jdk1.8) 彻底搞懂mysql日志系统binlog,redolog,undolog 出院了~~~ linux中ftp查看不到文件列表的问题 PHP版本怎么更新啊…… 成语接龙 StarUML4.0破解文件 Java SPI详解 WordPress评论框增加自定义表情 因在公司上不正经网站,我没过试用期… 优化了MYSQL大量写入问题,老板奖励了1000块给我 不慌不忙的坚强(林徽因39段最美文字!) ConcurrentHashMap常用方法源码解析(jdk1.8) 我是如何失去团队掌控的? HBASE填坑日志 关闭apache httpclient4.5 DEBUG日志 使用OpenShift搭建k8s集群 SonarQube Scanner的配置与使用简介
RocketMQ的push消费方式实现详解
李锋镝 · 2022-08-09 · via 李锋镝的博客

MQ消费方式

消费方式就是指消费者如何从MQ中获取到消息,分为两种方式,push(推方式)和pull(拉方式)。

1、push(推方式)

push,顾名思义,就是推的意思。就是当MQ收到生产者产生的消息的时候,会主动将消息推送到消费者进行消费,这种模式就叫push,也就是MQ将消息推给到消费者的意思。

自动草稿push模式

push这种模式的好处就是响应快,消息的实时性比较高,一旦消息MQ收到消息,那么就能立马将消息推送给消费者,消费者也就能立马收到消息进行消费。

但是这种push的模式,有个缺点就是一旦消息量比较大时,对消费者性能要求比较高,因为是消费者无法控制MQ消息的推送速度,一旦消息量大,那么消费者消费消息的压力就比较大。

2、pull(拉方式)

push是MQ主动给消费者推消息,那么pull呢?刚好跟push相反,就是消费者主动去MQ中拉取消息。

自动草稿pull模式

那么pull的优缺点自然也就跟push刚好相反。因为是消费者主动去MQ中拉取消息,那么消费者可根据自身消费的情况,决定何时去拉取消息,主动权在自己手上,这样消费者的压力就会相对小点;但是缺点也很明显,那么就会实时性相对于push方式会低一些,因为你得决定拉的时间间隔。

其实想想,消费方式就跟拿快递一样,快递就是一个消息,我自己就是消费者,快递要么快递小哥主动送(push)到家,要么我自己去快递站拿(pull)。

上一节说了消费消息的两种方式push和pull,或者说算一种理念。尚大的周阳老师有一句经常说的话我比较赞同,那就是“天上飞的理念,必然有落地的实现”。所以push或者pull到底如何落地,得看具体的MQ的产品了。

而RocketMQ作为阿里开源的一款高性能、功能丰富的MQ,自然同时实现了push和pull的两种消费方式,用户可以选择在项目中使用push还是pull。

自动草稿push模式的实现自动草稿pull模式的实现

但是一般情况下,项目中都是使用push的方式来消费,因为pull除了时实性差外,pull方式还得让开发人员主动去维护消息消费进度,增加额外的操作。

所以接下来就着重讲一下RocketMQ是如何实现push的逻辑。

RocketMQ聪明地实现push的原因

上文说到push模式的优点是时实性好,但是缺点就是消费者压力会比较大,所以,难道实现push模式,只能舍弃压力的控制么?

就在这时,RocketMQ大喊了一声

自动草稿

是的,RocketMQ对于push模式做到了实时和压力的平衡,这主要是因为RocketMQ的push模式其实算是一个“伪push”模式,真正底层的实现还是基于pull。

到这里可能有的小伙伴比较迷糊,怎么push变成“伪push”了,还是用pull实现的,到底是push还是pull?

自动草稿

前面我说过,push和pull只是一种理论,具体的实现看MQ。

所以RocketMQ为了兼顾两者,就选择通过消费者主动拉消息来实现push的效果,这也是为什么我称为“伪push”的原因,RocketMQ都给封装好了,让你用起来感觉是MQ主动push消息给你的。

既然底层是pull,那么RokcetMQ在实现消费者的逻辑的时候,就可以很容易实现控制压力的效果,毕竟这是“拉”方式天然自带的buff;但是如何通过pull实现push的时实的优点呢?毕竟鱼和熊掌我RokcetMQ偏要兼得。

这时这就不得不提到一种叫“长轮询”的机制。

轮询与长轮询

轮询与长轮询都属于pull的实现,都是由客户端主动给服务端发送请求,拉取数据。套到MQ中,就是都是消费者主动去MQ拉消息。

轮询

轮询是指不管服务端数据有无更新,客户端每隔定长时间请求拉取一次数据,可能有更新数据返回,也可能什么都没有。

自动草稿

再拿快递举例子,轮询就好比,小明买的iphone 13 pro max快递到了,显示正在派送中,但是小明等不及了,于是就去快递站拿,但是快递还没放到快递站,但是小明的心里急啊,他忍受不了相思之苦,于是小明每隔5分钟就往快递站跑一次,问一下快递到了没,到了就拿回来。这就是轮询的意思,也就是不论有没有数据,客户端都会每隔一定时间去请求一次服务端。

来分析一下拿快递的例子的问题:

  • 每隔5分钟就往快递站跑,那不是累死个小明么。
  • 还有一个问题,假设刚跑到快递站,快递没到,就回去了,但是刚到家的时候,快递到了,于是又等了5分钟,再去快递站终于拿到快递了,但是其实快递都到了几分钟了,你还是没有第一时间拿到快递,这就造成了延迟。

从而对应到程序中,就是会产生如下问题

  • 对于消息而言,会一直产生,这就要求消费者不停地间隔一定时间去拉取消息,即使没有消息也需要去请求,就会造成大量无用的请求,白白浪费大量耗费服务器内存和宽带资源。
  • 可能造成数据的延迟

长轮询

说长轮询概念之前,先来救救小明吧,毕竟小明可不想狗带。

既然原先小明每隔5分钟跑一次,那么是不是可以换种思路,当快递还没到的时候,让小明不要回来,直接在快递站待着,当快递到的时候,才让小明拿着快递回家。这下小明就喜死了,既可以有时间刷刷某音,逛逛某东,还可以在第一时间拿到13 pro max。

自动草稿

所以这种可以在快递站等待的机制,就叫长轮询。

长轮询也是客户端请求服务端,如果服务端有数据,那么就立马返回,客户端再次请求;当服务端不存在数据的时候,服务端并不会给客户端响应,而是将请求给hold住,当服务端有数据的时候才会给客户端响应,返回数据。

所以长轮询可以解决如下问题

  • 解决轮询带来的频繁请求服务端但是没有的问题
  • 一旦新的数据到了,那么消费者能立马就可以获取到新的数据,所以从效果上,有点像是push的感觉。

但是长轮询也会带来服务端代码实现逻辑复杂的问题,当然相比于优点来说,都不太重要。

push消费方式源码探究

理论都讲完了,接下来就到了show me the code的时间了,来看看RocketMQ的是如何通过长轮询机制来实现压力和时实的平衡。

这里我画了一张push模式下消费者消费流程图。

自动草稿消费者拉取消息的逻辑

  • ①消费者有一个后台线程,会去处理拉取消息(PullRequest)
  • ②先去判断有没有过多消息没有消费,如果有的话,那么就间隔一定时间再次从①开始执行拉取消息的逻辑
  • ③消费者没有过多消息没有消费,那么就会直接向MQ发送拉取消息的请求,有消息就返回,没有消息就hold住请求,等有新的消息到的时候才返回
  • ④消费者获取到消息之后,会去找用户自定义的消息处理逻辑的实现(MessageListener的实现)去消费消息,同时会再次拉取消息,继续从①开始执行逻辑

1、消费者拉取消息控制压力源码

当消费者准备去拉消息的时候,会先去判断当前消费者消费的压力再决定是否去拉取消息。

RocketMQ提供了两种判断消费压力逻辑,一种是基于还未消费的消息的数量的大小,还有一种是基于还未消费的消息所占内存的大小。

自动草稿控制压力源码

  • 判断还未消费消息的数量,数量太多就等会再执行重新执行拉取消息的逻辑
  • 判断还未消费消息的大小,如果还未消息的消息占用的内存过大,就等会再执行重新执行拉取消息的逻辑

总的一句话就是,当消费者消费的压力过大时,就不会去拉取消息,而是等待一定的时间再去执行拉取消息的逻辑,如果压力还是很大,就还继续等,如此循环,直到消费者的消费压力小于阈值的时候,才会真正的发送请求到MQ中拉取消息。

2、MQ将请求hold住源码

当服务端未找到消息时,就将请求进行挂起,存起来

自动草稿请求hold住源码

拉取不到消息时,会调用PullRequestHoldService的suspendPullRequest方法讲请求存储起来。PullRequestHoldService是用来存储拉取请求的类。

自动草稿PullRequestHoldService

suspendPullRequest方法会将请求分类,放到ManyPullRequest里,然后用一个ConcurrentHashMap进行存储

3、MQ收到消息响应给消费者的源码

自动草稿NotifyMessageArrivingListener

当生产者发送的消息达到MQ的时候,MQ会回调NotifyMessageArrivingListener的arriving方法,之后就会调用PullRequestHoldService的notifyMessageArriving方法,MQ会重新处理拉取消息的逻辑,此时就能找到最新来的那条消息,从而将最新的消息通过网络返回给消费者。

自动草稿notifyMessageArriving和返回消息逻辑

最后

所以从以上的分析可以看出,RocketMQ对于push的消费方式的实现是基于长轮询机制来实现的,同时平衡了时实和压力,这其实就很nice了。

最后我想说一句,其实不论是pull还是push,又或是轮询和长轮询,其实都是一种理论或者说是一种思想,不单单是MQ的东西,就比如在Nacos中,也使用了push和长轮询机制。但是这些理论在不同产品的具体实现,实现方式可能不太一样,但都是大同小异,所以当你懂了这些思想,再看其它框架的源码,其实就很容易了。

原文链接:https://www.cnblogs.com/zzyang/p/16565620.html

除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.lifengdi.com/transport/technology/3937