可靠性与死信
持久化、prefetch、DLX。
30 分钟
可靠性与死信
任务队列要 不丢、不重、可恢复:持久化队列与消息、publisher confirm、consumer manual ack、死信交换机(DLX) 兜住反复失败的消息。思路与 kafka-delivery 的 at-least-once + 幂等类似。
学习目标
- 配置 durable queue、persistent message、publisher confirm
- 理解 prefetch 与 consumer 数量的关系
- 搭建 DLX 将 poison message 隔离
核心内容
持久化三件套
Map<String, Object> args = Map.of(
"x-dead-letter-exchange", "coderoadmap.dlx",
"x-dead-letter-routing-key", "failed");
channel.queueDeclare("coderoadmap.work", true, false, false, args);
消息 deliveryMode=2,队列 durable=true,Exchange 也声明 durable。Broker 重启后未 ack 的消息仍在——但 不能替代 MySQL 真相(sb-jpa)。
Publisher Confirm
rabbitTemplate.setConfirmCallback((correlation, ack, cause) -> {
if (!ack) log.error("publish failed: {}", cause);
});
rabbitTemplate.convertAndSend(exchange, routingKey, body);
Confirm 表示 Broker 已 接收 消息;与 Kafka acks=all 类比。业务侧仍建议 先落库再发 MQ。
死信触发条件
| 情况 | 结果 |
|---|---|
| nack / reject 且 requeue=false | 进 DLX |
| 消息 TTL 过期 | 进 DLX |
| 队列长度超限 | 进 DLX |
@RabbitListener(queues = "coderoadmap.dlx.failed")
public void onDeadLetter(Message msg) {
log.warn("DLQ: {}", msg);
}
人工排查或告警后重投;勿无限 requeue 打满队列。监控 Ready/Unacked 见 rmq-monitor。
幂等与 Redis
重复消费时,用 业务 id + Redis SETNX(redis-patterns)或 MySQL 唯一键去重。RabbitMQ 无 Kafka 那种 exactly-once 事务 API,工程上 at-least-once + 幂等 最常见。
练习
- 配置 DLX,让 nack 三次后消息进入死信队列
- 说明 publisher confirm 与 consumer ack 各保证哪一段