RabbitMQ 3.13 的消费者处理失败后 basic_nack 带 requeue=true,一条反序列化失败的消息在队列里反复投递,redelivered 计数到 20 万,CPU 被打满,正常消息全堵在后面。
一开始怀疑是「异常是反序列化失败,重试永远不会成功」,查了一圈,方向不对。
排查方向其实有限,先把可能性排一排。requeue 为 true 时消息立刻回队首,没有退避。还有一种是没有配死信队列和最大重投次数。
少数情况下是prefetch 太大,坏消息占满本地缓冲。
上来先看队列的投递和堆积指标
rabbitmqctl list_queues name messages messages_unacknowledged
声明死信交换机并给队列绑定
rabbitmqadmin declare exchange name=dlx type=direct && rabbitmqadmin declare queue name=orders.dlq
随后把无法处理的消息 nack 且 requeue=false
python -c "import pika;ch=pika.BlockingChannel();print('basic_nack(requeue=False)')"
等前面都确认过,再用一条坏消息验证进入死信队列
rabbitmqadmin get queue=orders.dlq count=1
恢复的判定其实很直接。坏消息只投递一次就进入死信队列,orders 队列的 messages 回落到正常水平,消费者 CPU 从 100% 降到 20%。
requeue=true 只适合瞬时故障,反序列化错误重试多少次都不会成功;必须配死信队列并限制重投,否则一条坏消息能拖垮整个消费组。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。
