KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA

RabbitMQ 工程课:路由、确认与死信 — keel 龙骨

从 vhost、connection、channel 的边界讲起,把 AMQP 0-9-1 模型落到本机 broker 的真跑输出上:四种 exchange 的路由匹配与边界、publisher confirm 与 mandatory/alternate exchange 各补哪一段、手动 ack 与 prefetch 对分发公平性的影响、DLX 与 x-death 的真实结构、quorum queue 的 Raft 语义、内存与磁盘告警如何变成发布端背压。

从 vhost、connection、channel 的边界讲起,把 AMQP 0-9-1 模型落到本机 broker 的真跑输出上:四种 exchange 的路由匹配与边界、publisher confirm 与 mandatory/alternate exchange 各补哪一段、手动 ack 与 prefetch 对分发公平性的影响、DLX 与 x-death 的真实结构、quorum queue 的 Raft 语义、内存与磁盘告警如何变成发布端背压。

章节目录

  1. 00 · AMQP 0-9-1 模型全景 — 排查「消息没到」之前,先要能说清一条消息从 basic_publish 到消费回调,在 broker 里到底经过哪几个对象。这些对象不是同一层的东西:connection 是 TCP,channel 是它上面的复用槽位,vhost 是命名空间,exchange 是路由表,queue 才是真正存消息的地方。把它们混成一坨,后面每一章的失败现象都会看错。本篇的所有输出来自本机 RabbitMQ 4.3.6,节点名已做脱敏,统一写作 rabb
  2. 01 · 路由实测:四种 exchange 各收到什么 — exchange 选型和 routing key 设计是 RabbitMQ 里最容易埋雷的一步,因为配错了不会报错,只会静默地少发。这一章不背规则表,直接把同一批 routing key 分别投给四种 exchange,把每个队列实际收到的东西打印出来,用输出说话。实验环境是本机 RabbitMQ 4.3.6,vhost /lab,节点名已脱敏为 rabbit@node1。
  3. 02 · 上行可靠性:publish 的四个丢失点 — 「消息发出去了」是个含糊的说法。从 basicpublish 返回,到消息真的躺在某个队列里,中间有四段可能断:帧没送到 broker、到了 exchange 没人接、到了队列被拒收、broker 重启后消失。这四段各有一件对应的工具——publisher confirms、mandatory/alternate exchange、basic.nack、durable + deliverymode=2——但它们不是互相替代的,各补各的一
  4. 03 · 下行可靠性:ack、nack、requeue 与 prefetch — 上行解决了「消息进队列」,下行要解决的是「消息被正确处理、且处理能力被正确分配」。这里有两个独立的坑:一是 ack 时机错了导致消息丢或重复,二是没设 prefetch 导致 broker 把整队列消息全推给一个慢消费者、其它消费者空转。第二个坑在监控上表现为「消费速率正常、但队列迟迟不空」,很容易误判。本章的输出出自本机 RabbitMQ 4.3.6,节点名已脱敏。
  5. 04 · 死信与延迟:x-death 结构与延迟队列的代价 — 消费失败的消息去哪了?RabbitMQ 的答案是「看你怎么配」。配了 x-dead-letter-exchange 就进死信队列,没配就真的丢。死信最有价值的地方不是「消息没丢」,而是那条消息上会带一个 x-death header,把「它在哪个队列、因为什么原因、死了几次」写得清清楚楚。这一章先把 x-death 的每个字段对着真实输出拆开,再讲延迟队列的几种做法各自的代价。实验出自本机 RabbitMQ 4.3.6,节点名已脱敏。
  6. 05 · 集群与队列类型:classic、quorum 与 Raft 语义 — 「节点挂了一台,队列会怎样」这个问题没有统一答案,答案取决于队列类型。classic 队列(非复制)整个只活在一个节点上,那个节点挂了队列就不可用;quorum 队列用 Raft 把消息复制到多个节点,少数节点挂掉还能继续。这一章把两者的差异对着 listqueues 的 type 字段和 quorumstatus 的 Raft 字段讲清楚,并且明确标出哪些结论本机单节点跑不出来、只能引用官方规定。
  7. 06 · 流控与运维:内存告警怎么变成背压 — 前几章都在讲单条消息的命运,这一章讲整个 broker 的容量。RabbitMQ 有一个容易被忽视的设计:当内存或磁盘告急时,它不会丢掉最老的消息来减压,而是停止读取所有发布连接的数据,把压力原封不动地回推给你的应用。理解这条背压链路,是判断「队列堆积时到底该扩消费者还是该先止血」的前提。

进入 keel 阅读