RocketMQ全链路监控与稳定性优化实践:无人售货机场景
2026/9/16 9:17:28 网站建设 项目流程

在无人售货机这种“设备分散、网络不稳、订单碎片化”的场景里,RocketMQ 不只是消息管道,它几乎就是整个业务系统的主动脉。交易流水、设备心跳、补货工单、远程指令全部从这里走,一旦这条链路监控不到位,表面看只是消息堆积,实际上就是售货机不出货、用户投诉、补货员白跑一趟。这篇内容我会结合线上跑量产设备的实际经验,把 RocketMQ 的全链路监控、分级告警、日常运维和稳定性优化完整梳理一遍,不讲空泛理论,全部是可以落地照做的方案,适合正在做 IoT、新零售或无人设备后台的开发和运维同学参考。

1. 无人售货机场景为什么把 RocketMQ 当消息主动脉

1.1 设备消息的特征和普通业务消息完全不同

做过无人售货机的人都知道,这个场景下的消息流和普通电商、互金业务的消息流完全是两码事。设备端通过 4G、Wi-Fi 甚至 NB-IoT 联网,网络质量参差不齐,一个点位可能在地下室、在商场角落、在景区户外,信号时好时坏。单台设备每天上行的消息量不大,可能就几百到几千条,但设备基数大,几百上千台设备同时在线时,每秒钟的消息量就会被放大到一个不可忽视的量级,而且带有显著的脉冲特征——早上用户集中购买、午间高峰、晚上扫码时段,消息量会突然窜上来。

更关键的是消息类型非常杂。无人售货机的消息至少可以分成三类:一类是交易流水和订单结果,这是最核心的业务数据,丢一条就少一笔钱;一类是设备状态上报,比如温度、货道库存、门锁状态、故障代码,这类消息量大但单条价值低,丢了可以靠下一次上报补偿;还有一类是下行控制指令,比如远程开门、货道出货、价格下发、固件升级命令,这类消息对实时性要求高,而且要能确认设备确实收到了。

这三类消息混在同一个 RocketMQ 集群里,如果 Topic 划分不合理、监控指标不到位,生产环境就是一个黑盒。设备说“上报了”,后台说“没收到”,两边对不上账,排查起来极其痛苦。所以我一直强调,无人售货机接入 RocketMQ 之前,第一件事不是搭集群,而是把消息分类和 Topic 规范定好,这是后续监控和告警能发挥作用的前提。

1.2 选型对比:RocketMQ 为什么比 Kafka、EMQX 更适合这个场景

选型时很多人会拿 Kafka 来比。Kafka 的优势在于吞吐量极高、生态成熟,但它的吞吐优势需要靠分区数量和顺序写来发挥,而无人售货机这种场景,单 Topic 的消息量其实不算夸张,真正吃紧的是“小消息多 Topic 乱跳”的模型。Kafka 对 Topic 数量和消费组的管理是随着规模增长会变得复杂,一旦 Topic 维度不够克制,分区膨胀会拖垮 Broker。而且 Kafka 在消息重试、死信队列、定时消息这类开箱即用的功能上,是相对弱的,而这些恰恰是 IoT 场景非常依赖的。

EMQX 这类 MQTT Broker 在设备接入层确实有道,很多方案是 MQTT 做设备接入、RocketMQ 做业务流转。但如果你希望设备消息直接落进一个能支撑业务订阅、支持可靠重试、能和现有 Java 后端无缝集成的消息系统,RocketMQ 是更顺的选择。它的消费模型天然适合多个业务方同时订阅同一份消息:交易中心订阅订单流水,补货系统订阅库存变动,财务系统订阅流水对账,大家各取所需,互不干扰。再加上事务消息、延迟消息、消息轨迹这些能力,基本把无人售货机后台的刚性需求全覆盖了。

RocketMQ 的另一个好处是社区活跃度稳定,中文资料多,出了问题能很快找到同类案例。对于中小团队来说,这是一笔实实在在的隐性成本节省。我们的选择是:设备端用 MQTT 或者 HTTP 长连做接入网关,网关内部把协议统一转换成 RocketMQ 消息,业务侧完全屏蔽设备协议的差异,只和 RocketMQ 打交道。

1.3 Topic 划分:向上生长容易,向下拆分重写很难

我把无人售货机的 Topic 体系划分成了几类,比较简洁,也便于权限控制。

Topic 命名用途消息类型可靠性要求
order-trade-record设备端交易成功后的订单流水普通可靠消息必须不丢,依赖事务和重试保证
device-heartbeat设备心跳、温度、电量等状态上报普通消息允许少量丢失,以最新状态为准
device-event-report故障码、门锁告警、掉线通知等事件普通可靠消息高可靠,故障事件是关键告警源
command-dispatch下行控制指令,出货、开门、定价等RocketMQ 事务消息极高,指令必须达成且有确认

Topic 数量控制在个位数,而不是按设备型号或者区域去拆 Topic。不少团队一开始觉得按区域拆 Topic 方便隔离,后来就会发现运维成本暴涨,监控面板、消费组权限、告警规则全部要翻倍。设备维度完全可以通过消息里的deviceId字段解决,没有必要在生产端把消息拆散。按消息类型横向切分,远比按设备维度纵向切分更合理。

2. 线上监控的三层布防:集群、消费链路、设备点位

2.1 集群健康指标:磁盘、PageCache、JVM 这三样最容易出问题

RocketMQ 的 Broker 本质上是“内存 + 磁盘”的存储引擎,所以监控系统里最基础但最关键的指标,就是磁盘使用率。我见过不只一次线上事故是因为磁盘被打满,Broker 直接拒绝写入,消费端疯狂堆积,订单消息延迟飙到几万条。如果你的告警规则里没有磁盘水位的独立监控,那就等于把安全绳系在了沙子上。

磁盘监控不能只看“使用了百分之多少”,还要关注写入速率和落盘耗时。RocketMQ 默认的存储路径是store目录下的 commitlog、consumequeue、index 三类文件,commitlog 是顺序写,ConsumeQueue 是逻辑队列,一旦磁盘读写延迟异常(比如 iostat 里util持续超过 90%),即使磁盘容量还没满,写入性能也会急剧下降,消息发送 RT 会跟着抖起来。我一般会在 Prometheus 里配node_filesystem_avail_bytesnode_disk_io_time_seconds_total这组指标,再加一个“连续 5 分钟磁盘可用空间低于 20% 就 P1 告警”的规则。

PageCache 命中率同样不能忽略。RocketMQ 的读消息大部分时候是走 PageCache 的,只有 Cache 没命中才会落盘读。如果消费速度跟不上写入速度,PageCache 被反复刷掉,读延迟会大幅上升。可以用CacheSizeFlushPageCache相关指标来评估,也可以直接用free -m看 cached 部分的变化趋势。有时候 Broker 内存配置明明还有富余,但消费依然慢,排查到最后发现是 PageCache 命中率太低,整体读链路被动降速。这个坑最隐蔽,也最容易被漏掉。

JVM 方面要盯 GC 次数和耗时。RocketMQ 默认堆内存配置未必适合你的消息量,生产环境里 Full GC 一多,Broker 就会频繁 STW,表现为发送消息偶发超时、消费拉取出现较长的空白期。我用 Grafana 配了 GC 的 Histogram,只要 Full GC 单次超过 1 秒,或者每分钟 Full GC 次数大于 1,就直接触发告警。这组指标放在任意一个 Broker 节点都适用,而且越早接入越好,不要等出现踩线事故再补。

2.2 消费链路指标:堆积量、消费延迟、ReBalance 这三个是核心

光看集群健康是不够的,因为 Broker 活着不代表业务在正常的跑。真正和用户体感直接挂钩的,是消费链路的健康程度。

消费堆积量(ConsumerLag)是最直观的指标。RocketMQ 的 Broker 可以通过mqadmin consumerProgress命令按消费组查看堆积情况,或者通过 Prometheus 暴露的rocketmq_broker_consumer_progress指标采集。这里有一个重要的坑:堆积量要按“消费组 + Topic + 队列”级别来看,而不是只看一个全局数字。因为某个队列可能因为消费线程卡住而堆积,但其他队列消费正常,全局数据看不出问题来。我在告警规则里做了分组聚合,只有当同一个消费组在多个队列上都出现持续性堆积时才告警,避免单队列抖动导致的误报。

消费延迟比堆积量更适合做告警阈值。堆积量是绝对值,不同业务组之间的堆积量差异巨大,库存组堆 10 万条可能没事,交易组堆 1 万条就已经影响用户体验了。消费延迟指的是“最新生产消息的时间戳 - 最新已消费消息的时间戳”,单位是毫秒。这个指标跨业务组可比,也更直接对应业务受损害程度。我把告警阈值设成:

  • 延迟超过 30 秒:告警进入 P2,人工关注。
  • 延迟超过 2 分钟:告警进入 P1,立即排查。

这个阈值不是拍脑袋定的。无人售货机的下行指令(比如出货指令)从生成到设备执行,全链路允许的时间窗口大约在 10 秒以内,消息在 MQ 里占用的时间必须压到极低,否则设备侧就会报“指令超时”。能把消费延迟长期压在 30 秒内,业务基本无感;一旦超过 2 分钟,就很可能会集中爆发用户投诉。

ReBalance(分区重平衡)是另一个需要重点盯的指标。消费组在发生消费者实例上下线、Topic 队列数变更、Broker 故障时,会触发 ReBalance。频繁的 ReBalance 会导致消费短暂中断、重复消费,严重时还会产生“消费风暴”。我见过一个消费组因为消费者实例的启动脚本每次发布都会重启,导致每天固定时间点出现一次消息堆积,就是因为重启触发了 ReBalance。后来做了滚动发布 + 消费实例数量固定,问题才稳定下来。监控上要把RebalanceStartRebalanceEnd事件记录下来,如果发现单位时间内 ReBalance 次数明显异常,先查部署发布,再查 Broker 节点状态。

2.3 业务侧监控:单点位消息完整率比集群指标更贴近用户体验

集群级和消费级指标监控得再好,如果业务侧不看终态数据,依然可能发生“消息八成都成功了,但某个点位连续失败”的局部灾难。在无人售货机这种强线下属性的场景里,单个设备点位就是一个小型业务单元。某台售货机的交易流水断了几小时,如果只靠 MQ 集群指标,根本看不出来,因为整体消息量依然平稳。

我补充了一套业务侧监控,核心指标叫“点位消息完整率”。思路是:设备端每 5 分钟上报一次心跳并携带本地已生成的订单编号列表,后台把这些编号和 MQ 里实际收到的订单编号做比对,得出每个设备点位的消息完整率。

  • 连续 3 个上报周期完整率低于 95%:产生 P2 告警,提示该点位有人工介入排查。
  • 连续 5 个周期完整率低于 80%:升级为 P1,直接定位到设备,往往意味着设备端的网络模块或者协议转换网关出了问题。

这套监控我放在了 RocketMQ 消费端之后的一个轻量级计算服务里,本质上是“对账系统”,数据量不大,但价值极高。很多线上问题不会表现在集群指标上,只会在单点业务数据上露出马脚。集群指标告诉你“系统健康”,业务侧对账才告诉你“设备真的在正常赚钱”。

3. 告警体系设计:分级、聚合、防轰炸

3.1 告警等级划分:S1 到 S4,责任到人,响应时效明确

告警设计最怕的就是“所有问题都告警,等于没有问题”。团队精力是有限的,如果每天几十条告警砸过来,真正严重的故障反而会被淹没。我把告警分为四个等级,每个等级有明确的响应人、响应手段和闭环要求。

S1(紧急故障):消息全局不可消费、Broker 宕机、消费组堆积超过 10 万条且持续增长。这类告警对应的是核心链路已经断裂,需要立即拉群、打电话、不管几点都要起来处理。S1 的响应时效是 5 分钟内有人处理,15 分钟内给出初步反馈。

S2(严重异常):消费延迟超过 2 分钟、磁盘可用空间低于 20%、某个消费组出现持续性 ReBalance。这类问题不会立刻中断全链路,但如果不处理很快就会升级成 S1。响应时效是 15 分钟。

S3(一般异常):单个设备点位掉线、消息完整率低于 95%、Broker 节点 JVM GC 频率偏高。这类问题影响面局部,可以进白天的处理队列,但要有专人跟踪,避免小问题拖成大问题。响应时效是 4 小时内。

S4(提示信息):数据波动、流量峰值、某些非核心指标超过阈值。这类告警只记录,不打扰人,方便事后复盘时排查规律。

这套分级的好处是,值班的人看到告警就能立刻判断严重程度,不用每次先翻半天日志。真正到了故障现场,时间是最贵的成本。

3.2 告警聚合与生命周期管理:从触发到恢复的全自动闭环

告警如果只触发不闭环,就像火警报警器响了没人去按掉,过一会儿又响,反复骚扰,最终大家就会把它屏蔽。

我在 Alertmanager 里配置了分组(group_by)和抑制(inhibit)规则。分组的作用是把同一个消费组、同一个 Broker 实例、同一个时间段内触发的同类告警聚合成一条通知,而不是一条一条刷屏。比如某个 Broker 磁盘告警触发后,这个实例上的所有 Topic 堆积告警会自动被抑制,因为根因是同一个,重复报只会增加噪音。

另外,每条告警都要有“恢复”事件。告警恢复后自动发送一条“xxx 已恢复正常”的通知,这样值班同学不需要手动确认,也不需要猜“那条告警还在不在”。Alertmanager 本身就支持这一套生命周期管理:告警触发、告警等待、告警恢复、告警解决。关键是要在规则里配置好for参数,让告警在阈值持续超过一定时间后才触发,避免偶发毛刺制造恐慌。

比如消费延迟告警,我设了for: 2m,意思是延迟超过 2 分钟且持续 2 分钟后才告警。如果是偶发的一分钟延迟抖动,系统自己恢复,不打扰任何人。这个设计看似简单,但能砍掉至少一半的无效告警。

3.3 告警通知渠道:企业微信机器人、电话、值班表轮流

现在做无人零售的后台,企业微信几乎是标配,告警通知首选就是企业微信机器人。好处是能直接推到手机端,还可以在群里 @对应负责人。我配置的 webhook 消息里会附带告警详情、链接到 Grafana 面板、还有处理指引,值班同学点开链接就能看当时的曲线,不用再登录服务器查命令。

但企业微信机器人也有局限:如果机器人的 webhook 配置错了,或者手机静音,告警可能就漏了。所以 S1/S2 级别同时配置了电话告警,用阿里云 SLS 或者自建脚本调用电话接口,确保严重问题一定会被感知到。

值班表我也是在告警系统里配置的,周一到周日不同的人,节假日自动切到值班组。不要小看这件小事:没有轮值表的时候,告警发到团队群里,反而是“三个和尚没水吃”,每个人都觉得别人会看,结果没人响应。轮值表和 Escalation(升级)策略搭配起来——S1 告警 5 分钟没人认领就自动升级到技术负责人,这就是一个兜底链条。

3.4 告警疲劳治理:固定阈值到动态基线的演进

用固定阈值做告警,最怕的是“狼来了”效应。比如磁盘使用率超过 80% 告警,但系统稳定运行时本来就一直 75% 上下波动,你的阈值设置在 90%,等真到 90% 的时候,可能已经撑不了多久了。如果设在 80%,又天天误报。

我现在的做法是监控指标尽量用动态基线:采集最近 7 天同一时间段的数据,用百分位数(比如 P95)作为基准,超出基线一定比例才触发告警。这套逻辑用 Prometheus 的histogram_quantile或者第三方预测组件都能实现。

对于无人售货机场景,最典型的是“消息发送 RT”。白天峰值时段发送 RT 基线可能是 20ms,夜间低峰期基线可能是 5ms。固定阈值完全没法适配这种规律波动,动态基线则可以做到白天不误报、夜间更敏感。用了一个多月后,团队对告警的信任度明显回来了——收到告警意味着真的有问题,而不是“又抽风了”。

4. 量产稳定性优化的关键链路

4.1 部署架构演进:从单机主从到多节点容灾

无人售货机业务早期,消息量不大,很多团队图省事,一个 RocketMQ 单节点跑到底。这套方案在日订单量几万条时没问题,但一到量产,设备数量增加到几百台,单节点的风险就会被完全放大。

我建议量产环境至少是“两主两从”的主从架构:两个 Master 节点承担写入,两个 Slave 节点同步备份。RocketMQ 4.5 之后的版本还支持 DLedger(基于 Raft 的自动选主模式),这个模式下某个 Master 挂了,Slave 会自动升级成 Master,业务侧基本无感知。

不过 DLedger 也不是银弹。它的写入性能相比主从异步复制模式会有一点损耗,因为 Raft 需要多数派确认,相当于每次写入都多了一次网络同步。无人售货机这种消息量级(每秒几千条)完全顶得住,但你要有准备:如果未来单集群消息量涨到每秒几万条,可能要考虑单独集群隔离核心链路。

我最终采用的结构是双机房双集群 + 业务层双写。核心的订单消息通过事务消息保证不丢,事务状态表放在数据库里做兜底对账。跨机房容灾不是每个团队都能一步到位,但如果业务涉及多城市部署,至少要在核心集群上做跨境网络层的监控,避免区域网络抖动导致设备大面积掉线。

4.2 高频小消息的性能调优:批量发送、压缩、异步刷盘

设备上报的消息有个特点:每条消息很小,可能就几十字节到几百字节,但条数多,尤其是心跳和状态上报。大量小消息对 RocketMQ 的写入吞吐是不利的,因为每一次发送都要经过网络、Broker 内存、刷盘等环节。批量发送是立竿见影的性能优化手段。

设备接入网关在收到设备上报后,先在内存中积累一段时间(例如 200ms)或者积累达到一定数量,再调用 RocketMQ 的批量发送接口。实测单条发送改成批量发送后,发送端 CPU 占用率能降 40% 以上,Broker 端写入 QPS 也能提升一倍左右。但有一点要注意:批量发送有大小限制,默认单批不能超过 4MB,而且要保证同一批次的消息属于同一个 Topic。

消息体压缩我放在批量发送之前。设备上报的 JSON 结构里有很多重复字段(设备型号、固件版本、点位 ID),用 Gzip 压缩后体积能减少到原来的 1/5 甚至更小。代价是两个:CPU 开销增加,消费端要先解压。在这个场景里,网络带宽和磁盘 IO 的收益远大于 CPU 的额外开销。

刷盘策略我选了异步刷盘(ASYNC_FLUSH)而不是同步刷盘(SYNC_FLUSH)。原因很简单:设备业务允许极端情况下丢失几毫秒内的少量非关键消息,但不允许因为同步刷盘的性能瓶颈拖垮正常消息链路。核心交易消息靠事务消息和数据库兜底,状态上报消息本身可重传,所以异步刷盘是性能和安全之间的合理折中。如果你做的是金融交易这种绝对不能丢消息的场景,那同步刷盘是必须的,但无人售货机不属于这种场景。

4.3 消费者幂等设计:从 At Least Once 到真正接近不重不漏

RocketMQ 本身保证 At Least Once,也就是消息不丢,但极端情况下(比如消费端处理成功但提交位移前宕机)会重复投递。在无人售货机场景里,重复投递的杀伤力体现在哪?最典型的就是出货指令重复执行——同一笔订单,设备出两次货,货道直接卡死,商品掉落数量对不上账。

消费端要做幂等,不是靠 RocketMQ 的配置,而是靠业务设计。交易消息的幂等我用的是数据库唯一键:订单表order_id建唯一索引,消费端插入时冲突就直接返回成功,不重复处理业务逻辑。下行指令的幂等用的是指令状态表,每条指令有一个全局唯一的command_id,设备执行完指令后回报执行结果,后端收到重复指令时先查指令状态表,已经执行过的直接丢弃。

这套幂等设计上线后,因消息重复导致的出货异常从每月十几起降到了零,对量产设备来说是质的提升。有人会觉得幂等设计麻烦,但它其实是在为最坏情况兜底。无人售货机不是纯软件产品,它连着机械硬件,一旦重复出货,损失的不只是一个订单,而是整个点位的库存和口碑。

4.4 消息轨迹:线上问题排查的最后一张底牌

线上监控做得再好,也总有“不知道哪条消息怎么丢的”这种疑难杂症。RocketMQ 从 4.x 版本开始支持消息轨迹(Message Trace),开启后可以在控制台或者通过 API 查看一条消息的完整生命周期:什么时候生产、生产耗时、存储在哪、什么时候被消费、消费结果如何。

无人售货机场景里,消息轨迹最有价值的地方在于“终端设备侧数据回传慢”的排查。用户扫码买了一瓶水,支付成功了,但设备没出货,用户投诉。这时候查 MQ 轨迹就能看到:到底是设备端根本没上报订单消息,还是消息到了 MQ 没被消费,还是消费了但下游处理失败。整个过程清晰明了,不用逐台设备去找日志。

开启消息轨迹会带来约 10% 的持久化存储开销,但对于无人售货机这种消息量级完全可以接受。在关键 Topic 上开启,在全链路压测的时候把轨迹数据也纳入压测范围,避免上线后因为轨迹写入导致消息发送耗时不稳定。

5. 高频踩坑与多环境运维巡检清单

5.1 环境配置的经典坑:JVM、文件句柄、时钟偏移

RocketMQ 在生产环境跑一段时间后,最容易暴露出问题的往往不是功能逻辑,而是基础环境配置。我把这三年踩过的最典型的几个坑列出来,给还没踩到的同学提个醒。

第一个坑是 JVM 堆内存设置。RocketMQ 默认的runbroker.sh里 JVM 参数是为中大型服务器准备的,堆内存动不动就 8G。如果部署的机器只有 8G 内存,堆加上堆外(PageCache 占的那部分)很容易吃满,操作系统直接触发 OOM Killer。我的惯例是单台 Broker 至少 16G 内存,堆内存给 4G 到 6G,其余留给 PageCache。很多性能问题根本不是 RocketMQ 本身的问题,而是给你的堆内存太小、给系统的缓存空间不够。

第二个坑是文件句柄数。RocketMQ 是极重 IO 的应用,文件句柄消耗很快。Linux 默认的ulimit -n是 1024,跑不了几分钟就会报Too many open files。我一般会设置到 655350,而且要注意是 broker 启动用户的实际生效值,不是 root 用户下改一下就完事。这个坑特别隐蔽,因为很多机器平时开箱即用,不会触发到 1024 的上限,但一旦线上流量正常,文件句柄告警马上就来了。

第三个坑是时钟偏移。RocketMQ 的消息在 Broker 端的写入时间戳、消费端的时间戳都依赖系统时钟。如果 Broker 节点之间的时钟偏差超过了几秒,告警系统里看到的消费延迟就会变成负数,甚至触发错误的 ReBalance 判断。我会在每台机器上配置 NTP 同步,并且加一个监控项,检查所有 Broker 节点的时钟偏差,超过 1 秒就告警。

5.2 弱网环境特有的问题:超时、重连和设备端消息补偿

无人售货机设备端的网络环境远不如服务器机房稳定,这块出的问题往往不在 RocketMQ 本身,而在接入层和设备端的配合。设备走 4G 网络时 IP 经常变、网络抖动大、短暂掉线家常便饭。

设备端到网关的 HTTP 长连接或 MQTT 连接,超时配置要格外小心。超时设太短,网络一抖就断了,设备会频繁重连,网关压力陡增;超时设太长,网络断了半天才发现,消息堆积在设备本地。我的经验是:连接超时设 10 秒,读写超时设 30 秒,心跳间隔 30 秒,心跳超时 90 秒判定掉线。这几个值是经过设备端和网关压力测试测出来的,在稳定性与实时性之间比较平衡。

设备端本地必须要有消息补偿机制。设备上报消息到网关,网关返回 ACK,设备才算发送成功;如果网关没返回 ACK,设备端要把消息存在本地 Flash 或者轻量级数据库里,间隔一段时间重新上报,重试次数和重试频率要有限制,避免设备离线后堆积大量消息造成上线时消息风暴。我遇到过某款设备因为重试频率设的太高,一次网络恢复后同时回传几万条消息,直接把 MQ 集群打出了消费堆积告警。后来加了设备端的重试退避算法,第一波先回传最近 5 分钟的消息,剩下的每隔一段时间均匀回传,整个链路才稳定下来。

5.3 日常巡检清单:不开 Web 控制台也能速查问题

很多运维同学习惯打开 RocketMQ Web 控制台(dashboard)看监控面板,但真正线上排查时,命令行mqadmin往往是更快更可靠的手段。下面是我日常巡检和故障排查时最常用的几条命令。

# 查看指定 Broker 的运行状态和角色 mqadmin brokerStatus -n 192.168.1.10:9876 -b 192.168.1.10:10911 # 查看某个消费组的消费进度 mqadmin consumerProgress -n 192.168.1.10:9876 -g GID_DEVICE_ORDER # 查看 Topic 的队列分布和消息堆积情况 mqadmin topicStatus -n 192.168.1.10:9876 -t order-trade-record # 查看消费组的具体消费延迟,精确到队列维度的分布 mqadmin consumerStatus -n 192.168.1.10:9876 -g GID_DEVICE_ORDER # 查看集群下所有 Broker 节点的磁盘使用和运行状态,一条命令概览 mqadmin clusterList -n 192.168.1.10:9876 # 查看 Broker 中某个 Topic 的写入 TPS 和大小等统计信息 mqadmin topicRoute -n 192.168.1.10:9876 -t order-trade-record

如果嫌命令记不住,也可以开启 RocketMQ 的Dashboard,在界面上看集群消费者、生产者、Topic 分布的实时状态。但 Dashboard 适合看报表、不适合比你实时告警更快的定位问题。生产环境我建议两手都用:日常巡检看 Dashboard,故障排查用命令行直接确认。

我还有一个巡检习惯,就是每周固定跑一次“消费组进度对账脚本”,把每个消费组的积压数量、最大延迟、消费速率落到一张表格里,看一周的趋势变化。很多时候问题不是突然出现的,而是累积的:消费速率像心电图一样慢慢往下掉,等到告警阈值触发时,其实已经劣化了好几天了。定期趋势巡检能让你在问题变成故障之前就发现它。

5.4 一个真实案例:某点位“订单已支付但未出货”的排查全流程

最后分享一个线上真实案例,来串一下整篇文章的监控和排查体系。

某天早上 9:12,告警系统弹出一条 S2 告警:消费组GID_ORDER_TXNorder-trade-record上消费延迟超过 2 分钟。因为这是交易核心链路,值班同学立刻响应。

第一步,查消费组状态。用mqadmin consumerProgress -g GID_ORDER_TXN -t order-trade-record后发现,总堆积量其实不大,才 2000 多条,问题出在某个特定队列上,堆积量占了 1800 条。其他队列都正常,这基本排除了集群整体故障的可能。

第二步,查消费端日志。发现堆积队列所在的分区,消费者实例的消费线程池一直在抛RejectedExecutionException。进一步看堆栈,是消费线程池满了,池子里有线程卡在了一个外部 HTTP 调用上。那个外部接口是出货指令的推送服务,它的超时设了 60 秒,而且并发了上百个请求,直接把消费线程池堵死了。

第三步,定位根因。不是 MQ 的问题,是这个消费组的下游调用超时太长 + 线程池数量配置不合理。我们把下游 HTTP 调用超时改到 3 秒,并且对消费线程池设置了一个最大等待队列,多余的消费请求直接进入快速失败分支,由 RocketMQ 消费重试机制兜底。这样任何一条消息最多阻塞 3 秒,不会拖死整个消费链路。

第四步,恢复之后复盘。当时影响到的是部分点位的订单状态更新延迟,有用户反馈“已支付但未出货”——其实订单消息并没有丢,只是消费端堵住了,导致出货指令没能及时推给设备。如果当时设备侧没有超时兜底机制,用户会更焦虑。这次之后我们做了一件很重要的事:把所有消费组下游依赖的外部接口的耗时做成一个监控指标,任何接口 P99 超过 5 秒就触发告警,避免消费线程池再次被堵死。

这个案例能说明一个问题:RocketMQ 的稳定性,不光靠 MQ 集群本身,更靠你消费链路上下游的依赖治理。监控和告警的价值就是帮你尽快锁定“堵点”到底在哪个环节,而不是让你在整条链路上大海捞针。

6. 最后想分享的几点运维体会

如果你正准备给无人售货机这种 IoT 业务搭建 RocketMQ 监控运维体系,我的建议是:不要一开始就想做到“全知全能”,先把最核心的几十个指标管好,把告警分级定义清楚,把值班链路跑通,然后再逐步补齐业务侧点位维度的对账监控。量产的稳定性优化是一个持续迭代的过程,第一天做成 60 分,第三天迭代到 80 分,比憋一个大版本最后上线炸掉要安全得多。

另外,监控的核心目的是“减少排查时间”,而不是“增加告警数量”。每一条告警都应该有明确的原因、响应人、处理动作和恢复条件。如果一条告警上线后一个月内都没有触发过,也不要直接删掉它——先确认它是不是阈值设得太宽没有意义,还是真的因为没有出现过异常。有些告警存在本身就是一种安心。

无人售货机业务一旦上了量,你会发现在这些“边角料”上的功夫,带来的收益远远超过把核心业务代码写得多漂亮。消息中间件的稳定运行,是整个交易闭环能够正常完成的地基。地基稳了,上面的业务才能放心长出来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询