news 2026/7/2 22:01:05

RabbitMQ真实生产故障问题还原与分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RabbitMQ真实生产故障问题还原与分析

由某个服务BI-collector-xx队列出现阻塞,影响很整个rabbitMQ集群服务不可用,多个应用MQ生产者服务出现假死状态,系统影响面较广,业务影响很大。当时为了应急处理,恢复系统可用,运维相对粗暴的把一堆阻塞队列信息清空,然后重启整个集群。

在复盘整个故障过程中,我心中有不少疑惑,至少存在以下几个问题点:

  1. 为什么出现队列阻塞?
  2. 某个队列出现阻塞为什么会影响到其他队列的运行(即多队列间相互影响)?
  3. 某个应用MQ队列出现问题,为什么会导致应用不可用呢?

2、试验队列阻塞

某天周末在家里,找个测试环境,安装rabbitmq尝试重现这过程,并做模拟测试。

写两个测试应用Demo(假设是两个项目应用)分别有生产者和消费者,并分别使用队列testA和testB。

为了尽可能还原生产的情况,一开始测试使用了同一个vhost,后面分别设置不同vhost。

生产者A,示例代码如下

消费者A

MQ配置

生产者B,每次生产10万条消息

消费者B,代码故意写错(模拟出现异常的情况),不是正常的json串导致解释json时抛出异常

先了解一下Rabbitmq客户端启动连接工作过程,通过wireshark抓包分析,如下

先对AMQP做一个简单的介绍,请求的AMQP协议方法信息,AMQP协议方法包含类名+方法名+参数,这一列主要展示了类名和方法名

  • Connection.Start:请求服务端开始建立连接
  • Channel.Open请求服务端建立信道
  • Queue.Declare声明队列
  • Basic.Consume开始一个消费者,请求指定队列的消息

详细方法可以查看amqp官网https://www.rabbitmq.com/amqp-0-9-1-reference.html

工作过程分析:

Basic.Publish客户端发送Basic.Publish方法请求,将消息发布到exchangerabbitmq server会根据路由规则转发到队列中;

Basic.Deliver服务端发送Basic.Deliver方法请求,投递消息到监听队列的客户端消费者;

Basic.Ack客户端发送Basic.Ack方法请求,告知rabbimq server,消息已接收处理。

两个应用程序启动后,通过rabbitmq管理控制台可以观察一些参数和监控指标

一开始A应用生产和消费都是正常的。

B消费端错误代码异常,狂刷报错信息

经过大概30分钟运行,观察A生产者应用控制台也有出现异常信息

查看服务端连接状态出现blocked情况,与生产故障发生情景很类似。

此时客户端即本机器,CPU和内存上涨明显,风扇声音很响,明显卡顿,再过30分钟应用基本不可用状态。

分析原因

上面错误代码展示了消费者B无法ack,由于没有进行ack导致队里阻塞。那么问题来了,这是为什么呢?其实这是RabbitMQ的一种保护机制。防止当消息激增的时候,海量的消息进入consumer而引发consumer宕机。

RabbitMQ提供了一种QOS(服务质量保证)功能,即在非自动确认的消息的前提下,限制信道上的消费者所能保持的最大未确认的数量。可以通过设置prefetchCount实现,自动确认prefetchCount设置无效。

举例说明:可以理解为在consumer前面加了一个缓冲容器,容器能容纳最大的消息数量就是PrefetchCount。如果容器没有满RabbitMQ就会将消息投递到容器内,如果满了就不投递了。当consumer对消息进行ack以后就会将此消息移除,从而放入新的消息。

通过上面的配置发现prefetch初始我只配置了2,并且concurrency配置的只有1,所以当我发送了2条错误消息以后,由于解析失败这2条消息一直没有被ack。将缓冲区沾满了,这个时候RabbitMQ认为这个consumer已经没有消费能力了就不继续给它推送消息了,所以就造成了队列阻塞。

判断队列是否有阻塞的风险。

ack模式为manual,并且线上出现了unacked消息,这个时候不用慌。由于QOS是限制信道channel上的消费者所能保持的最大未确认的数量。所以允许出现unacked的数量可以通过channelCount * prefetchCount *消费节点数量得出。

channlCount就是由concurrency,max-concurrency决定的。

  • min = concurrency * prefetch *消费节点数量
  • max = max-concurrency * prefetch *消费节点数量

由此可以得出结论

  • unacked_msg_count < min队列不会阻塞。但需要及时处理unacked的消息。
  • unacked_msg_count >= min可能会出现堵塞。
  • unacked_msg_count >= max队列一定阻塞。
重点注意

1unacked的消息在consumer切断连接后(如重启)再连接,会自动回到队头。

2、若将ack模式改成auto自动,这样会使QOS不生效。会出现大量消息涌入consumer从而可能造成consumer宕机风险。

再回看程序配置,做一些分析和调整

对B消费端问题代码加个try-catch-finally,不管中间有何问题,都进行消息签收ACK。

代码调整之后,两个队列正常运行,客户端两个应用也正常运行。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 21:59:59

PAT乙级69道真题的C++实现合集(1002-1070,每题独立可编译)

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;整理了PAT乙级考试中编号从1002到1070共69道真题的标准C代码实现&#xff0c;每道题对应一个独立的.cpp文件&#xff0c;如1003.cpp、1017.cpp、1053.cpp等&#xff0c;命名清晰&#xff0c;开箱即用。所有代码…

作者头像 李华
网站建设 2026/7/2 21:58:44

MATLAB车牌识别实战工程:HSV颜色定位+字符模板匹配全流程代码包

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;直接运行就能识别蓝牌、黄牌的MATLAB车牌识别方案&#xff0c;从原始图片开始走完整流程&#xff1a;自动灰度化、高斯滤波去噪、Canny边缘检测、HSV空间下按颜色特征定位车牌区域、仿射校正、连通域分析切分单…

作者头像 李华
网站建设 2026/7/2 21:58:39

Visio旧版流程图VDX文件繁简中文批量替换工具(C#离线版)

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;直接处理Visio 2008等老版本导出的VDX格式文件&#xff0c;无需安装Visio软件&#xff0c;纯本地运行。工具通过解析VDX内部XML结构&#xff0c;精准定位并批量替换所有可见文本——包括形状标题、连接线标注、…

作者头像 李华
网站建设 2026/7/2 21:57:54

小黄车Java考试专用IDEA工程模板(含Maven配置与测试结构)

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;专为万得小黄车编程考试设计的Java开发环境模板&#xff0c;开箱即用&#xff0c;直接导入IntelliJ IDEA即可编码、编译、运行和调试。内置标准Maven项目结构&#xff1a;pom.xml已预设常用依赖&#xff0c;src…

作者头像 李华
网站建设 2026/7/2 21:57:14

纯ANSI C实现的FFT算法源码包,含测试用例与完整使用文档

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;提供FFTv2.c和FFTv2.h两个核心文件&#xff0c;用标准C语言实现快速傅里叶变换&#xff0c;支持复数输入输出&#xff0c;不依赖任何第三方库&#xff0c;可在GCC、Keil、IAR等编译器下直接编译运行&#xff1b…

作者头像 李华
网站建设 2026/7/2 21:57:10

2026-07-01 GitHub 热点项目精选

/* 全局样式 */* { margin: 0; padding: 0; box-sizing: border-box; }body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;max-width: 900px; margin: 0 auto; padding: 30px 20px; line-height: 1.7; color: #2d3748;backgro…

作者头像 李华