RocketMQ 5.0 无状态实时性消费详解

作者:绍舒

背景

RocketMQ 5.0 版本引入了 Proxy 模块、无状态 pop 消费机制和 gRPC 协议等创新功能,同时还推出了一种全新的客户端类型:SimpleConsumer。

SimpleConsumer 客户端采用了无状态的 pop 机制,彻底解决了在客户端发布消息、上下线时可能出现的负载均衡问题。然而,这种新机制也带来了一个新的挑战:当客户端数量较少且消息数量较少时,可能会出现消息消费延时的情况。

在当前的消息产品中,消费普遍使用了长轮询机制,即客户端向服务端发送一个超时时间相对较长的请求,该请求会一直挂起,除非队列中存在消息或该请求到达设定的长轮询时间。

然而,在引入 Proxy 之后,目前的长轮询机制出现了一个问题。客户端层面的长轮询和 Proxy 与 Broker 内部的长轮询之间互相耦合,也就是说,一次客户端对 Proxy 的长轮询只对应一次 Proxy 对 Broker 的长轮询。因此,在以下情况下会出现问题:当客户端数量较少且后端存在多个可用的 Broker 时,如果请求到达了没有消息的 Broker,就会触发长轮询挂起逻辑。此时,即使另一台 Broker 存在消息,由于请求挂在了另一个 Broker 上,也无法拉取到消息。这导致客户端无法实时接收到消息,即 false empty response。

这种情况可能导致以下现象:用户发送一条消息后,再次发起消费请求,但该请求却无法实时拉取到消息。这种情况对于消息传递的实时性和可靠性产生了不利影响。

AWS 的文档里也有描述此等现象,他们的解决方案是通过查询是所有的后端服务,减少 false empty response。

在这里插入图片描述

其他产品

在设计方案时,首先是需要目前存在的消息商业化产品是如何处理该问题的。

MNS 采取了以下策略,主要是将长轮询时间切割为多个短轮询时间片,以尽可能覆盖所有的 Broker。

首先,在长轮询时间内,会对后端的 Broker 进行多次请求。其次,当未超过短轮询配额时,优先使用短轮询消费请求来与 Broker 进行通信,否则将使用长轮询,其时间等于客户端的长轮询时间。此外,考虑到过多的短轮询可能会导致 CPU 和网络资源消耗过多的问题,因此在短轮询超过一定数量且剩余时间充足时,最后一次请求将转为长轮询。

然而,上述策略虽以尽可能轮询完所有的 Broker 为目标,但并不能解决所有问题。当轮询时间较短或 Broker 数量较多时,无法轮询完所有的 Broker。即使时间足够充足的情况下,也有可能出现时间错位的情况,即在短轮询请求结束后,才有消息在该 Broker 上就绪,导致无法及时取回该消息。

解法

技术方案

首先,需要明确该问题的范围和条件。该问题只会在客户端数量较少且请求较少的情况下出现。当客户端数量较多且具备充足的请求能力时,该问题不会出现。因此,理想情况是设计一个自适应的方案,能够在客户端数量较多时不引入额外成本来解决该问题。

为了解决该问题,关键在于将前端的客户端长轮询和后端的 Broker 长轮询解耦,并赋予 Proxy 感知后端消息个数的能力,使其能够优先选择有消息的 Broker,避免 false empty response。

考虑到 Pop 消费本身的无状态属性,期望设计方案的逻辑与 Pop 一致,而不在代理中引入额外的状态来处理该问题。

另外,简洁性是非常重要的,因此期望该方案能够保持简单可靠,不引入过多的复杂性。

  1. 为了解决该问题,本质上是要将前端的客户端长轮询和后端的 Broker 长轮询解耦开来,并赋予 Proxy 感知后端消息个数的能力,能够优先选择有消息的 Broker,避免 false empty response。
  2. 由于 Pop 消费本身的无状态属性,因此期望该方案的设计逻辑和 Pop 一致,而不在 Proxy 引入额外的状态来处理这个事情。
  3. Simplicity is ALL,因此期望这个方案简单可靠。

我们使用了 NOTIFICATION,可以获取到后端是否有尚未消费的消息。拥有了上述后端消息情况的信息,就能够更加智能地指导 Proxy 侧的消息拉取。

通过重构 NOTIFICATION,我们对其进行了一些改进,以更好地适应这个方案的要求。

pop with notify

一个客户端的请求可以被抽象为一个长轮询任务,该轮询任务由通知任务和请求任务组成。

通知任务的目的是获取 Broker 是否存在可消费的消息,对应的是 Notification 请求;而请求任务的目的是消费 Broker 上的消息,对应的是 Pop 请求。

首先,长轮询任务会执行一次 Pop 请求,以确保在消息积压的情况下能够高效处理。如果成功获取到消息,则会正常返回结果并结束任务。如果没有获取到消息,并且还有剩余的轮询时间,则会向每个 Broker 提交一个异步通知任务。

在任务通知返回时,如果不存在任何消息,长轮询任务将被标记为已完成状态。然而,如果相关的 Broker 存在消息,该结果将被添加到队列中,并且消费任务将被启动。该队列的目的在于缓存多个返回结果,以备将来的重试之需。对于单机代理而言,只要存在一个通知结果返回消息,Proxy 即可进行消息拉取操作。然而,在实际的分布式环境中,可能会存在多个代理,因此即使通知结果返回消息存在,也不能保证客户端能够成功拉取消息。因此,该队列的设计旨在避免发生这种情况。

在这里插入图片描述

消费任务会从上述队列中获取结果,若无结果,则直接返回。这是因为只有在通知任务返回该 Broker 存在消息时,消费任务才会被触发。因此,若消费任务无法获取结果,可推断其他并发的消费任务已经处理了该消息。

消费任务从队列获取到结果后,会进行加锁,以确保一个长轮询任务只有一个正在进行的消费任务,以避免额外的未被处理的消息。

在这里插入图片描述

如果获取到消息或长轮询时间结束,该任务会被标记完成并返回结果。但如果没有获取到消息(可能是其他客户端的并发操作),则会继续发起该路由所对应的异步通知任务,并尝试进行消费。

自适应切换

考虑到当请求较多时,无需采用 pop with notify 机制,可使用原先的 pop 长轮询 broker 方案,但是需要考虑的是,如何在两者之间进行自适应切换。目前是基于当前 Proxy 统计的 pop 请求数做判断,当请求数少于某一值时,则认为当前请求较少,使用 pop with notify;反之则使用 pop 长轮询。

由于上述方案基于的均为单机视角,因此当消费请求在 proxy 侧不均衡时,可能会导致判断条件结果有所偏差。

Metric

为了之后进一步调优长轮询和观察长轮询的效果,我们设计了一组 metric 指标,来记录并观测实时长轮询的表现和损耗。

  1. 客户端发起的长轮询次数 (is_long_polling)
  2. pop with notify 次数 (通过现有 rpc metric 统计)
  3. 首次 pop 请求命中消息次数 (未触发 notify) (is_short_polling_hit)

使用方式

在使用时需明确长轮询和短轮询的区分,可以参考 AWS 的定义,当轮询时间大于 0 时,长轮询生效。

在这里插入图片描述

可以看到需明确一个长轮询最小时间,因为长轮询时间过小时无意义,AWS 的最小值采取了 1 秒。

在这里插入图片描述

在目前版本的 Apache RocketMQ 服务端中,采用了最小 5 秒的限制,即需超过 5 秒才能触发长轮询,该值可在 ProxyConfig#grpcClientConsumerMinLongPollingTimeoutMillis 中配置或修改。

对于 SimpleConsumer 而言,可以通过 awaitDuration 字段来调整长轮询时间。

SimpleConsumer consumer = provider.newSimpleConsumerBuilder().setClientConfiguration(clientConfiguration).setConsumerGroup(consumerGroup)// set await duration for long-polling..setAwaitDuration(awaitDuration).setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression)).build();

总结

通过如上方案,我们成功设计了一套基于无状态消费方式的实时消费方案,在做到客户端无状态消费的同时,还能够避免 false empty response,保证消费的实时性,同时,相较于原先 PushConsumer 的长轮询方案,能够大量减少用户侧无效请求数量,降低网络开销。

RocketMQ 学习社区体验地址

RocketMQ 学习社区重磅上线!AI 互动,一秒了解 RocketMQ 功能源码。RocketMQ 学习社区是国内首个基于 AIGC 提供的知识服务社区,旨在成为 RocketMQ 学习路上的“贴身小二”。

PS:RocketMQ 社区以 RocketMQ 5.0 资料为主要训练内容,持续优化迭代中,回答内容均由人工智能模型生成,其准确性和完整性无法保证,且不代表 RocketMQ 学习社区的态度或观点。
立即体验 RocketMQ 学习社区(建议 PC 端体验完整功能):https://rocketmq-learning.com/

为了帮助用户更全面的了解 RocketMQ 5.0,同时收集更多反馈,**「寻找 RocketMQ 首席评测官」**活动惊喜上线!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WRUz4bGL-1690130818194)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/df4c1c35104e46c086cbd7f6bdc7c5aa~tplv-k3u1fbpfcp-zoom-1.image “image”)]

点击此处,即可报名参加!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/7277.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT字节数组类QByteArray

QT字节数组类QByteArray 初始化访问某个元素截取字符串获取字节数组的大小数据转换与处理Hex转换数值转换与输出 字母大小写转换字符串数值转化为各类数值QBQyteArray和char*互转QByteArray 和std::string互转与字符串QString互转QByteArray和自定义结构体之间的转化判断是否为…

区块链实验室(11) - PBFT耗时与流量特征

以前面仿真程序为例,分析PBFT的耗时与流量特征。实验如下,100个节点构成1个无标度网络,节点最小度为5,最大度为38. 从每个节点发起1次交易共识。统计每次交易的耗时以及流量。本文所述的流量见前述仿真程序的说明:区块链实验室(3)…

13.4.2 【Linux】sudo

相对于 su 需要了解新切换的使用者密码 (常常是需要 root 的密码), sudo 的执行则仅需要自己的密码即可。sudo 可以让你以其他用户的身份执行指令 (通常是使用 root 的身份来执行指令),因此并非所有人都能够…

AcWing 1210. 连号区间数

输入样例1: 4 3 2 4 1输出样例1: 7输入样例2: 5 3 4 2 5 1输出样例2: 9样例解释 第一个用例中,有 77 个连号区间分别是:[1,1],[1,2],[1,3],[1,4],[2,2],[3,3],[4,4][1,1],[1,2],[1,3],[1,4],[2,2],[3,3…

Linux系统知识1—Linux命令基础格式,什么是命令,命令行,ls命令入门,ls命令的参数和选项,-a,-l -h选项的使用及组合使用

一.什么是命令,命令行 .命令行:即 Linux 终端( Terminal ),是一种命令提示符页面。以纯"字符"的形式操作系统,可以使用各种字符化命令对系统发出操作指令。 .命令:即 Lin…

redis(9):spring里面使用redis

1 创建一个mave项目 自行创建一个maven项目 2 修改pom.xml <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.7</maven.compiler.source><maven.compiler.target>1.7</maven…

SpringMVC

文章目录 一.SpringMVC的概念1.1 Spring的概念1.2 MVC和SpringMVC的关系 二.SpringMVC步骤2.1 创建一个springMVC项目2.2 获取参数的功能2.3 输出参数的功能 三.SpringMVC的注解介绍3.1 获取参数3.1.1 获取参数单个参数3.1.2 获取多个参数3.1.3获取对象3.1.4 获取json对象3.1.5…

深度学习常用优化器总结,具详细(SGD,Momentum,AdaGrad,Rmsprop,Adam,Adamw)

学习需要&#xff0c;总结一些常用优化器。 目录 前言SGD&#xff1a;随机梯度下降BGD&#xff1a;批量梯度下降MBGD&#xff1a;小批量梯度下降MomentumAdaGradRMSpropAdam: Adaptive Moment EstimationAdamW参考文章 前言 优化器的本质是使用不同的策略进行参数更新。常用的…

【C++】多态

一、多态的概念 多态&#xff0c;顾名思义就是多种状态。 多态概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同的状态。 举个例子:比如买票这个行为&#xff0c;当普通人买票时&#xff…

【PostgreSQL内核学习(八)—— 查询执行(查询执行策略)】

查询执行 查询执行概述查询执行策略可优化语句和数据定义语句四种执行策略策略选择实现Portal执行的过程 声明&#xff1a;本文的部分内容参考了他人的文章。在编写过程中&#xff0c;我们尊重他人的知识产权和学术成果&#xff0c;力求遵循合理使用原则&#xff0c;并在适用的…

基于LoRA微调部署Stable Diffusion【免费试用阿里云】

文章目录 Stable Diffusion介绍环境及资源准备过程注交互式建模&#xff08;PAI-DSW&#xff09;的试用在创建的工作空间中创建实例安装 Diffusers Stable Diffusion介绍 Stable Diffusion 是一种文本到图像的潜在扩散模型&#xff0c;由 Runway 和慕尼黑大学合作构建&#xf…

vue开发环境搭建指南

nodejs下载和安装 从nodejs官网下载nodejs安装版本(愿配置环境变量的可以下载zip版本,解压,添加path环境变量) 在命令行里运行 node -v显示如下版本,则安装成功 10.15.3 #vue-cli3安装 在命令行里运行 npm i -g @vue/cli查看版本号 vue -V显示如下版本,则安装成功 3…

微信小程序反编译

PC--微信小程序反编译 小程序反编译工具&#xff1a; 免责声明&#xff1a;不得将小程序反编译源码程序和反编译图片素材挪作商业或盈利用 使用教程地&#xff1a;https://www.kancloud.cn/ludeqi/xcxzs/2607637 最新版下载地址&#xff1a;https://xcx.siqingw.top/xcx.zip 小…

Python Flask构建微信小程序订餐系统 (十二)

🔥 创建切换商品分类状态的JS文件 🔥 ; var food_act_ops={init:function(){this.eventBind();},eventBind:function(){//表示作用域var that = this;$(".wrap_search select[name=status]").change(function(){$(".wrap_search").submit();});$(&qu…

海外网红营销合作指南:详解海外合同与协议要点

随着互联网的发展和社交媒体的普及&#xff0c;海外网红营销成为了品牌推广和营销的重要力量。然而&#xff0c;这种跨国合作需要谨慎考虑&#xff0c;签订合适的合同与协议显得尤为重要&#xff0c;以确保各方权益得到保障并促进合作的顺利进行。本文Nox聚星将详细介绍与海外网…

web前端设计师的主要职责说明(合集)

web前端设计师的主要职责说明1 职责&#xff1a; 1. 根据UI设计师提供的设计图&#xff0c;实现一流的Web界面&#xff0c;优化代码并保持在各浏览器下良好的兼容性; 2. Web前端表现层及与后端交互的架构设计和开发; 3. JavaScript程序模块开发&#xff0c;通用类库、框架编…

STM32 互补PWM 带死区 HAL

1、设置PWM波频率100KHz&#xff0c;占空比50%&#xff0c;死区时间1us 2、 while 循环之前启动PWM HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //启动TIM1_CH1 PWM输出 HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1);//启动TIM1_CH1N PWM输出 3、死区计算 DT_time…

每日一题——判断链表中是否有环

题目 判断给定的链表中是否有环。如果有环则返回true&#xff0c;否则返回false。 数据范围&#xff1a;链表长度 0≤n≤10000&#xff0c;链表中任意节点的值满足 ∣val∣<100000 要求&#xff1a;空间复杂度 O(1)&#xff0c;时间复杂度 O(n) 输入分为两部分&#xff0c…

优维低代码实践:添加构件

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 优维…

HCIA静态路由综合实验(eNSP)

实验题目及要求&#xff1a; 1、分析IP地址分配。 主干IP掩码均为30&#xff1b; 环回IP掩码为28&#xff0c;方便汇总掩码27&#xff1b; 然后预留部分IP地址。 如下图&#xff1a; 2、按如上图片要求连接设备&#xff0c;并标记好IP分配信息&#xff0c;便于命令配置时一…