<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>消息队列 on 安橙的博客</title><link>https://blog.ans20xx.com/tags/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/</link><description>Recent content in 消息队列 on 安橙的博客</description><generator>Hugo -- 0.163.3</generator><language>zh</language><lastBuildDate>Wed, 18 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.ans20xx.com/tags/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/index.xml" rel="self" type="application/rss+xml"/><item><title>RocketMQ 复习</title><link>https://blog.ans20xx.com/posts/backend/rocketmq-%E5%AD%A6%E4%B9%A0/</link><pubDate>Wed, 18 Feb 2026 00:00:00 +0000</pubDate><guid>https://blog.ans20xx.com/posts/backend/rocketmq-%E5%AD%A6%E4%B9%A0/</guid><description>&lt;h1 id="概述"&gt;概述&lt;/h1&gt;
&lt;div
class="mindmap-container"
id="mindmap-38471562"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-38471562" style="display:none;"&gt;
- 概述
- 定位
- RocketMQ 是一个分布式消息中间件，用于在分布式系统中以异步方式传递时间/数据
- 典型问题
- 异步解耦
- 场景：下单后做扣库存、发优惠券、发短信、写审计日志
- 没用 MQ：下单接口串行调用 N 个下游 -&amp;gt; 延迟高、耦合重、下游挂了全挂
- 用 MQ：下单服务只负责写订单 &amp;#43; 发消息，下游异步消费，链路变短、隔离故障、便于扩展
- 削峰填谷
- 场景：大促瞬时 QPS 飙升，下游撑不住
- 用 MQ：把瞬时峰值写入 MQ，消费者按能力稳定拉取 -&amp;gt; 系统不被打爆
- 广播/集群消费
- 广播：配置刷新、缓存预热、全量通知
- 集群：订单履约、发货、对账（同组只要处理一次）
- 顺序/延迟/事务
- 顺序：同一订单状态流转必须按照顺序处理
- 延迟：30 分钟未支付自动关单
- 事务：下单写库 &amp;#43; 发消息要一致性
- 领域模型
- Topic/MessageQueue（并发与顺序的载体）
- Topic：逻辑分类
- MessageQueue（队列/分区）：Topic 下的物理分片
- 并发的本质：多个队列=&amp;gt;多个消费者实例并行消费
- 顺序的边界：只保证同一队列内有序，跨队列无需
- 原因：MessageQueue 带来了水平扩展吞吐（分片并行）&amp;#43;提供队列内顺序语义
- Producer 生产者
- 生产者发送消息时，核心要决定：这条消息进入哪个队列
- 普通消息：轮询/负载均衡选择队列（提升吞吐）
- 顺序消息：按业务 key 做一致性路由到同一队列，保证顺序
- ConsumerGroup 消费组
- 消费组：一组消费者实例共享同一套消费进度
- 集群消费：同组内分摊队列
- 广播消费：每个实例都处理全量消息
- 同一个 Topic，两个不同的 ConsumerGroup 相当于两套独立的订阅者，各自消费一份完整消息流
- 卖点
- 高吞吐
- 顺序写：消息落到 CommitLog -&amp;gt; 磁盘友好
- 零拷贝/高效网络传输：减少内核态/用户态拷贝开销
- 批量与异步：批量写入、批量拉取、异步刷盘/复制
- 读写分离：写走 CommitLog，读通过索引定位
- 可扩展
- Topic 多队列 -&amp;gt; 消费端扩容实例可提升并发
- Broker 集群扩容 -&amp;gt; 分摊存储与 I/O 压力
- NameServer 做路由发现 -&amp;gt; Producer/Consumer 动态感知集群变化
- 靠队列分片 &amp;#43; Broker 横向扩展 &amp;#43; 消费组负载均衡
- 语义能力
- 至少一次投递与重复消费
- RocketMQ 工程实践通常是至少一次：可能重复，但不丢
- 业务必须幂等
- 重试与死信
- 消费失败 -&amp;gt; 重试
- 达到最大次数仍然失败 -&amp;gt; 进入死信队列
- 生产实践：DLQ 监控高进 &amp;#43; 人工/自动补偿 &amp;#43; 重新投递
- 事务消息（最终一致性）
- 目标：本地事务与消息发送一致
- 核心机制：半消息（先存 broker 不投递）-&amp;gt; 本地事务 -&amp;gt; commit 才投递；不确定则回查
- 它解决的是最终一致性，不是强一致 ACID
&lt;/textarea&gt;
&lt;h1 id="核心概念"&gt;核心概念&lt;/h1&gt;
&lt;div
class="mindmap-container"
id="mindmap-51476823"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-51476823" style="display:none;"&gt;
- 核心概念
- Topic
- 定义：消息的逻辑分类，Producer 发送到 Topic，Consumer 订阅 Topic。
- 关键点：Topic 本身不决定并发，并发来自 Topic 下的 MessageQueue 数量
- 一个 Topic 通常会在多个 Broker 上分布存储，每个 Broker 上持有一些队列分片
- MessageQueue
- 定义：Topic 的物理分片，是投递与顺序的基本单元。
- 并发能力=队列数上限：同哦个 ConsumerGroup 里，一个队列同一个时刻只会被一个消费者实例消费
- 顺序边界：RocketMQ 的顺序语义通常是队列内有序，跨队列不保证
- 路由载体：Producer 发送时必须选择一个队列（轮询/哈希/自定义）
- Producer 生产者
- 职责：构造消息、选择 Topic 队列、发送、处理失败重试
- Producer 会先拿到 Topic 的路由信息（队列分布在哪些 Broker）
- 发送失败通常会重试/换 Broker（取决于客户端策略与路由状态）
- 发送模式
- 同步：拿到 sendResult 才返回（最常用）
- 异步：回调（高吞吐/低延迟）
- 单向：不关心结果（日志/打点）
- Consumer（消费者）
- 职责：拉取消息（Pull 体系，Push 是封装）、本地处理、成功后提交 offset，失败触发重试
- RocketMQ PushConsumer 本质是客户端内部循环 Pull &amp;#43; 回调你业务代码
- 消费并发：由消费线程数 &amp;#43; 队列分配决定
- ConsumerGroup（消费组）
- 定义：一组消费者实例，共享同一套消费进度（offset），一起消费 Topic。
- CLUSTERING（集群消费）：同组分摊消费（每条只处理一次）
- BROADCASTING（广播消费）：每个实例都处理全量（各自进度）
- NameServer
- 定位：路由注册与发现（轻量注册中心，不像 Kafka 把协调状态放在上面）
- Broker 启动后像 NameServer 注册：Topic -&amp;gt; Broker -&amp;gt; 队列信息
- Producer/Consumer 定期从 NameServer 拉取最新路由
- NameServer 挂了是否可以发消息
- 短期通常能发（客户端还有路由缓存），但路由无法更新；长期不行，且新 Topic/新 Broker 不可见。
- Broker
- 职责：接收消息，持久化存储，为消费者提供拉取、维护消费进度相关能力、做复制。
- 消息一般先写 CommitLog （顺序写），再构建队列索引。
- 吞吐高的原因：顺序写&amp;#43;批量&amp;#43;高效 IO 路径
- Offset （消费进度）
- 定义：ConsumerGroup 在每个 MessageQueue 上的消费位置
- 成功消费 -&amp;gt; 提交 offset
- 失败 -&amp;gt; 不提交 -&amp;gt; 后续重试/再次提交
- 数据流
- 生产链路
- 拿路由
- Producer 启动后从 NameServer 拉取 Topic 路由：有哪些 Broker、每个 Broker 上有哪些队列
- 选队列
- Produer 根据策略选择一个 MessageQueue
- 普通消息：轮询/负载均衡
- 顺序消息：按业务 key 哈希到固定队列
- 发送到 Broker
- Producer 把消息发送到队列所在 Broker
- 持久化与应答
- Broker 持久化成功后返回 sendResult，Producer 认为发送成功
- 消费链路
- 订阅与分配
- Consumer 加入 ConumserGroup，订阅 Topic
- 在集群模式下，同组实例会进行队列分配：每个 MessageQueue 分配给某个实例
- 拉取
- 被分配到队列的 Consumer 维护该队列的 offset，向 Broker 发起拉取请求
- 拉取这个队列从 offset=N 开始的下一批消息
- 本地处理
- Consumer 收到消息后调用你的业务处理逻辑（线程池并发执行）
- 提交 Offset
- 业务成功 -&amp;gt; 提交 offset（推进进度）
&lt;/textarea&gt;
&lt;h1 id="可靠性语义幂等重试死信"&gt;可靠性、语义、幂等、重试、死信&lt;/h1&gt;
&lt;div
class="mindmap-container"
id="mindmap-51278364"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-51278364" style="display:none;"&gt;
- 可靠性/语义/幂等/重试/死信
- 消息语义
- 三种语义
- At-most-once（至多一次）：不重复，但可能丢
- At-least-once（至少一次）：尽量不丢，但可能重复（RocketMQ 采用）
- Exactly-once（恰好一次）：不丢不重
- 为什么会重复
- 本质：分布式不确定性，无法在网络超时常见里判断对方是否已经成功
- 生产端导致重复：超时不等于失败
- Producer 发出了 send 请求
- Broker 实际写成功了，但 ack 在路上丢了/Producer 超时
- Producer 认为失败 -&amp;gt; 重试发送
- Broker 上存在两条业务等价消息
- 消费端导致重复：处理成功但提交 offset 失败/延迟
- Consumer 拉到消息并执行成功
- 在提交 offset 前发生进程重启/网络抖动/提交失败
- 下次启动从旧 offset 拉 -&amp;gt; 同一消息再次被处理
- 重试与死信：失败后到底怎么流转
- 消费失败 -&amp;gt; 重试：两类消费方式的区别
- 并发消费：消息可并行处理；失败后会触发稍后重投
- 顺序消费：同队列内严格顺序；失败会卡住队列，知道成功或打到策略
- 重试次数与延迟
- 消费失败后，消息会进入“重试主题/重试队列“
- 每次重试都会有一定的延迟
- 达到最大重试次数后仍然失败 -&amp;gt; 进入死信队列
- DLQ 常见命名 %DLQ%&amp;lt;ConsumerGroup&amp;gt;
- DLQ 工程治理
- 监控报警
- DLQ 堆积量、进入 DLQ 的速率、重试次数分布、消费失败率
- 分类原因
- 可重试：下游超时、偶发网络、锁冲突
- 不可重试：参数非法、业务校验失败、数据缺失
- Offset 管理
- Offset 是什么
- Offset 是 ConsumerGroup 在每个 MessageQueue 上的消费位置
- 不是全局一个值，而是 (group,topic,queueId) -&amp;gt; offset
- 正确提交时机
- 处理成功后再提交
&lt;/textarea&gt;
&lt;h1 id="性能与扩展顺序与分区堆积治理"&gt;性能与扩展、顺序与分区、堆积治理&lt;/h1&gt;
&lt;div
class="mindmap-container"
id="mindmap-53418627"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-53418627" style="display:none;"&gt;
- 性能与扩展、顺序与分区、堆积治理
- 吞吐与并发怎么调
- 吞吐链路拆解，多个环节的 min
- Producer 发送能力
- Broker 写入能力
- Consumer 拉取与处理能力
- 队列分片与分配：队列数决定
- 并发的硬上限：Queue 数决定可扩展性
- 集群消费模式下，同一个 ConsumerGroup 内，一个 MessageQueue 同一时刻只会分配给一个消费者实例
- 有效消费实例并行度 &amp;lt;= 队列数 Q
- 有 C 个实例：有效利用 = min(Q,C)
- 线程数只能提高单实例处理并行，队列数太少时，扩容实例不涨吞吐
- 调整的三类杠杆
- 队列数
- 现象：加消费者实例吞吐不涨/涨很少
- 原因：Q 太小，很多实例分不到队列
- 操作：提高 Topic 队列数
- 消费者实例数
- 前提：Q 足够
- 收益：线性提升
- 消费者线程数/批量参数
- 适用 Q 足够但实例受限或业务处理轻的场景
- 堆积定位
- 堆积的数学本质
- 堆积增长 = 生产速率 &amp;gt; 消费速率，差值积累在 broker
- 堆积原因分类
- 消费变慢
- 失败重试太多
- 生产突增
- Broker 压力抖动
- 堆积排查步骤
- 确定堆积是全局还是局部
- 如果是局部队列对接，大概率是热点 key/顺序路由/某实例异常
- 消费失败率与重试量
- 失败率高 -&amp;gt; 先止血，否则越修越崩
- 识别同一类异常栈是否集中
- 看单消息处理耗时分布
- 平均不重要，重点看 p95/p99
- p99 高往往来自：慢 SQL、远程调用尾延迟、锁竞争
- 看下游容量
- 看队列数与分配
- 看 Broker 层资源
- 堆积治理手段
- 止血
- 限流生产端：控制入口
- 失败隔离：把异常消息旁路到补偿 Topic/DLQ，避免拖垮主消费
- 降级业务逻辑：先做核心动作，其他异步/延后
- 恢复吞吐
- 扩容消费者实例
- 提高批量拉取/批量处理
- 优化热点：把热点 key 拆散
- 若某些队列极端堆积：考虑迁移/重新分配队列所在 broker
- 根治
- 优化热点：慢 SQL、缓存、异步化、批处理
- 调整队列数与 key 策略
- 建立 DLQ/补偿闭环与告警
- 压测与容量规划：明确峰值可承受的 TPS 与延迟
&lt;/textarea&gt;
&lt;h1 id="存储与高可用"&gt;存储与高可用&lt;/h1&gt;
&lt;div
class="mindmap-container"
id="mindmap-37461528"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-37461528" style="display:none;"&gt;
- 存储与高可用
- Broker 存储核心
- 三类文件
- CommitLog：消息本体的唯一真相源
- 所有 Topic 的消息都会追加吸入 CommitLog（不是每个队列一个日志，而是统一日志）
- 写入模型是 append-only（追加写），是 RocketMQ 的高吞吐基础之一
- ConsumeQueue：面向消费的队列索引
- 消费者按照 MessageQueue 语义来消费，CommitLog 是全局混合写入的，需要一个队列视角的索引结构把队列映射回 CommitLog
- ConsumeQueue 的本质是：每个 (topic, queueId) 一套逻辑队列索引，记录这条队列消息在 CommitLog 的物理位置等信息
- ConsumeQueue 是可重建的-Broker 异常后基于 CommitLog 恢复并重建缺失的 ConsumeQueue 索引，因此 ConsumeQueue 对绝对不丢要求没那么高
- IndexFile：按 key 查询的哈希索引
- 用于按 message key 做快速查询
- 写入流程
- 流程
- Producer 把消息发送到 Broker
- Broker 顺序追加写 CommitLog
- 再异步/批量地更新 ConsumeQueue/IndexFile
- 原因
- 顺序写 CommitLog 最快
- 索引可以延迟/批量构建，并且 ConsumeQueue 丢了也能重建
- 读取链路
- 消费者按队列 (topic, queueId) 消费
- Consumer 拉取时携带 offset
- Broker 通过 ConsumeQueue 把队列 offset 映射到 CommitLog 的物理位置
- 再从 CommitLog 把消息读出来返回给 Consumer
- 吞吐高：顺序写&amp;#43;mmap&amp;#43;零拷贝&amp;#43;批量
- 顺序写：CommitLog append-only 模式写磁盘
- mmap 内存映射与 MappedFile 抽象
- Broker 用 mmap 把文件映射为虚拟内存，写入像写内存一样，减少传统 read/write 的系统调用与拷贝成本
- 零拷贝方向
- 批量
- 批量写入、批量拉取能显著摊薄网络往返与系统调用开销
- HA：复制、切换、延迟与一致性取舍
- 传统 Master/Slave：复制延迟与一致性
- Master 负责写入，Slave 复制数据做冗余
- 关键变量：复制是同步还是异步，直接决定
- RPO（数据丢失窗口）：异步复制可能丢失最近一段
- RTO（恢复时间）：切换/重连需要时间
- 自动主从切换：Controller
- Controller：把谁是主、怎么选主、怎么切这个协调逻辑集中管理，从而支持自动故障转移
- 切换时关注
- 选主/仲裁机制
- 路由更新
- 复制进度
- 业务容忍度
- RocketMQ-on-DLedger(Raft)：更强一致的 HA 思路
- DLedge 把 CommitLog 的复制变成 Raft 日志复制，从而提高一致性并提供自动选主
- 代价：写路径更重，延迟更高，但一致性更强、切换更自动化
&lt;/textarea&gt;</description></item></channel></rss>