06-18-A-RabbitMQ消息特性与消费机制详解

06-18-A-RabbitMQ消息特性与消费机制详解

️ 关键词:四种 Exchange · topic 通配符 · Publisher Confirm · Return 机制 · Consumer Ack · prefetch · 死信交换机 DLX · TTL · 延迟队列 · 优先级队列 · 消费幂等

📌 导读 :本篇讲在这个模型上长出来的"消息特性"------四种 Exchange 的路由规则与经典设计、消息可靠性的三端机制(Publisher Confirm + Return + Consumer Ack + 持久化)、prefetch 流控、死信交换机(DLX)的三种触发、TTL+DLX 组合实现延迟队列(含队头阻塞坑)、优先级队列、消费幂等。看完本篇你能做到:被问"RabbitMQ 怎么保证消息不丢"能讲出三端确认的完整链路,被问"延迟队列怎么实现"能讲出 TTL+DLX 组合和队头阻塞坑,被问"死信有哪几种"能列出被拒/过期/队列满三来源。


📑 目录

  • 06-18-A-RabbitMQ消息特性与消费机制详解
    • [📖 术语速查表(每个词都用人话解释)](#📖 术语速查表(每个词都用人话解释))
    • [一、四种 Exchange:路由规则与经典设计](#一、四种 Exchange:路由规则与经典设计)
      • [1.1 对比与示例](#1.1 对比与示例)
      • [1.2 topic Exchange 通配符](#1.2 topic Exchange 通配符)
      • [1.3 路由失败的兜底:mandatory 与 AE](#1.3 路由失败的兜底:mandatory 与 AE)
    • 二、消息可靠性:三端确认的完整链路
      • [2.1 三端可靠性](#2.1 三端可靠性)
      • [2.2 Publisher Confirm(生产者确认)](#2.2 Publisher Confirm(生产者确认))
      • [2.3 Consumer Ack(消费者确认)](#2.3 Consumer Ack(消费者确认))
      • [2.4 prefetch:消费流控](#2.4 prefetch:消费流控)
    • 三、死信交换机(DLX)
      • [3.1 消息什么时候变"死信"](#3.1 消息什么时候变"死信")
      • [3.2 DLX 配置与流转](#3.2 DLX 配置与流转)
      • [3.3 死信处理最佳实践](#3.3 死信处理最佳实践)
    • [四、延迟队列:TTL + DLX 与延迟插件](#四、延迟队列:TTL + DLX 与延迟插件)
      • [4.1 方案一:TTL + DLX(无插件)](#4.1 方案一:TTL + DLX(无插件))
      • [4.2 两个坑](#4.2 两个坑)
      • [4.3 方案二:延迟插件(推荐)](#4.3 方案二:延迟插件(推荐))
      • [4.4 三种延迟方案对比](#4.4 三种延迟方案对比)
    • 五、其他消息特性
      • [5.1 优先级队列](#5.1 优先级队列)
      • [5.2 消息属性与持久化](#5.2 消息属性与持久化)
      • [5.3 消费幂等(与 RocketMQ 同款军规)](#5.3 消费幂等(与 RocketMQ 同款军规))
    • 六、跑一遍:确认机制与死信全流程
      • [6.1 观察 Publisher Confirm 与 Return](#6.1 观察 Publisher Confirm 与 Return)
      • [6.2 死信全流程](#6.2 死信全流程)
    • 七、总结
      • [7.1 一张图回顾全文](#7.1 一张图回顾全文)
      • [7.2 核心要点浓缩(十二条)](#7.2 核心要点浓缩(十二条))

📖 术语速查表(每个词都用人话解释)

** Exchange 类型类**

术语 一句话白话解释
direct Exchange 精确匹配:Routing Key == Binding Key 才投递------一对一
fanout Exchange 广播:忽略 Routing Key,投递到所有绑定的 Queue------一对多
topic Exchange 模式匹配 :Binding Key 支持通配符(* 匹配一个词,# 匹配零或多个词)------灵活路由(最常用)
headers Exchange 按消息头匹配:忽略 Routing Key,按 headers 属性匹配------少用
默认 Exchange 名为 ""(空串)的 direct Exchange------每个 Queue 自动以队列名绑定,publish("", "queueName") 直达
备用交换机(AE) Alternate Exchange------路由不到任何 Queue 的消息转投到这里兜底(不丢)
mandatory 发送标志------路由不到 Queue 时退回 Producer(basic.return),默认 false 直接丢弃

️ 可靠性类

术语 一句话白话解释
Publisher Confirm 生产者确认------Broker 收到消息后回调确认(ack/nack),Producer 据此判断发送成功与否
Return 机制 mandatory=true 时路由失败的消息退回 Producer(ReturnCallback)
Consumer Ack 消费者确认------Consumer 处理完消息手动 ack,Broker 才删除消息;不 ack 则消息重新投递
basicNack / basicReject 拒绝消息------requeue=true 重新入队(可能无限重试),false 丢弃或进死信
prefetch(QoS) 每个 Consumer 最多持有 N 条未 ack 消息------流控,防止消息全推给一个 Consumer
持久化三件套 Exchange durable + Queue durable + 消息 deliveryMode=2------Broker 重启不丢

️ 死信与延迟类

术语 一句话白话解释
死信交换机(DLX) Dead Letter Exchange------消息"死"了(被拒/过期/队列满)后转发到的 Exchange
死信队列(DLQ) 绑定到 DLX 的 Queue------死信消息最终落到这里,人工处理
TTL(Time To Live) 消息/队列的存活时间------超过 TTL 消息变死信(配合 DLX 实现延迟队列)
延迟队列插件 rabbitmq_delayed_message_exchange------官方插件,Exchange 层暂存消息到期才路由(规避 TTL 队头阻塞)
优先级队列 x-max-priority------队列内按优先级出队(高优先级先消费,代价是内存/性能)

一、四种 Exchange:路由规则与经典设计

1.1 对比与示例

类型 匹配规则 示例 适用
direct Routing Key == Binding Key(精确) key=pay.success → 绑定 pay.success 的 Queue 点对点
fanout 忽略 key,广播所有绑定 Queue 订单事件 → 库存/积分/通知/日志 Queue 广播/发布订阅
topic 模式匹配(* 一词,# 零或多词) order.* 匹配 order.create/order.pay;#.error 匹配所有 .error 灵活路由(最常用)
headers 按消息头属性匹配(x-match=all/any) headers={type:order} → 匹配该 header 的 Queue 少用(性能差)

1.2 topic Exchange 通配符

text 复制代码
Routing Key 格式:用 . 分隔的词,如 order.create.success

通配符:
*  匹配恰好一个词:order.* 匹配 order.create、order.pay,不匹配 order.create.success
#  匹配零或多个词:order.# 匹配 order、order.create、order.create.success

经典设计:

text 复制代码
Exchange: order-exchange (topic)
Binding1: order.create     → Queue: order-create-queue    (创建处理)
Binding2: order.*          → Queue: order-all-queue       (所有订单事件统计)
Binding3: #.fail           → Queue: order-fail-queue      (所有失败告警)

消息 Routing Key = order.create.fail
→ 命中 Binding2(order.*)和 Binding3(#.fail)
→ 进 order-all-queue 和 order-fail-queue 两个 Queue

1.3 路由失败的兜底:mandatory 与 AE

方案 行为 适用
mandatory=true 路由不到 Queue → 消息退回 Producer(ReturnCallback),Producer 落库补偿 需要感知"发丢了"
备用交换机(AE) Exchange 配 alternate-exchange,路由不到的消息转投 AE(通常绑一个兜底 Queue) Broker 侧兜底,Producer 无感
都不配(默认) 消息静默丢弃------最危险的默认行为 不可接受
java 复制代码
// mandatory + ReturnCallback(Spring AMQP)
rabbitTemplate.setMandatory(true);
rabbitTemplate.setReturnsCallback(returned ->
    log.error("消息路由失败退回: exchange={}, key={}, replyText={}, msg={}",
        returned.getExchange(), returned.getRoutingKey(),
        returned.getReplyText(), returned.getMessage()));

二、消息可靠性:三端确认的完整链路

2.1 三端可靠性

#mermaid-svg-5raEVdzN1PbgcLD2{font-family:Microsoft YaHei;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5raEVdzN1PbgcLD2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5raEVdzN1PbgcLD2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5raEVdzN1PbgcLD2 .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-5raEVdzN1PbgcLD2 .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-5raEVdzN1PbgcLD2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5raEVdzN1PbgcLD2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5raEVdzN1PbgcLD2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5raEVdzN1PbgcLD2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5raEVdzN1PbgcLD2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5raEVdzN1PbgcLD2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5raEVdzN1PbgcLD2 .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-5raEVdzN1PbgcLD2 .marker.cross{stroke:#0b0b0b;}#mermaid-svg-5raEVdzN1PbgcLD2 svg{font-family:Microsoft YaHei;font-size:16px;}#mermaid-svg-5raEVdzN1PbgcLD2 p{margin:0;}#mermaid-svg-5raEVdzN1PbgcLD2 .label{font-family:Microsoft YaHei;color:#333;}#mermaid-svg-5raEVdzN1PbgcLD2 .cluster-label text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-5raEVdzN1PbgcLD2 .cluster-label span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-5raEVdzN1PbgcLD2 .cluster-label span p{background-color:transparent;}#mermaid-svg-5raEVdzN1PbgcLD2 .label text,#mermaid-svg-5raEVdzN1PbgcLD2 span{fill:#333;color:#333;}#mermaid-svg-5raEVdzN1PbgcLD2 .node rect,#mermaid-svg-5raEVdzN1PbgcLD2 .node circle,#mermaid-svg-5raEVdzN1PbgcLD2 .node ellipse,#mermaid-svg-5raEVdzN1PbgcLD2 .node polygon,#mermaid-svg-5raEVdzN1PbgcLD2 .node path{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-5raEVdzN1PbgcLD2 .rough-node .label text,#mermaid-svg-5raEVdzN1PbgcLD2 .node .label text,#mermaid-svg-5raEVdzN1PbgcLD2 .image-shape .label,#mermaid-svg-5raEVdzN1PbgcLD2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-5raEVdzN1PbgcLD2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5raEVdzN1PbgcLD2 .rough-node .label,#mermaid-svg-5raEVdzN1PbgcLD2 .node .label,#mermaid-svg-5raEVdzN1PbgcLD2 .image-shape .label,#mermaid-svg-5raEVdzN1PbgcLD2 .icon-shape .label{text-align:center;}#mermaid-svg-5raEVdzN1PbgcLD2 .node.clickable{cursor:pointer;}#mermaid-svg-5raEVdzN1PbgcLD2 .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-5raEVdzN1PbgcLD2 .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-5raEVdzN1PbgcLD2 .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-5raEVdzN1PbgcLD2 .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-5raEVdzN1PbgcLD2 .edgeLabel{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-5raEVdzN1PbgcLD2 .edgeLabel p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-5raEVdzN1PbgcLD2 .edgeLabel rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-5raEVdzN1PbgcLD2 .labelBkg{background-color:rgba(243.9999999999, 220.9999999998, 255, 0.5);}#mermaid-svg-5raEVdzN1PbgcLD2 .cluster rect{fill:hsl(220.5882352941, 100%, 98.3333333333%);stroke:hsl(220.5882352941, 60%, 88.3333333333%);stroke-width:1px;}#mermaid-svg-5raEVdzN1PbgcLD2 .cluster text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-5raEVdzN1PbgcLD2 .cluster span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-5raEVdzN1PbgcLD2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Microsoft YaHei;font-size:12px;background:hsl(220.5882352941, 100%, 98.3333333333%);border:1px solid hsl(220.5882352941, 60%, 88.3333333333%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5raEVdzN1PbgcLD2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5raEVdzN1PbgcLD2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-5raEVdzN1PbgcLD2 .icon-shape,#mermaid-svg-5raEVdzN1PbgcLD2 .image-shape{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-5raEVdzN1PbgcLD2 .icon-shape p,#mermaid-svg-5raEVdzN1PbgcLD2 .image-shape p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);padding:2px;}#mermaid-svg-5raEVdzN1PbgcLD2 .icon-shape .label rect,#mermaid-svg-5raEVdzN1PbgcLD2 .image-shape .label rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-5raEVdzN1PbgcLD2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5raEVdzN1PbgcLD2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5raEVdzN1PbgcLD2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
① Producer→Broker
Publisher Confirm
Broker 收到消息回调 ack/nack

  • mandatory 退回路由失败的消息
    → 保证发送不丢。

② Broker 存储
持久化三件套
Exchange/Queue durable + 消息 deliveryMode=2
Quorum Queue 多数派落盘
→ Broker 重启不丢。

③ Broker→Consumer
Consumer Ack
Consumer 处理完手动 ack
不 ack 消息重新投递

  • prefetch 流控
    → 保证消费不丢。

2.2 Publisher Confirm(生产者确认)

java 复制代码
// 开启 confirm 模式(application.yml: spring.rabbitmq.publisher-confirm-type: correlated)
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
    if (ack) {
        // Broker 已收到消息(持久化消息 = 已落盘)
    } else {
        // Broker 没收到(nack)------重发或落库补偿
        log.error("消息发送失败: {}, correlationData={}", cause, correlationData);
        compensationService.saveForRetry(correlationData);
    }
});

三种 confirm 模式:

模式 行为 适用
none(默认) 不确认 不可靠,别用
correlated(推荐) 异步回调,不阻塞发送,correlationData 关联业务 生产标配
simple 同步 waitForConfirms 阻塞等确认 简单场景/测试

confirm 的时机 :普通消息 = 写入内存(持久化消息 = 落盘)后 ack;Quorum Queue = 多数派落盘后才 ack------这就是 Quorum 更可靠的体现。

2.3 Consumer Ack(消费者确认)

java 复制代码
// 手动 ack 模式(application.yml: spring.rabbitmq.listener.simple.acknowledge-mode: manual)
@RabbitListener(queues = "order-queue")
public void onMessage(Message message, Channel channel) throws IOException {
    long deliveryTag = message.getMessageProperties().getDeliveryTag();
    try {
        process(message);                       // ① 先业务
        channel.basicAck(deliveryTag, false);   // ② 后确认(Broker 才删消息)
    } catch (Exception e) {
        // requeue=false:不重新入队 → 有 DLX 进死信,没有则丢弃
        channel.basicNack(deliveryTag, false, false);
        log.error("消费失败进死信: {}", deliveryTag, e);
    }
}

三种 ack 模式:

模式 行为 可靠性
AUTO(Spring 默认) 监听器正常返回自动 ack,抛异常自动 nack+requeue 中(异常无限重入队可能死循环)
MANUAL 手动 basicAck/basicNack 高(推荐)
NONE 不 ack(fire and forget) 低(Consumer 挂=丢消息)

basicNack 的 requeue 抉择:

requeue 行为 风险
true 消息重新入队头,立即再投递 毒消息(永远处理失败)无限循环,CPU 打满
false 丢弃或进死信(配了 DLX) 要配 DLX 兜底,否则真丢

军规 :requeue=true 只用于"瞬时故障"(网络抖动),且要限制重试次数(header 里记 x-death 次数);业务异常一律 requeue=false + DLX 兜底。

2.4 prefetch:消费流控

java 复制代码
// 每个 Consumer 最多持有 10 条未 ack 消息
spring.rabbitmq.listener.simple.prefetch=10
prefetch 效果
太小(1) 每条都要等 ack 往返------吞吐低
太大(1000) 消息全推给一个 Consumer 囤着------其他 Consumer 空闲(负载不均),Consumer 挂了大量消息 requeue
适中(10~50) 吞吐与均衡的平衡------处理快的多拿,慢的少拿(天然负载均衡)

对比 Kafka :Kafka 是 Consumer 主动 poll(拉多少自己定),RabbitMQ 是 Broker push(prefetch 是 push 模式的"刹车")------推模型必须流控,否则 Consumer 被推爆。


三、死信交换机(DLX)

3.1 消息什么时候变"死信"

来源 说明
被拒绝 Consumer basicNack/basicReject 且 requeue=false
TTL 过期 消息/队列 TTL 到期
队列满 队列达到最大长度(x-max-length),最早的消息被挤出(或按 x-overflow=reject-head 拒新)

3.2 DLX 配置与流转

java 复制代码
// 声明业务队列(配死信路由)+ 死信队列
@Bean
public Queue orderQueue() {
    return QueueBuilder.durable("order-queue")
        .withArgument("x-dead-letter-exchange", "order-dlx")      // 死信交换机
        .withArgument("x-dead-letter-routing-key", "order.dead")  // 死信路由键
        .withArgument("x-max-length", 100000)                     // 队列上限(防积压撑爆)
        .build();
}

@Bean
public Queue deadLetterQueue() {
    return QueueBuilder.durable("order-dead-queue").build();
}

@Bean
public Binding dlqBinding() {
    return BindingBuilder.bind(deadLetterQueue())
        .to(dlxExchange()).with("order.dead");   // order-dlx + order.dead → order-dead-queue
}

死信流转 :消息在 order-queue 被拒/过期/队列满 → 转发到 order-dlx(按 order.dead 路由)→ 进 order-dead-queue → 人工处理/告警。

死信消息自带"验尸报告" :header 里的 x-death 记录了死信原因(rejected/expired/maxlen)、原队列、时间、次数------排查死信先看 x-death。

3.3 死信处理最佳实践

text 复制代码
① 监控:DLQ 有新消息 → P1 告警(和 RocketMQ %DLQ% 同款军规)
② 排查:看 x-death 原因 + 消费异常日志
③ 重放:修复 bug 后把 DLQ 消息重新 publish 回业务 Exchange(管理界面 Shovel 插件可批量搬)
④ 上限:DLQ 也要设 x-max-length + TTL------死信堆积同样会撑爆内存

四、延迟队列:TTL + DLX 与延迟插件

4.1 方案一:TTL + DLX(无插件)

RabbitMQ 没有原生延迟消息 ------用 TTL(消息过期)+ DLX(死信转发) 组合实现:
#mermaid-svg-AHZyzAjL83ZIL8fB{font-family:Microsoft YaHei;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AHZyzAjL83ZIL8fB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AHZyzAjL83ZIL8fB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AHZyzAjL83ZIL8fB .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-AHZyzAjL83ZIL8fB .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-AHZyzAjL83ZIL8fB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AHZyzAjL83ZIL8fB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AHZyzAjL83ZIL8fB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AHZyzAjL83ZIL8fB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AHZyzAjL83ZIL8fB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AHZyzAjL83ZIL8fB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AHZyzAjL83ZIL8fB .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-AHZyzAjL83ZIL8fB .marker.cross{stroke:#0b0b0b;}#mermaid-svg-AHZyzAjL83ZIL8fB svg{font-family:Microsoft YaHei;font-size:16px;}#mermaid-svg-AHZyzAjL83ZIL8fB p{margin:0;}#mermaid-svg-AHZyzAjL83ZIL8fB .label{font-family:Microsoft YaHei;color:#333;}#mermaid-svg-AHZyzAjL83ZIL8fB .cluster-label text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-AHZyzAjL83ZIL8fB .cluster-label span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-AHZyzAjL83ZIL8fB .cluster-label span p{background-color:transparent;}#mermaid-svg-AHZyzAjL83ZIL8fB .label text,#mermaid-svg-AHZyzAjL83ZIL8fB span{fill:#333;color:#333;}#mermaid-svg-AHZyzAjL83ZIL8fB .node rect,#mermaid-svg-AHZyzAjL83ZIL8fB .node circle,#mermaid-svg-AHZyzAjL83ZIL8fB .node ellipse,#mermaid-svg-AHZyzAjL83ZIL8fB .node polygon,#mermaid-svg-AHZyzAjL83ZIL8fB .node path{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-AHZyzAjL83ZIL8fB .rough-node .label text,#mermaid-svg-AHZyzAjL83ZIL8fB .node .label text,#mermaid-svg-AHZyzAjL83ZIL8fB .image-shape .label,#mermaid-svg-AHZyzAjL83ZIL8fB .icon-shape .label{text-anchor:middle;}#mermaid-svg-AHZyzAjL83ZIL8fB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AHZyzAjL83ZIL8fB .rough-node .label,#mermaid-svg-AHZyzAjL83ZIL8fB .node .label,#mermaid-svg-AHZyzAjL83ZIL8fB .image-shape .label,#mermaid-svg-AHZyzAjL83ZIL8fB .icon-shape .label{text-align:center;}#mermaid-svg-AHZyzAjL83ZIL8fB .node.clickable{cursor:pointer;}#mermaid-svg-AHZyzAjL83ZIL8fB .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-AHZyzAjL83ZIL8fB .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-AHZyzAjL83ZIL8fB .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-AHZyzAjL83ZIL8fB .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-AHZyzAjL83ZIL8fB .edgeLabel{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-AHZyzAjL83ZIL8fB .edgeLabel p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-AHZyzAjL83ZIL8fB .edgeLabel rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-AHZyzAjL83ZIL8fB .labelBkg{background-color:rgba(243.9999999999, 220.9999999998, 255, 0.5);}#mermaid-svg-AHZyzAjL83ZIL8fB .cluster rect{fill:hsl(220.5882352941, 100%, 98.3333333333%);stroke:hsl(220.5882352941, 60%, 88.3333333333%);stroke-width:1px;}#mermaid-svg-AHZyzAjL83ZIL8fB .cluster text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-AHZyzAjL83ZIL8fB .cluster span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-AHZyzAjL83ZIL8fB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Microsoft YaHei;font-size:12px;background:hsl(220.5882352941, 100%, 98.3333333333%);border:1px solid hsl(220.5882352941, 60%, 88.3333333333%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AHZyzAjL83ZIL8fB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-AHZyzAjL83ZIL8fB rect.text{fill:none;stroke-width:0;}#mermaid-svg-AHZyzAjL83ZIL8fB .icon-shape,#mermaid-svg-AHZyzAjL83ZIL8fB .image-shape{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-AHZyzAjL83ZIL8fB .icon-shape p,#mermaid-svg-AHZyzAjL83ZIL8fB .image-shape p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);padding:2px;}#mermaid-svg-AHZyzAjL83ZIL8fB .icon-shape .label rect,#mermaid-svg-AHZyzAjL83ZIL8fB .image-shape .label rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-AHZyzAjL83ZIL8fB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AHZyzAjL83ZIL8fB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AHZyzAjL83ZIL8fB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
Producer 发延迟消息
设置 TTL=30min 发到延迟 Queue,
无 Consumer

延迟 Queue 消息等待 30min
,TTL 倒计时 没有 Consumer 消费。

30min 后 TTL 过期 消息变死信。
DLX 转发 按死信路由键转发到业务 Queue
业务 Queue Consumer 消
费,执行延迟任务 如:订单超时取消。

java 复制代码
// 延迟队列:消息 TTL 30 分钟,过期后转发到业务队列
@Bean
public Queue delayQueue() {
    return QueueBuilder.durable("order-delay-queue")
        .withArgument("x-message-ttl", 1800000)                   // TTL 30 分钟
        .withArgument("x-dead-letter-exchange", "order-exchange") // 过期后转发
        .withArgument("x-dead-letter-routing-key", "order.timeout")
        .build();
}
// 注意:延迟队列本身没有 Consumer------消息在里面"等死"

4.2 两个坑

坑 说明 解法
队列 TTL 按队头判断 RabbitMQ 只检查队头消息 是否过期------队头 TTL 长、后面 TTL 短的消息即使过期也不转发(队头阻塞) ① 同一队列只用相同 TTL (按延迟时长分队列:delay-5s/delay-1m/delay-30m)② 用消息级 TTL+延迟插件
延迟精度 TTL 到期后死信转发有延迟(秒级)------不是精确定时 消费时二次校验时间(和 RocketMQ 同款军规)

4.3 方案二:延迟插件(推荐)

shell 复制代码
# 安装官方插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
java 复制代码
// 声明延迟 Exchange(x-delayed-message 类型)
@Bean
public CustomExchange delayExchange() {
    Map<String, Object> args = Map.of("x-delayed-type", "direct");
    return new CustomExchange("order-delay-exchange", "x-delayed-message", true, false, args);
}

// 发送:任意延迟时间(毫秒级精度,header 里带 x-delay)
rabbitTemplate.convertAndSend("order-delay-exchange", "order.timeout", msg,
    m -> { m.getMessageProperties().setDelay(1800_000); return m; });  // 延迟 30min

插件原理 :消息暂存在 Exchange 层 (Mnesia 表),到期才路由到 Queue------规避了队列 TTL 的队头阻塞,支持任意延迟时间。

4.4 三种延迟方案对比

方案 精度 任意时间 坑
TTL+DLX(分队列) 秒级 ❌(固定几档) 队列数膨胀
TTL+DLX(消息级 TTL) 秒级 ✅ 队头阻塞
延迟插件 毫秒级 ✅ 单 Exchange 延迟消息量大时性能降(暂存 Mnesia)
(对比)RocketMQ 秒级 4.x ❌ 18 级 / 5.x ✅ 内核自带,无插件依赖

五、其他消息特性

5.1 优先级队列

java 复制代码
// 队列支持 10 级优先级
QueueBuilder.durable("task-queue").withArgument("x-max-priority", 10).build();

// 发送时指定优先级(0~255,映射到队列的 max 级)
MessageProperties props = new MessageProperties();
props.setPriority(9);   // VIP 任务高优先级

代价 :优先级排序要内存+CPU(队列内堆排序)------max-priority 别设太大(≤10),高吞吐队列慎用。

5.2 消息属性与持久化

java 复制代码
MessageProperties props = new MessageProperties();
props.setDeliveryMode(MessageDeliveryMode.PERSISTENT);  // deliveryMode=2 持久化
props.setMessageId(orderId);                            // 消息 ID(幂等用业务 Key)
props.setContentType("application/json");
props.setExpiration("1800000");                         // 消息级 TTL(毫秒字符串)
props.setHeader("x-retry-count", 0);                    // 自定义 header(重试计数)

持久化三件套缺一不可 :Exchange durable=true + Queue durable=true + 消息 deliveryMode=2------任何一个不持久化,重启都会丢(09 篇 3.1:持久化≠实时刷盘,confirm 才保不丢)。

5.3 消费幂等(与 RocketMQ 同款军规)

RabbitMQ 同样只保证 At Least Once------重复来源:Consumer ack 前崩溃重投、requeue=true 重试、网络重发。

java 复制代码
@RabbitListener(queues = "order-queue")
public void onMessage(Message message, Channel channel) throws IOException {
    String orderId = message.getMessageProperties().getMessageId();  // 业务 Key
    // 幂等三板斧(06-02-A 篇六章同款):
    // ① 状态机:订单状态不符直接 ack 跳过
    // ② 唯一键:流水表 orderId 唯一索引,重复插入捕获 DuplicateKeyException
    // ③ 去重表:Redis SETNX msg:dedup:{orderId}
    try {
        if (!orderService.processIdempotent(orderId)) {
            log.warn("重复消息,跳过: {}", orderId);
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    } catch (Exception e) {
        channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
    }
}

注意 :幂等键用业务 Key(messageId 设成订单号),不要用 RabbitMQ 自动生成的 deliveryTag(requeue 后会变)。


六、跑一遍:确认机制与死信全流程

下面是可以直接照做的实操示例(延续 09 篇的 Docker 环境),每一步给出真实结果。

6.1 观察 Publisher Confirm 与 Return

java 复制代码
// Spring Boot 配置(application.yml)
// spring.rabbitmq.publisher-confirm-type: correlated
// spring.rabbitmq.publisher-returns: true
// spring.rabbitmq.template.mandatory: true

@Test
void testConfirmAndReturn() {
    rabbitTemplate.setConfirmCallback((cd, ack, cause) ->
        System.out.println("Confirm: ack=" + ack + ", cause=" + cause));
    rabbitTemplate.setReturnsCallback(r ->
        System.out.println("Return: key=" + r.getRoutingKey() + ", text=" + r.getReplyText()));

    // ① 正常发送(路由命中)
    rabbitTemplate.convertAndSend("order-exchange", "order.create", "msg-1");
    // ② 路由不到的 Key(触发 Return)
    rabbitTemplate.convertAndSend("order-exchange", "order.unknown", "msg-2");
}

真实输出:

text 复制代码
Return: key=order.unknown, text=NO_ROUTE          ← ② 先触发 Return(路由失败退回)
Confirm: ack=true, cause=null                     ← ①② 都会 Confirm(消息到达 Exchange 即 ack)
Confirm: ack=true, cause=null

💡 关键认知 :Confirm 只保证"消息到达 Exchange",不保证"进入 Queue" ------②的消息 Confirm=ack 但被 Return 了。只配 Confirm 不配 mandatory+ReturnCallback,路由失败的消息就静默丢了(这就是 1.3 节"最危险的默认行为")。

6.2 死信全流程

shell 复制代码
# ③ 给 order-create-queue 配 DLX(重建队列,RabbitMQ 队列参数不可修改)
docker exec rabbit rabbitmqadmin declare exchange name=order-dlx type=direct durable=true
docker exec rabbit rabbitmqadmin declare queue name=order-dead-queue durable=true
docker exec rabbit rabbitmqadmin declare binding source=order-dlx \
  destination=order-dead-queue routing_key="order.dead"
docker exec rabbit rabbitmqadmin declare queue name=order-create-queue durable=true \
  arguments='{"x-dead-letter-exchange":"order-dlx","x-dead-letter-routing-key":"order.dead"}'

# ④ 发一条消息,然后"拒绝且不重新入队"(模拟消费失败进死信)
docker exec rabbit rabbitmqadmin publish exchange=order-exchange \
  routing_key=order.create payload='{"orderId":1002}'
docker exec rabbit rabbitmqadmin get queue=order-create-queue ackmode=nack_requeue_false count=1

# ⑤ 查看死信队列
docker exec rabbit rabbitmqadmin list queues name messages

⑤ 的输出(被拒消息经 DLX 转到了死信队列):

text 复制代码
+--------------------+----------+
| name               | messages |
+--------------------+----------+
| order-create-queue | 0        |   ← 原队列已空
| order-dead-queue   | 1        |   ← 死信落在这里
+--------------------+----------+

# ⑥ 取死信看"验尸报告"(x-death header)
docker exec rabbit rabbitmqadmin get queue=order-dead-queue count=1 --format=json

⑥ 输出中的关键字段:

json 复制代码
{
  "payload": "{\"orderId\":1002}",
  "properties": {
    "headers": {
      "x-death": [{
        "count": 1,
        "reason": "rejected",              ← 死信原因:被拒绝
        "queue": "order-create-queue",     ← 原队列
        "exchange": "order-exchange",
        "routing-keys": ["order.create"],
        "time": "2024-01-01T10:05:00Z"
      }]
    }
  }
}

💡 对照理解 :⑥的 x-death 就是 3.2 节说的"验尸报告"------reason 字段区分三种死信来源(rejected=被拒 / expired=TTL 过期 / maxlen=队列满),count 记录死信次数(多次死信会累加)。生产排查死信第一步就是看 x-death 的 reason 和 queue。


七、总结

7.1 一张图回顾全文

#mermaid-svg-09bPQaSpzmT0bM9o{font-family:Microsoft YaHei;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-09bPQaSpzmT0bM9o .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-09bPQaSpzmT0bM9o .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-09bPQaSpzmT0bM9o .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-09bPQaSpzmT0bM9o .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-09bPQaSpzmT0bM9o .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-09bPQaSpzmT0bM9o .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-09bPQaSpzmT0bM9o .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-09bPQaSpzmT0bM9o .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-09bPQaSpzmT0bM9o .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-09bPQaSpzmT0bM9o .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-09bPQaSpzmT0bM9o .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-09bPQaSpzmT0bM9o .marker.cross{stroke:#0b0b0b;}#mermaid-svg-09bPQaSpzmT0bM9o svg{font-family:Microsoft YaHei;font-size:16px;}#mermaid-svg-09bPQaSpzmT0bM9o p{margin:0;}#mermaid-svg-09bPQaSpzmT0bM9o .label{font-family:Microsoft YaHei;color:#333;}#mermaid-svg-09bPQaSpzmT0bM9o .cluster-label text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-09bPQaSpzmT0bM9o .cluster-label span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-09bPQaSpzmT0bM9o .cluster-label span p{background-color:transparent;}#mermaid-svg-09bPQaSpzmT0bM9o .label text,#mermaid-svg-09bPQaSpzmT0bM9o span{fill:#333;color:#333;}#mermaid-svg-09bPQaSpzmT0bM9o .node rect,#mermaid-svg-09bPQaSpzmT0bM9o .node circle,#mermaid-svg-09bPQaSpzmT0bM9o .node ellipse,#mermaid-svg-09bPQaSpzmT0bM9o .node polygon,#mermaid-svg-09bPQaSpzmT0bM9o .node path{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-09bPQaSpzmT0bM9o .rough-node .label text,#mermaid-svg-09bPQaSpzmT0bM9o .node .label text,#mermaid-svg-09bPQaSpzmT0bM9o .image-shape .label,#mermaid-svg-09bPQaSpzmT0bM9o .icon-shape .label{text-anchor:middle;}#mermaid-svg-09bPQaSpzmT0bM9o .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-09bPQaSpzmT0bM9o .rough-node .label,#mermaid-svg-09bPQaSpzmT0bM9o .node .label,#mermaid-svg-09bPQaSpzmT0bM9o .image-shape .label,#mermaid-svg-09bPQaSpzmT0bM9o .icon-shape .label{text-align:center;}#mermaid-svg-09bPQaSpzmT0bM9o .node.clickable{cursor:pointer;}#mermaid-svg-09bPQaSpzmT0bM9o .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-09bPQaSpzmT0bM9o .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-09bPQaSpzmT0bM9o .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-09bPQaSpzmT0bM9o .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-09bPQaSpzmT0bM9o .edgeLabel{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-09bPQaSpzmT0bM9o .edgeLabel p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-09bPQaSpzmT0bM9o .edgeLabel rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-09bPQaSpzmT0bM9o .labelBkg{background-color:rgba(243.9999999999, 220.9999999998, 255, 0.5);}#mermaid-svg-09bPQaSpzmT0bM9o .cluster rect{fill:hsl(220.5882352941, 100%, 98.3333333333%);stroke:hsl(220.5882352941, 60%, 88.3333333333%);stroke-width:1px;}#mermaid-svg-09bPQaSpzmT0bM9o .cluster text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-09bPQaSpzmT0bM9o .cluster span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-09bPQaSpzmT0bM9o div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Microsoft YaHei;font-size:12px;background:hsl(220.5882352941, 100%, 98.3333333333%);border:1px solid hsl(220.5882352941, 60%, 88.3333333333%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-09bPQaSpzmT0bM9o .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-09bPQaSpzmT0bM9o rect.text{fill:none;stroke-width:0;}#mermaid-svg-09bPQaSpzmT0bM9o .icon-shape,#mermaid-svg-09bPQaSpzmT0bM9o .image-shape{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-09bPQaSpzmT0bM9o .icon-shape p,#mermaid-svg-09bPQaSpzmT0bM9o .image-shape p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);padding:2px;}#mermaid-svg-09bPQaSpzmT0bM9o .icon-shape .label rect,#mermaid-svg-09bPQaSpzmT0bM9o .image-shape .label rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-09bPQaSpzmT0bM9o .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-09bPQaSpzmT0bM9o .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-09bPQaSpzmT0bM9o :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} RabbitMQ 消息特性与消费
路由。
四种 Exchange:direct/fanout/topic/headers
topic 通配符 * 一词 # 多词
路由不到默认丢弃!
mandatory 退回 + AE 兜底。

三端可靠。
Publisher Confirm(到 Exchange)

  • Return(进 Queue)
    持久化三件套 durable×2+deliveryMode=2
    Consumer 手动 ack,先业务后确认
    prefetch 10~50 流控。

死信与延迟。
死信三来源:被拒/过期/队列满
x-death 验尸报告
延迟=TTL+DLX(队头阻塞坑)
或延迟插件(任意时间,推荐)。

幂等。
At Least Once 是承诺
三板斧:状态机/唯一键/去重表
幂等键用业务 Key 不用 deliveryTag。

7.2 核心要点浓缩(十二条)

  1. 四种 Exchange :direct 精确匹配、fanout 广播、topic 通配符(* 一词/# 多词)、headers 属性匹配------topic 最常用,headers 少用。
  2. 默认 Exchange :空串 direct,Queue 自动以队列名绑定------简单点对点场景直接用默认 Exchange。
  3. 路由不到默认丢弃 :mandatory=true 退回 Producer(ReturnCallback)或配 AE 兜底------Confirm=ack 不代表进了 Queue,只配 Confirm 会静默丢。
  4. Publisher Confirm :correlated 异步回调(生产标配)------Quorum Queue 多数派落盘才 ack,经典队列落盘即 ack。
  5. Consumer Ack :手动模式"先业务后 basicAck"------AUTO 模式异常无限 requeue 可能死循环。
  6. basicNack 的 requeue 抉择 :true 只用于瞬时故障(防毒消息死循环),业务异常一律 false + DLX 兜底。
  7. prefetch 流控 :10~50 平衡吞吐与均衡------push 模式必须有刹车(对比 Kafka pull 自控)。
  8. 持久化三件套 :Exchange durable + Queue durable + deliveryMode=2------缺一重启就丢;持久化≠实时刷盘,confirm 才保不丢。
  9. 死信三来源 :被拒(requeue=false)、TTL 过期、队列满(x-max-length 挤出)------x-death header 是验尸报告(reason/queue/count)。
  10. 延迟队列两方案 :TTL+DLX(队列级 TTL 有队头阻塞坑 ------同队列同 TTL 或消息级 TTL)、延迟插件(任意时间毫秒精度,推荐)。
  11. 优先级队列 :x-max-priority ≤10------堆排序有内存/CPU 代价,高吞吐队列慎用。
  12. 消费幂等 :At Least Once 承诺下三板斧(状态机/唯一键/去重表)------幂等键用业务 Key(messageId=订单号),不用 deliveryTag(requeue 会变)。

📌 最后一句话 :RabbitMQ 的可靠性是"三端确认环环相扣 "------发送端 Confirm+Return 双保险(到 Exchange + 进 Queue 都要确认),存储端持久化三件套+Quorum 多数派,消费端手动 ack+prefetch 流控+DLX 兜底。任何一端偷懒(默认配置)都有丢失窗口 ------RabbitMQ 的默认值偏向"易用"而不是"可靠",生产必须逐项显式配置。而 TTL+DLX 的延迟方案提醒我们:用通用机制组合出特性时,一定要搞清楚组合的边界条件(队头阻塞)------这正是"延迟插件"存在的意义。


📌 配套阅读:

上一篇:《06-17-A-RabbitMQ架构与存储原理详解.md》

下一篇:《06-19-A-RabbitMQ高可用与生产调优详解.md》

如果这篇文章对你有帮助,欢迎点赞、收藏、关注!

相关推荐
闻哥2 小时前
分布式任务调度框架:XXL-Job / ElasticJob / DolphinScheduler / SchedulerX 架构对比与选型
分布式·架构·wpf
明月无心照西山2 小时前
分布式任务系统的监控告警分级与自愈设计——以帮帮星球为例
分布式
guo_wen_qiang3 小时前
kafka一直restarting,报错InconsistentClusterIdException
分布式·kafka
实战派K8S&DB3 小时前
TDSQL 核心模块与进程体系
运维·数据库·分布式·sql·mysql
仍然.3 小时前
Redis---分布式锁
数据库·redis·分布式
此时不提桶,更待何时3 小时前
06-19-A-RabbitMQ高可用与生产调优详解
rabbitmq
小小龙学IT4 小时前
etcd 深度解析:Go 分布式一致性 KV 存储与 Raft 共识实战
分布式·golang·etcd
小师兄吃牛肉12 小时前
Java 同步系列之 ZooKeeper 分布式锁
java·分布式·java-zookeeper