<?xml version="1.0" encoding="utf-8"?>
<ul>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。本速查以 RocketMQ 5.x 为主线，兼顾 4.x 常用能力。不同版本命令、参数和默认值可能变化，生产操作前以当前版本文档为准。核心概念            概念      说明                  NameServer      轻量路由中心，维护 Broker 和 Topic 路由              Broker      消息存储与服务节点              Topic      消息逻辑分类              Queue      Topic 内物理并行队列              ProducerGroup      生产者逻辑分组              ConsumerGroup      消费者逻辑分组              CommitLog      所有 Topic 消息的物理顺序日志              ConsumeQueue      Topic 队列逻辑索引              IndexFile      Key 与时间查询索引              DLedger / Controller      副本一致性与自动高可用相关模式              Proxy      5.x 接入层，可转发或协调客户端请求      常用端口            服务      常见端口                  NameServer      9876              Broker      10911、10909、10912 等随配置变化              Proxy      8080、8081 等随配置变化              Dashboard      8080      端口以实际配置文件为准。Docker 快速启动docker run -d --name rocketmq-namesrv apache/rocketmq:5.3.1 sh mqnamesrvdocker run -d \  --name rocketmq-broker \  --link rocketmq-namesrv:namesrv \  -e "NAMESRV_ADDR=namesrv:9876" \  apache/rocketmq:5.3.1 sh mqbrokerdocker run -d \  --name rocketmq-dashboard \  -p 8080:8080 \  -e "JAVA_OPTS=-Drocketmq.namesrv.addr=namesrv:9876" \  apache/rocketmq-dashboard:latest生产环境固定版本，不建议使用 latest。mqadmin 常用命令mqadmin clusterList -n namesrv:9876mqadmin topicList -n namesrv:9876mqadmin topicRoute -n namesrv:9876 -t OrderTopicmqadmin topicStatus -n namesrv:9876 -t OrderTopicmqadmin consumerProgress -n namesrv:9876 -g order-consumermqadmin consumerConnection -n namesrv:9876 -g order-consumermqadmin updateTopic -n namesrv:9876 -c DefaultCluster -t OrderTopic -r 6 -w 6高危命令：mqadmin deleteTopicmqadmin resetOffsetByTimemqadmin wipeWritePermission执行前必须确认环境、Topic、消费位点和回滚方案。生产者模板DefaultMQProducer producer = new DefaultMQProducer("order-producer-group");producer.setNamesrvAddr("namesrv:9876");producer.setSendMsgTimeout(3000);producer.setRetryTimesWhenSendFailed(2);producer.start();try {    Message message = new Message(            "OrderTopic",            "OrderCreated",            "O202608250001".getBytes(StandardCharsets.UTF_8));    message.setKeys("O202608250001");    SendResult result = producer.send(message);    System.out.println(result.getSendStatus() + "," + result.getMsgId());} finally {    producer.shutdown();}消费者模板DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("order-consumer");consumer.setNamesrvAddr("namesrv:9876");consumer.subscribe("OrderTopic", "OrderCreated || OrderPaid");consumer.setConsumeThreadMin(4);consumer.setConsumeThreadMax(8);consumer.setConsumeTimeout(15);consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -&gt; {    try {        msgs.forEach(this::handle);        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;    } catch (TemporaryException e) {        return ConsumeConcurrentlyStatus.RECONSUME_LATER;    }});consumer.start();顺序消息producer.send(message, (queues, msg, arg) -&gt; {    int index = Math.floorMod(String.valueOf(arg).hashCode(), queues.size());    return queues.get(index);}, orderNo);consumer.registerMessageListener((MessageListenerOrderly) (msgs, context) -&gt; {    try {        msgs.forEach(this::handle);        return ConsumeOrderlyStatus.SUCCESS;    } catch (Exception e) {        context.setSuspendCurrentQueueTimeMillis(1000);        return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;    }});延迟消息固定级别：message.setDelayTimeLevel(16);5.x 定时：message.setDeliverTimeMs(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(30));必须确认客户端和 Broker 均支持对应能力。事务消息要点half message  -&gt; execute local transaction  -&gt; COMMIT_MESSAGE / ROLLBACK_MESSAGE / UNKNOW  -&gt; checkback by transactionId回查必须查询持久化状态表，不能依赖内存。存储速查store/commitlogstore/consumequeue/Topic/queueIdstore/indexstore/configstore/checkpoint            文件      作用                  CommitLog      消息物理正文              ConsumeQueue      队列逻辑索引              IndexFile      Key 和时间查询              checkpoint      恢复检查点              config      Topic、消费位点等配置      监控指标broker_put_tpsbroker_get_tpsbroker_put_latency_mscommitlog_flush_latency_msdispatch_lagdisk_usage_ratioreplica_sync_diffproducer_send_failure_totalconsumer_lagconsumer_retry_totaldead_letter_oldest_age_seconds排障路径send fail  -&gt; client config  -&gt; topic route  -&gt; acl  -&gt; broker metricsmessage missing  -&gt; business outbox  -&gt; send result  -&gt; broker message  -&gt; consumer trace  -&gt; business resultconsumer lag  -&gt; group online  -&gt; queue assignment  -&gt; consume latency  -&gt; retry / dead letter  -&gt; downstream health生产检查清单  Topic、队列数、权限已评审；  副本与刷盘策略满足 RPO；  磁盘保留覆盖最大 lag 和恢复窗口；  ACL 账号最小权限；  生产端有 Outbox 或事务补偿；  消费端幂等；  重试与死信治理入口可用；  消息轨迹和业务键可查询；  监控告警覆盖集群、Topic、消费组；  扩缩容和切主已演练；  备份可恢复；  迁移有对账和回滚方案。版本注意事项            能力      注意                  定时消息      5.x 能力与 4.x 固定级别差异较大              Proxy      客户端协议和 SDK 版本需匹配              Controller      部署与配置随版本变化              Dashboard      功能与 API 随版本变化              事务消息      不同客户端构造函数和监听器 API 有差异      思考题  你的核心 Topic 使用哪种刷盘和复制组合？  消费组最大可接受消息年龄是多少？  死信重放入口在哪里？  位点重置是否已有审批和审计？  最近一次备份恢复演练是什么时候？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。掌握 RocketMQ 不止是记住 API，而是能在业务、架构、存储、内核、云原生和团队协作之间做出可验证的取舍。本章给出继续精进的路线。31.1 能力模型            阶段      核心能力                  入门      部署、收发、Topic、消费组              熟练      事务、顺序、延迟、幂等、监控              高级      存储、高可用、容量、故障演练              专家      架构选型、平台治理、源码贡献              大师      在复杂业务和组织中落地可靠消息体系      大师级能力的标志是：能把不确定性显式化，用数据、演练和治理承接风险。31.2 深入源码推荐阅读路径：client send  -&gt; broker request handler  -&gt; message store  -&gt; commitlog append  -&gt; reput dispatch  -&gt; consume queue  -&gt; pull message  -&gt; offset commit重点模块：  remoting 协议；  producer 发送与重试；  consumer 重平衡；  topic 路由；  MappedFileQueue；  CommitLog；  ConsumeQueue；  IndexFile；  刷盘线程；  复制与 Controller；  事务回查；  定时消息；  Proxy 转发。读源码时先跑单测，再打断点跟一条消息。31.3 建立实验环境实验清单：  单机部署；  双主双从；  Controller 集群；  Proxy 集群；  混合版本迁移；  磁盘故障注入；  网络分区；  断电恢复；  负载压测；  冷读压测。记录每次实验：versionconfigurationinput loadobserved metricsfailure injectionrecovery behaviorconclusion31.4 平台化建设消息平台应提供：  Topic 生命周期管理；  权限申请与审计；  事件契约管理；  SDK 规范；  监控模板；  死信治理台；  消息查询和轨迹；  容量看板；  成本看板；  故障 Runbook；  混沌演练；  自动巡检。平台的目标不是减少所有手工操作，而是让高风险操作有流程、有校验、有证据。31.5 业务架构能力继续学习：  DDD 聚合与事件边界；  Event Sourcing；  CQRS 投影；  Saga 与补偿；  数据一致性；  工作流引擎与消息协作；  数据治理；  安全合规；  成本治理；  混沌工程。技术方案必须回答：business invariantfailure moderecovery pathobservabilitycostrollback31.6 版本追踪关注：  5.x 新特性；  Proxy 演进；  Controller 与高可用；  定时消息；  多语言客户端；  性能优化；  安全增强；  云原生部署；  社区 RFC；  兼容性说明。学习新版本时保持“当前版本文档优先”，不要把旧博客结论当成事实。31.7 个人知识库建议沉淀：  架构图；  参数表；  故障案例；  压测报告；  演练记录；  容量模型；  Topic 命名规范；  事件 schema 规范；  面试复盘；  源码笔记。每个案例都记录时间线、根因、修复、验证和长期预防。31.8 协作与领导高级工程师要推动：  事件契约评审；  消息可靠性分级；  故障演练常态化；  死信治理值班；  容量评审机制；  变更审批和自动化；  多团队 Topic 归属；  事故复盘无责文化。好的消息体系是团队工程能力的体现，不是某个人的经验判断。本章小结大师之路从跑通一条消息开始，经过存储与高可用源码、真实故障演练、平台化治理，最终沉淀为组织级工程能力。保持对版本、数据和业务边界的敬畏，持续记录实验与事故，才能在复杂系统中做出可靠决策。思考题  你所在团队的消息可靠性如何分级？  下一个最值得做的故障演练是什么？  如何把死信治理变成日常流程？  哪些 Topic 契约缺少版本治理？  你的容量模型多久校准一次？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。本章按“基础、存储、消息类型、高可用、性能、项目治理”整理高频问题。回答面试题时，最好先给结论，再讲机制，最后补生产实践和边界条件。30.1 NameServer 和 Broker 的关系是什么？NameServer 维护路由信息，Broker 定期注册并上报 Topic 队列数据，客户端从 NameServer 获取路由后直连或通过 Proxy 访问 Broker。回答要点：  NameServer 是轻量路由中心；  Broker 承担消息存储和请求处理；  NameServer 节点之间通常不强同步，客户端会综合路由视图；  NameServer 宕机不立即影响已有连接；  新路由发现和拓扑更新会受影响。加分项：说明 5.x Controller 与高可用架构演进。30.2 RocketMQ 如何保证消息不丢？分层回答：producer send + retry + local compensationbroker flush + replicationconsumer consume success + idempotentplatform monitoring + reconciliation关键点：  生产端确认 SendStatus；  重要消息配合 Outbox 或事务消息；  Broker 使用满足 SLA 的刷盘和副本策略；  消费成功后再确认；  所有链路有对账；  断电、磁盘损坏、机房故障需要不同方案。不存在的万能开关，可靠性和成本必须一起讨论。30.3 RocketMQ 为什么会重复消费？典型场景：  发送超时后内部重试；  消费成功但位点提交失败；  消费超时触发重试；  死信重放；  补偿任务和消息并发。处理方式：使用 eventId 或业务唯一键幂等，业务表用唯一约束或状态机条件更新。Redis 可作为优化，不能作为唯一保障。30.4 顺序消息如何保证顺序？三个条件：same key -&gt; same queuesame queue -&gt; orderly consumefailure -&gt; bounded retry回答时说明局部顺序和全局顺序，队列选择器、MessageListenerOrderly、重试挂起和扩缩容影响。大多数业务只需要订单号、账号或 SKU 级局部顺序。30.5 事务消息的流程是什么？流程：send half message  -&gt; execute local transaction  -&gt; commit or rollback  -&gt; unknown then checkback关键点：  半消息对消费者不可见；  本地事务必须可回查；  回查不能依赖内存状态；  消费失败不会回滚生产端本地事务；  通常与本地事件表配合；  它是最终一致，不是分布式强事务。30.6 延迟消息的原理和限制是什么？4.x 以固定延迟级别为主，Broker 按级别调度后投递到真实 Topic。5.x 增强定时消息能力，可按时间触发。限制：  到期精度受调度和消费能力影响；  版本能力差异大；  最大延迟时间可能有限制；  相同到期时间会造成洪峰；  业务仍需状态机幂等。30.7 CommitLog、ConsumeQueue、IndexFile 的关系是什么？CommitLog: physical message bodyConsumeQueue: topic queue logical indexIndexFile: key/time query index回答要点：  所有 Topic 消息顺序追加 CommitLog；  ConsumeQueue 保存 CommitLog offset、size 和 tag hash；  IndexFile 支持按 Key 和时间查询；  索引由 ReputMessageService 异步构建；  dispatch lag 可能造成短暂不可见。30.8 刷盘和复制策略如何选择？            策略      目的                  同步刷盘      降低宿主机断电丢失风险              异步刷盘      提升吞吐              同步复制      降低节点故障丢失风险              异步复制      降低延迟和带宽成本      核心是业务 RPO 与延迟预算。交易类偏可靠，日志类可偏成本。必须结合磁盘、网络和故障演练验证。30.9 Broker 主从切换为什么可能丢消息？异步复制下，主节点返回成功但部分尾部消息尚未复制到从节点。主节点磁盘损坏并切换到落后副本时，这部分消息可能不可恢复。防范：  核心链路使用同步复制；  监控副本差距；  自动切换选择位点最新副本；  使用 Controller 或共识模式；  epoch fencing 防脑裂；  保留业务级对账。30.10 消费者数量和队列数量的关系是什么？集群消费下，队列是最小分配单元。消费者数量超过队列数量时，多余实例空转；消费者数量少于队列数量时，单实例承担多个队列。扩容步骤：  先确认消费慢原因；  优化单条处理耗时；  增加实例；  增加线程；  最后考虑扩队列；  注意顺序消息影响。30.11 消息积压如何处理？先分类：            现象      原因                  消费组不在线      部署或配置问题              消费耗时高      业务和下游瓶颈              重试风暴      下游异常              热点队列      key 或路由集中      处理顺序：  保护下游；  降级非核心逻辑；  增加有效消费者；  拆分热点 Topic 或 key；  评估扩队列；  恢复后对账。30.12 如何设计消息幂等？回答框架：  选择业务幂等键，如 eventId、paymentId；  事件表或业务表唯一约束；  事件处理与业务变更同事务；  状态机条件更新；  Redis 只做快速拦截；  针对并发和重放测试；  用对账兜底。不要只说“用 Redis setnx”。30.13 RocketMQ 和 Kafka 怎么选？RocketMQ 适合业务消息、事务消息、延迟消息、重试死信、大量 Topic 队列和消息轨迹查询。Kafka 适合流日志、实时计算管道、丰富连接器生态和大规模 append-only 回放。加分项：  不做绝对化比较；  提到两者语义差异；  强调用自身负载压测；  讨论团队能力和运维成本；  提混合架构。30.14 死信队列如何治理？死信不是删除终点，而是治理队列：  保存异常、堆栈和上下文；  告警按未处理年龄和业务影响分级；  修复代码或数据；  小批量重放；  幂等保护；  记录处理结论；  沉淀告警规则。30.15 消息轨迹有什么用？轨迹能证明：  生产端是否发送成功；  消息何时写入 Broker；  进入哪个队列和位点；  哪个消费组拉取；  消费耗时和结果；  是否重试或死信。限制：需要开启、有开销、可能采样，敏感信息要脱敏。30.16 项目中如何做容量规划？回答公式：disk = peak bytes/s × retention × replica × expansionqueues = required consumer parallelismnetwork = send + replicate + consume + trace再补充峰值、重试、死信、轨迹、消费 lag、故障恢复窗口、多租户隔离和压测修正。30.17 高频追问清单  半消息回查失败怎么办？  顺序消息消费失败能否跳过？  广播模式和集群模式区别？  Tag 过滤和 SQL 过滤区别？  Proxy 模式解决什么问题？  Controller 如何防止脑裂？  磁盘满了怎么办？  位点重置有什么风险？  迁移集群时位点怎么处理？  如何验证消息没有丢？回答策略：先讲业务目标，再讲机制，最后讲监控、演练和回滚。本章小结RocketMQ 面试的高频考点集中在消息语义、存储结构、事务、顺序、延迟、重试幂等、高可用和容量治理。高质量回答要区分“机制”和“生产实践”，明确版本差异和故障边界，并能给出可验证的监控与对账方案。思考题  如何用一句话说清事务消息的边界？  顺序消息为什么容易牺牲吞吐？  为什么“不丢”必须分层讨论？  死信治理需要哪些字段？  面试中如何展示生产经验？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。性能调优的目标是满足业务 SLA，而不是追求单点最高 TPS。RocketMQ 调优通常沿着链路推进：客户端发送、网络、Broker 写入、索引构建、消费处理、下游依赖和存储回收。先测基线，再改一个变量，最后保留结果。29.1 调优流程define SLA  -&gt; build baseline  -&gt; profile bottleneck  -&gt; change one variable  -&gt; verify result  -&gt; document and monitorSLA 示例：            指标      目标                  send P99      &lt; 10 ms              consume P99      &lt; 100 ms              end-to-end P99      &lt; 1 s              max lag      &lt; 10,000              recovery time      &lt; 5 min      没有延迟目标的压测容易得到“高吞吐但不可用”的结论。29.2 生产者调优常见参数：            参数      影响                  maxMessageSize      单条消息上限              sendMsgTimeout      等待 Broker 时间              retryTimesWhenSendFailed      同步重试次数              compressMsgBodyOverHowmuch      压缩阈值              producer group      逻辑分组      优化：  复用生产者实例；  控制消息大小；  大对象放对象存储；  合理压缩；  设置有限重试；  批量发送需业务允许；  避免发送线程内做慢 IO；  保存 SendStatus 和业务键。29.3 Broker 写入调优写入路径：request decode  -&gt; validate  -&gt; append commitlog  -&gt; replicate  -&gt; flush  -&gt; response可调方向：  独立高性能数据盘；  评估同步刷盘与异步刷盘；  评估同步复制与异步复制；  控制 Topic 队列总数；  限制超大消息；  均衡 Broker 写入；  避免冷读挤占页缓存；  确认线程池和请求队列；  使用合适的系统 IO 调度。任何可靠性降低都必须经过业务确认，不能为了压测数字关闭必要保护。29.4 消费调优先定位单条耗时：deserialize  -&gt; validate  -&gt; database operation  -&gt; rpc call  -&gt; local business transaction  -&gt; metrics常见优化：            优化      适用                  优化慢 SQL      数据库瓶颈              索引和唯一键      查询慢              下游批量提交      高吞吐导入              增加消费者实例      CPU 或并发不足              增加消费线程      单机仍有余量              旁路非核心逻辑      可异步处理              降级审计细节      故障窗口      消费线程增加前必须确认数据库连接池、下游限流和顺序性要求。29.5 队列与热点热点表现：  单队列消费 lag 明显更高；  单 Broker 磁盘和 CPU 更高；  单排序 key 消息集中；  局部顺序导致吞吐受限。处理：  调整队列选择；  拆分热点 Topic；  拆分热点业务 key；  非顺序业务改并发消费；  Broker 均衡；  顺序流程异步旁路；  预估促销热点。29.6 索引与查询调优查询慢的原因：  时间范围过大；  Key 选择性低；  冷数据读取；  磁盘竞争；  并发查询过高；  轨迹全量开启。建议：  缩小时间范围；  使用精确业务 Key；  查询走只读副本或备份；  管理查询限流；  关键链路采样；  高频业务查询放数据库或搜索引擎。29.7 JVM 与操作系统JVM 观察：GC pauseheap usagethread countthread blockeddirect memorymapped memorysafepoint系统观察：CPU usagerun queueiowaitdisk utilnetwork bandwidthtcp retransmitfile descriptorsswap原则：  避免频繁 Full GC；  不盲目增大堆；  观察长尾延迟；  避免换页；  保持文件句柄余量；  不与其他重 IO 服务混部。29.8 压测方法压测维度：  固定消息大小；  阶梯提升 TPS；  写读混合；  故障注入；  事务消息；  顺序消息；  延迟消息；  冷查询；  长时间稳定；  重试风暴。记录：client latencybroker latencydisk throughputnetwork throughputcpugcerror ratelag压测环境与生产磁盘、网络和副本策略越接近，结论越可信。29.9 反模式            反模式      后果                  盲目调大线程      压垮数据库              关闭刷盘换 TPS      断电丢数据              无限重试      放大故障              全量轨迹      磁盘和带宽暴涨              只看平均延迟      掩盖 P99              单队列全局顺序      吞吐瓶颈              压测后不固化配置      结果不可复现      本章小结RocketMQ 性能调优要先定义延迟和可靠性目标，再分层定位客户端、Broker、磁盘、网络和下游瓶颈。生产端关注复用、消息大小和重试；Broker 关注顺序写、刷盘、复制、页缓存和负载均衡；消费端关注单条耗时、幂等、线程和下游容量。所有优化都要以可复现压测和持续监控收尾。思考题  为什么平均延迟不能代表用户体验？  同步刷盘和同步复制对延迟有什么影响？  消费线程越多越好吗？  冷读为什么会影响写入？  压测配置为什么要固化？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。本章以“电商订单事件链路”为例，把生产者、消费者、幂等、顺序、延迟、事务、监控和部署串联成一个可落地方案。示例可运行性优先，但连接地址、Topic 和数据库配置需要按环境替换。28.1 业务场景流程：create order  -&gt; publish OrderCreated  -&gt; reserve inventory  -&gt; wait payment  -&gt; publish OrderPaid  -&gt; shipping service  -&gt; timeout 30m  -&gt; close unpaid order需求：  创建订单和事件不丢；  库存不重复扣减；  同一订单状态顺序处理；  超时可靠关闭；  全链路可追踪；  死信可治理；  核心链路可降级。28.2 Topic 设计            Topic      类型      生产者      消费者                  order.order-created.v1      事务顺序      order-api      inventory              order.order-paid.v1      事务顺序      order-api      shipping              order.order-timeout.v1      延迟      order-api      order-timeout-worker              order.governance.v1      普通      consumer      ops 服务      命名建议：业务域 + 事件名 + 版本。28.3 事件契约OrderCreated：{  "eventId": "01J8ZP7Q8M2A",  "eventType": "OrderCreated",  "version": 1,  "occurredAt": "2026-08-25T10:00:00+08:00",  "data": {    "orderNo": "O202608250001",    "userId": "U10001",    "items": [      {        "skuId": "SKU1001",        "quantity": 2,        "price": 9900      }    ]  }}字段规范：  eventId 全局唯一；  version 明确契约版本；  occurredAt 带时区；  金额使用最小单位；  不放密码、token 和完整敏感信息。28.4 数据表设计订单表：CREATE TABLE orders (  id BIGINT PRIMARY KEY AUTO_INCREMENT,  order_no VARCHAR(64) NOT NULL,  user_id VARCHAR(64) NOT NULL,  status VARCHAR(20) NOT NULL,  amount BIGINT NOT NULL,  version INT NOT NULL DEFAULT 0,  created_at DATETIME(6) NOT NULL,  updated_at DATETIME(6) NOT NULL,  UNIQUE KEY uk_order_no (order_no),  KEY idx_user_time (user_id, created_at));事件表：CREATE TABLE outbox_event (  id BIGINT PRIMARY KEY AUTO_INCREMENT,  event_id VARCHAR(64) NOT NULL,  transaction_id VARCHAR(64) NOT NULL,  event_type VARCHAR(64) NOT NULL,  aggregate_id VARCHAR(64) NOT NULL,  status VARCHAR(20) NOT NULL,  payload JSON NOT NULL,  created_at DATETIME(6) NOT NULL,  updated_at DATETIME(6) NOT NULL,  UNIQUE KEY uk_event_id (event_id),  UNIQUE KEY uk_transaction_id (transaction_id),  KEY idx_status_time (status, created_at));库存变更表：CREATE TABLE inventory_change (  id BIGINT PRIMARY KEY AUTO_INCREMENT,  change_id VARCHAR(64) NOT NULL,  sku_id VARCHAR(64) NOT NULL,  order_no VARCHAR(64) NOT NULL,  quantity INT NOT NULL,  created_at DATETIME(6) NOT NULL,  UNIQUE KEY uk_change_id (change_id),  KEY idx_sku_time (sku_id, created_at));28.5 生产者封装@Servicepublic class OrderEventProducer implements AutoCloseable {    private final TransactionMQProducer producer;    public OrderEventProducer(OrderTransactionListener listener) throws MQClientException {        producer = new TransactionMQProducer("order-producer-group");        producer.setNamesrvAddr("rocketmq-namesrv:9876");        producer.setTransactionListener(listener);        producer.setSendMsgTimeout(3000);        producer.start();    }    public void sendOrderCreated(Order order, OrderCreatedEvent event) throws Exception {        Message message = new Message(                "order.order-created.v1",                "OrderCreated",                Json.write(event));        message.setKeys(order.orderNo());        producer.sendMessageInTransaction(message, order.orderNo());    }    @Override    public void close() {        producer.shutdown();    }}顺序发送时使用稳定选择器：public MessageQueue orderQueueSelector(List&lt;MessageQueue&gt; queues, Object arg) {    int index = Math.floorMod(String.valueOf(arg).hashCode(), queues.size());    return queues.get(index);}28.6 库存消费者@Componentpublic class InventoryOrderConsumer {    private final InventoryReserveService reserveService;    @PostConstruct    public void start() throws Exception {        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("inventory-consumer");        consumer.setNamesrvAddr("rocketmq-namesrv:9876");        consumer.subscribe("order.order-created.v1", "OrderCreated");        consumer.setConsumeThreadMin(4);        consumer.setConsumeThreadMax(8);        consumer.registerMessageListener((MessageListenerOrderly) (msgs, context) -&gt; {            for (MessageExt msg : msgs) {                OrderCreatedEvent event = Json.read(msg.getBody(), OrderCreatedEvent.class);                reserveService.reserve(event);            }            return ConsumeOrderlyStatus.SUCCESS;        });        consumer.start();    }}库存处理：INSERT INTO inventory_change(change_id, sku_id, order_no, quantity, created_at)VALUES (?, ?, ?, ?, NOW(6));若唯一键冲突，说明事件重复，记录日志后确认。28.7 超时关单发送：Message message = new Message(        "order.order-timeout.v1",        "OrderTimeout",        Json.write(new OrderTimeoutEvent(orderNo, expireAt)));message.setKeys(orderNo);message.setDeliverTimeMs(expireAt.toEpochMilli());producer.send(message);消费：UPDATE ordersSET status = 'CLOSED', close_reason = 'TIMEOUT', version = version + 1WHERE order_no = ? AND status = 'WAIT_PAY';更新行数为 0 表示订单已进入其他状态，记录审计后确认消费。28.8 监控埋点核心指标：order_created_totalorder_event_send_success_totalorder_event_send_failure_totalinventory_reserve_success_totalinventory_reserve_duplicate_totalorder_timeout_fired_totalorder_timeout_effective_totalorder_event_lagorder_dead_letter_age日志字段：traceId, eventId, orderNo, topic, messageId, queueId, offset告警：  创建订单成功但事件发送失败；  库存消费 lag 超阈值；  超时事件未按时触发；  死信年龄超阈值；  业务对账差异。28.9 部署配置资源建议：            组件      副本      资源                  order-api      2+      2C4G              inventory-consumer      按队列和吞吐      2C4G              timeout-worker      2+      1C2G              rocketmq cluster      2 broker 组以上      独立磁盘      配置中心：rocketmq:  namesrv: rocketmq-namesrv:9876  producer-group: order-producer-group  topics:    created: order.order-created.v1    paid: order.order-paid.v1    timeout: order.order-timeout.v1生产环境使用环境变量或密钥服务注入地址和凭据。28.10 验收测试用例：  创建订单成功且事件可查询；  本地事务回滚后事件不投递；  半消息回查能返回正确状态；  库存重复消费不重复扣减；  同一订单事件按状态顺序处理；  未支付订单 30 分钟关闭；  已支付订单不会被超时关闭；  死信重放不会产生重复业务；  Broker 重启后链路恢复；  业务对账无差异。本章小结项目实战的关键是让订单数据库、本地事件表、RocketMQ 消息、库存变更表和监控对账形成闭环。生产端用事务消息和 Outbox，消费端用顺序、幂等和状态机，超时用延迟消息加条件更新，治理用死信和指标承接异常。思考题  为什么事件表和订单同事务？  库存扣减的幂等键如何选择？  超时关单为什么要条件更新？  顺序消费失败时如何避免阻塞全部订单？  上线前哪些故障必须演练？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。消息队列的价值不是“把调用改成异步”，而是为业务建立清晰的事件契约、状态流转和故障恢复路径。本章整理常见业务架构模式，以及它们的风险边界。27.1 事件驱动架构基本结构：order service  -&gt; publish OrderCreated  -&gt; inventory / notification / risk consumers收益：  降低服务耦合；  支持新增下游而不改上游；  削峰填谷；  建立业务审计流；  支持数据同步和实时分析。代价：  链路可观测性要求高；  最终一致；  事件治理复杂；  重复和乱序必须处理；  故障影响可能延迟暴露。27.2 命令与事件            类型      语义      示例                  Command      要求对方执行动作      CreateOrderCommand              Event      说明事实已经发生      OrderCreatedEvent      错误示例：OrderPaid event -&gt; consumer tells inventory to deduct更清晰的设计：OrderPaid event -&gt; inventory service reacts: reserve or deduct stock事件命名使用过去式，命令命名使用祈使式。27.3 Outbox 模式解决本地事务与消息发送一致性：transaction:  update business table  insert outbox eventrelay:  scan outbox  send message  mark sent要点：  业务与事件同事务；  eventId 全局唯一；  relay 支持重试；  消费端幂等；  事件表按时间分区；  清理策略与审计要求一致。RocketMQ 事务消息可以减少扫描延迟，但本地 outbox 仍是可靠审计和补偿基础。27.4 Saga 模式分布式长流程用本地事务加补偿：create order  -&gt; reserve inventory  -&gt; charge payment  -&gt; failure  -&gt; release inventory  -&gt; close order设计要点：  每步有幂等操作；  每步有对应补偿；  补偿也可能失败；  状态机持久化；  定时恢复悬挂流程；  对外提供流程状态查询；  支持人工介入。RocketMQ 承担步骤事件和补偿事件，不负责自动回滚数据库。27.5 CQRS 与数据同步命令侧：order API -&gt; order DB -&gt; publish event查询侧：consumer -&gt; projection table / search index / cache注意：  查询模型最终一致；  投影任务必须幂等；  事件乱序要按聚合 ID 处理；  支持重放；  建立版本和快照；  提供对账和重建任务。不要让用户在提交命令后立刻查询旧状态却不给出一致性提示。27.6 异步任务模式：API accepts request  -&gt; persist task  -&gt; send task message  -&gt; worker execute  -&gt; update task status任务表字段：            字段      说明                  task_id      唯一 ID              type      任务类型              payload      输入参数              status      状态              attempt      尝试次数              next_retry_at      下次执行时间              result      输出或失败原因      消息丢失时可由任务表补偿，任务重复时可由 task_id 幂等。27.7 广播通知广播消息适合：  本地缓存刷新；  配置变更通知；  在线服务元信息刷新；  灰度规则通知。不适合：  数据库唯一记录写入；  扣款、扣库存；  全局审计事实；  必须全部实例确认的强一致流程。广播消费的新实例可能无法自动获得历史全量消息，通常需要“全量加载 + 增量广播”组合。27.8 削峰填谷peak requests  -&gt; enqueue  -&gt; controlled consumers  -&gt; downstream database关键参数：  队列长度；  消费并发；  请求超时；  过期策略；  用户反馈；  降级策略；  死信治理。削峰不是无限排队。超过业务等待时间后，应拒绝或降级，而不是让用户等待未知结果。27.9 事件版本管理事件契约演化：            变更      兼容性                  新增可选字段      向后兼容              删除字段      需迁移期              修改字段含义      不兼容              枚举新增值      消费端需容错              修改业务键      高风险      推荐：eventType + versioneventIdschema registryconsumer tolerance for unknown fields消费者应允许未知字段，生产者避免重命名字段。27.10 服务边界事件平台治理：  Topic 命名规范；  事件 schema 注册；  生产者和消费者授权；  SLA 和 lag 告警；  死信治理；  事件文档；  兼容性测试；  数据脱敏；  生命周期管理；  归属团队。示例命名：order.order-created.v1risk.payment-checked.v1user.profile-updated.v2本章小结业务架构模式的核心是明确事实、命令、状态和补偿。Outbox 保证生产可靠，Saga 处理长流程，CQRS 支撑查询模型，异步任务通过任务表兜底。RocketMQ 提供传输、重试、死信和事务能力，但业务正确性仍依赖契约、幂等、状态机和对账。思考题  Command 和 Event 的命名有什么区别？  Outbox 与事务消息如何组合？  Saga 补偿失败怎么办？  CQRS 查询模型如何重放重建？  哪些场景不适合广播消息？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Kafka 和 RocketMQ 都是高吞吐分布式消息系统，但默认设计取向不同。Kafka 早期围绕流式日志和批量传输发展，RocketMQ 更强调业务消息能力，例如事务消息、重试队列、延迟消息和丰富的队列治理。选型要结合业务语义、团队经验和运维能力。26.1 定位差异            维度      Kafka 常见定位      RocketMQ 常见定位                  核心场景      流处理日志管道、事件流      业务事件、交易事件、任务消息              消费模型      拉取分区日志      拉取队列，Push 封装              典型生态      Kafka Connect、Streams、Flink      业务解耦、事务、延迟、重试              数据形态      高吞吐追加日志      业务消息和索引查询      这不是绝对边界。Kafka 可以承载业务事件，RocketMQ 也能承载流处理，但生态和默认优化会使成本不同。26.2 存储模型Kafka 常见模型：partition log  segment files  consumer offsetRocketMQ 模型：CommitLog  all topics appended togetherConsumeQueue  logical queue indexIndexFile  key/time query index对比：            项目      Kafka      RocketMQ                  写入组织      每个 partition 追加      Broker 内所有 Topic 汇入 CommitLog              队列数量多时      文件和 IO 更分散      顺序写更集中              按消息 Key 查询      不是核心能力      IndexFile 原生支持              存储层复杂度      partition 模型直观      多层索引需要理解      不同版本和云实现都有优化，以上是通用架构差异，不代表所有部署形态。26.3 消息语义            能力      Kafka      RocketMQ                  至少一次      支持      支持              消费重试      应用或生态处理      消费组重试队列              死信      依赖生态或自建      系统死信 Topic              延迟消息      通常应用或生态实现      4.x 固定级别，5.x 增强定时能力              事务消息      Kafka 事务面向流处理原子写读      RocketMQ 面向本地事务与消息提交              消息轨迹      生态实现      客户端和平台能力      两者的事务语义目标不同，不能简单说谁更强。Kafka 事务偏流处理多条记录的原子性，RocketMQ 事务消息偏业务库与消息发送的一致性。26.4 消费与位点Kafka：  消费者组管理 partition 分配；  offset 可提交到内部 Topic；  rebalance 生态成熟；  常配合 Streams 或 Flink 管理状态。RocketMQ：  消费者组管理 queue 分配；  位点保存在 Broker；  提供重试和死信模型；  Push 客户端封装长轮询；  队列数决定最大并行度。两者都有重复可能，业务都必须幂等。26.5 性能与延迟影响性能的因素：  消息大小；  批量大小；  刷盘策略；  副本同步；  分区 / 队列数；  客户端语言；  消费逻辑；  磁盘和网络；  是否冷读；  是否开启轨迹和复杂过滤。粗略结论：            场景      常见倾向                  大吞吐流日志      Kafka 常有优势              大量 Topic 队列写入      RocketMQ CommitLog 聚合写入有优势              低延迟小包业务消息      需实测              按业务 Key 查消息      RocketMQ 更直接      不要根据网上单点压测做最终决策，必须用自己的消息大小、副本、延迟目标和磁盘模型压测。26.6 运维对比            维度      Kafka      RocketMQ                  元数据      KRaft 或历史 ZooKeeper      NameServer / Controller 演进              分区迁移      常用重分配工具      队列与 Broker 治理              多租户      配额、ACL、生态治理      ACL、Topic 配额、平台治理              云托管      成熟      逐渐增强              排障生态      非常丰富      国内实践和社区资料较多      团队熟悉度经常比架构差异更影响总成本。26.7 选型建议优先考虑 RocketMQ：  业务事件需要事务消息、延迟消息、重试死信；  Topic 和队列数量多；  常按消息 Key 查询轨迹；  团队已有 RocketMQ 运维经验；  需要 Java 客户端深度集成。优先考虑 Kafka：  大规模流式日志管道；  以 Flink / Kafka Streams 为核心的数据平台；  生态连接器要求高；  主要做 append-only 事件流和回放；  团队已有 Kafka 平台能力。26.8 混合架构常见分层：business service  -&gt; RocketMQ business events  -&gt; data integration  -&gt; Kafka stream platform边界：  业务动作与事务一致性放 RocketMQ；  分析、实时计算、日志汇聚放 Kafka；  两边通过 CDC 或事件桥接；  统一事件 ID 和 schema 治理；  避免双写核心状态。本章小结Kafka 和 RocketMQ 的差异来自设计目标：流日志管道与业务消息治理。RocketMQ 的优势在业务消息功能完整、队列治理和消息轨迹；Kafka 的优势在流生态、连接器和高吞吐管道。选型应以业务语义、团队能力和压测结果为准，而不是纸面参数。思考题  为什么不能简单比较两者 TPS？  RocketMQ CommitLog 聚合写入带来什么收益？  两者事务语义有什么不同目标？  什么场景适合 RocketMQ 与 Kafka 混用？  选型时团队经验为什么重要？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。备份回答“数据坏了能不能恢复”，迁移回答“换集群后路由、位点、业务和客户端能不能安全切换”。两者都不是简单复制文件，必须先定义恢复目标、数据边界和回滚路径。25.1 目标定义常用目标：            目标      问题                  RPO      最多可接受丢多少数据              RTO      多久恢复服务              消息范围      全集群、核心 Topic、审计 Topic              位点范围      消费位点、重试、死信、事务状态              服务范围      客户端、Proxy、监控、告警      示例：core topics RPO = 0 through sync replicationrecovery RTO = 30 minutesnoncritical topics RPO = 5 minutes没有目标的备份方案很难验证有效性。25.2 备份对象必须备份：  Topic 配置；  队列数和权限；  ACL 配置；  Broker 配置；  NameServer 地址和元信息；  消费组位点；  关键消息数据；  事务和定时消息状态；  监控和告警配置；  运维脚本与证书配置说明。消息数据可以选择：            方式      适用                  副本      在线高可用              冷备份文件      指定时间点恢复              异地复制      机房级容灾              归档到对象存储      审计和长期保留              业务事件表      业务级兜底      25.3 文件备份理论备份对象：store/commitlogstore/consumequeuestore/indexstore/configstore/checkpointbroker config注意：  在线文件复制可能得到不一致快照；  Broker 停止后复制更一致，但服务中断；  云盘快照需确认崩溃一致性；  ConsumeQueue 和 Index 可重建，但重建耗时；  必须保留 checkpoint 和配置；  备份文件不要和原集群同故障域；  恢复前校验版本和目录结构。25.4 备份验证备份必须恢复演练：restore to isolated cluster  -&gt; start brokers  -&gt; verify topic route  -&gt; check offsets  -&gt; sample messages  -&gt; compare counts  -&gt; test consumer resume  -&gt; measure recovery time验证指标：  消息条数；  按时间范围的边界；  指定业务 Key 查询；  消费位点；  死信和重试；  权限；  恢复耗时；  应用可连接性。未演练过的备份只能算“复制了一份未知状态的文件”。25.5 迁移方式            方式      适用      特点                  停机迁移      小规模、强一致      简单但服务中断              双写迁移      核心业务      数据可对账，改造多              双消费迁移      消费逻辑切换      需防重复副作用              位点映射迁移      新旧数据连续      位点换算复杂              云厂商迁移      上云或跨云      依赖工具和网络      常用流程：inventory  -&gt; build target  -&gt; backfill or dual write  -&gt; verify data  -&gt; migrate consumers gradually  -&gt; switch producers  -&gt; observe  -&gt; retire old cluster25.6 位点迁移位点不是全局数字，必须按队列处理：old cluster:topic + broker + queueId -&gt; offsetnew cluster:topic + broker + queueId -&gt; offset如果新集群从历史数据第一条开始重放，位点可以重新初始化；如果新旧数据拼接，需要明确边界事件和切换时间戳。推荐做法：  使用业务事件时间和唯一 ID 做对账；  新旧集群使用相同 eventId；  消费端幂等；  记录切换边界；  小流量消费组验证；  保留回滚位点。25.7 客户端切换切换清单：  配置中心地址；  ACL 凭据；  Topic 名称和权限；  消费组命名；  SDK 版本；  超时和重试；  TLS 配置；  灰度规则；  回滚开关。发布顺序建议：noncritical consumers  -&gt; noncritical producers  -&gt; critical consumers  -&gt; critical producers避免生产者新集群、消费者旧集群的长期错配。25.8 回滚方案回滚前提：  旧集群仍可写入；  双写或补偿仍在运行；  新增事件可回流；  位点可恢复；  客户端配置可快速切换；  业务幂等有效。需要明确：rollback triggerrollback ownerdata reconciliationmaximum rollback window超过最大回滚窗口后，只能前向修复，不能强行回退。25.9 常见错误            错误      后果                  只备份消息不备份配置      恢复后路由和权限缺失              在线随意复制存储文件      数据不一致              位点直接照搬      消费错位              双消费未做幂等      重复业务动作              迁移后不做对账      数据缺失不可发现              无回滚窗口      只能停业修复              备份未恢复演练      恢复能力未知      本章小结备份与迁移的核心是数据边界、位点语义、配置完整性和回滚能力。副本是在线高可用，不等于备份；文件复制不等于可恢复。关键业务应有业务级对账和事件表兜底，所有方案都要在隔离环境中演练。思考题  RPO 和 RTO 如何影响备份设计？  为什么不能把旧集群 offset 直接写入新集群？  双写迁移和双消费迁移分别适合什么场景？  迁移时为什么 eventId 很重要？  为什么备份必须做恢复演练？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。消息平台保存业务事件、账号标识、订单数据和链路日志，安全不是可选项。RocketMQ 安全治理要覆盖网络边界、身份认证、权限控制、传输加密、敏感数据、审计和密钥生命周期。24.1 威胁模型常见风险：            风险      后果                  无认证集群      任意服务可写 Topic              共享管理员账号      权限失控、审计失效              Topic 越权读写      数据泄露或污染              管理接口暴露      修改路由、删除资源              明文传输      网络窃听              消息体敏感信息泄露      合规风险              死信查询无控制      用户数据暴露              轨迹日志滥用      业务画像泄露      安全设计从“谁能访问什么资源、做什么操作、留下什么证据”开始。24.2 网络边界建议：  Broker、NameServer、Controller 部署在受控内网；  管理端口不暴露公网；  按环境隔离网络；  生产、测试、开发使用独立集群；  办公网络通过堡垒机访问；  Proxy 或网关层统一入口；  配置防火墙和安全组。最小暴露原则：client -&gt; proxy / broker data portops -&gt; bastion -&gt; admin portmonitor -&gt; metrics endpoint24.3 认证与授权RocketMQ 支持 ACL，具体配置项随版本变化。核心思想：            主体      权限                  业务生产者      指定 Topic WRITE              业务消费者      指定 Topic READ              运维账号      管理指定集群              监控账号      只读指标和状态              平台管理员      高权限但需审批      建议账号命名：order-service-prodrisk-consumer-prodrocketmq-monitor-prodrocketmq-admin-prod禁止所有服务共用一个高权限账号。24.4 Topic 权限权限规划：OrderTopic  order-api          WRITE  order-consumer     READ  risk-consumer      READ  other-service      DENY%DLQ%order-consumer  ops-governance     READ  order-consumer     DENY治理规则：  Topic 按业务域命名；  申请时声明读写方；  变更需要审批；  权限定期审计；  下线服务及时回收；  系统 Topic 单独管控；  死信 Topic 默认不给业务消费者。24.5 传输加密TLS 可以保护：  客户端到 Broker；  客户端到 Proxy；  Broker 内部通信；  复制流量；  管理请求。启用前评估：  CPU 开销；  握手延迟；  证书管理；  客户端兼容；  证书轮转流程；  混合协议过渡。生产建议使用平台统一证书管理，避免证书写死在镜像或代码仓库中。24.6 消息体安全敏感字段处理：            字段      建议                  密码      不发送              完整银行卡号      脱敏或令牌化              手机号      掩码或加密              身份证号      不进入普通事件              地址      最小化              token      不放消息      示例：{  "userId": "U10001",  "phoneMasked": "138****0001",  "cardToken": "tok_abc123"}如果必须传输敏感数据，应加密消息体，并单独管理密钥和授权。24.7 密钥管理原则：  不把 AK/SK 写入代码；  使用 KMS 或平台密钥服务；  支持定期轮转；  不同环境不同密钥；  最小权限分发；  记录密钥使用；  泄露后立即吊销和轮转。应用侧通过环境变量、K8s Secret 或托管身份获取凭据，并限制访问范围。24.8 审计与合规必须审计：  Topic 创建、修改、删除；  权限变更；  位点重置；  消息查询和导出；  死信处理；  集群扩缩容；  管理员登录；  备份和恢复。审计记录包含：whowhenwherewhat resourcewhat actionwhyresult定期输出权限、账号、Topic、消费组和敏感消息访问报表。24.9 常见安全问题            问题      处理                  测试和生产共用集群      立即隔离              客户端硬编码凭据      移入密钥管理              Dashboard 无登录      接入认证并限制网络              业务账号可查死信      收敛权限              消息体包含手机号      契约治理和脱敏              权限申请无审批      建立流程              证书过期      监控和轮转演练      本章小结RocketMQ 安全治理要在网络、认证、授权、加密、消息契约、密钥和审计七个层面同时落地。最小权限是主线：服务只能访问自己的 Topic，运维只能操作自己的环境，管理员操作必须留痕。消息平台一旦被越权写入或读取，影响的不只是技术指标，还有业务数据可信度。思考题  为什么业务服务不能共享管理员账号？  死信 Topic 为什么默认不给业务消费者？  TLS 会带来哪些成本？  消息体脱敏应该在哪个阶段设计？  位点重置为什么必须审计？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。故障排查的第一步是固定时间线和影响面，再分层验证。不要先改配置，也不要先重启。RocketMQ 的问题通常由路由、权限、订阅、位点、存储、下游依赖或客户端版本共同造成，盲目变更会破坏证据。23.1 排查框架confirm impact  -&gt; collect timeline  -&gt; classify symptom  -&gt; check client  -&gt; check route  -&gt; check broker  -&gt; check storage and os  -&gt; check downstream  -&gt; apply mitigation  -&gt; root cause review必须记录：  开始时间和恢复时间；  环境、集群、Topic、消费组；  错误率和延迟曲线；  发布、扩缩容、配置变更；  依赖服务状态；  最终止损动作。23.2 发送失败常见错误：            错误      方向                  No route info of this topic      Topic 未创建、路由错误、权限              send timeout      网络、Broker 繁忙、磁盘慢、大批量              topic not exist      环境错误或自动创建关闭              no permission      ACL 配置              message too large      超过限制              broker busy      繁忙、锁竞争、磁盘或请求堆积      检查顺序：client config  -&gt; nameserver address  -&gt; topic route  -&gt; acl  -&gt; broker metrics  -&gt; producer thread / batch size保留发送失败日志中的业务键，便于后续对账。23.3 消息丢失先定义丢失：business DB committed  -&gt; event not sent  -&gt; broker not persisted  -&gt; consumer not pulled  -&gt; business not applied排查：  查业务库和本地事件表；  查生产日志和 SendStatus；  按消息 ID 或 Key 查 Broker；  查消费轨迹；  查消费者业务处理表；  查死信和重试；  执行业务对账。如果 Broker 没有消息，优先查生产端；如果 Broker 有但消费没有，优先查路由、订阅和位点；如果已消费但业务未生效，优先查消费事务和幂等。23.4 消费积压分类：            现象      原因                  消费组不在线      发布失败、崩溃、配置错误              队列无人消费      实例少、重平衡异常、订阅不一致              消费耗时高      慢 SQL、下游慢、线程不足              单队列热点      顺序 key 热点              重试风暴      下游故障              位点落后      手工重置或长期故障      止损顺序：protect downstream  -&gt; disable noncritical logic  -&gt; scale consumers  -&gt; improve batch size if safe  -&gt; isolate hot topic  -&gt; add queues if architecture allows先保护下游数据库，再追求追平速度。23.5 顺序异常证据链：message key  -&gt; queue id  -&gt; queue offset  -&gt; store time  -&gt; consume time  -&gt; consumer instance常见原因：  队列选择器不稳定；  发送重试换队列；  使用并发消费；  消费重试跳过；  重放乱序；  业务时间与存储时间混淆。处理前先确认业务是否真的依赖顺序，以及乱序窗口影响哪些状态。23.6 Broker 磁盘问题检查：df -hdu -sh store/*iostat -x 1dmesg | grep -i errorbroker.logclean commitlog log判断：            现象      可能                  commitlog 增长快      写入高、保留长、消费落后              consumequeue 异常大      队列或 Topic 过多              index 过大      Key 过多或轨迹全量              磁盘 util 高      真实 IO 瓶颈              文件句柄不足      队列多、进程限制低      磁盘接近拒写时优先扩容，确认位点前不要手工删除数据文件。23.7 重平衡异常现象：  消费暂停；  重复消费增加；  部分队列无人处理；  消费者实例列表变化频繁。检查：  消费者健康检查；  发布滚动策略；  网络闪断；  GC 或 CPU 饥饿；  订阅关系一致性；  消费者版本；  会话超时配置。频繁上下线比一次重平衡更值得治理。23.8 事务消息问题常见现象：            现象      可能                  半消息悬挂      本地事务未知、回查失败              本地成功但消息未投递      回查返回错误              本地失败但消息投递      executeLocalTransaction 返回 COMMIT              重复事件      回查和补偿并发      检查：  half message ID；  transactionId；  本地事件表状态；  回查日志；  回查异常和超时；  生产者监听器配置。23.9 常用命令示例命令名称随版本可能不同：mqadmin clusterList -n rocketmq-namesrv:9876mqadmin topicStatus -n rocketmq-namesrv:9876 -t OrderTopicmqadmin consumerProgress -n rocketmq-namesrv:9876 -g order-consumermqadmin topicRoute -n rocketmq-namesrv:9876 -t OrderTopic高危命令：  删除 Topic；  重置位点；  关闭 Broker；  修改权限；  清理存储文件。必须先备份信息并获得变更确认。23.10 应急预案每类故障都应有 Runbook：            故障      止损                  Broker 不可用      切换副本、客户端熔断、业务降级              磁盘将满      停批处理、扩容、清理确认过期数据              消费积压      保护下游、扩消费者、旁路非关键逻辑              重试风暴      熔断下游、限流、暂停非核心              消息丢失疑云      先对账，不盲目重放              死信爆发      冻结重放、修复逻辑、小批量验证      本章小结故障排查要沿着“业务事实、消息轨迹、路由状态、存储指标、下游依赖”的链条推进。先确认影响和证据，再做可回滚止损；恢复后必须做对账和根因复盘。大多数疑难问题不是单点故障，而是状态、配置和补偿逻辑共同作用的结果。思考题  为什么故障初期不建议立即重启 Broker？  “消息丢失”有哪几个不同层面？  消费积压时为什么先保护下游？  判断顺序异常需要哪些证据？  哪些 mqadmin 命令属于高危操作？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。监控的目标是在用户感知前发现风险，在故障发生时快速定位层级。RocketMQ 监控至少覆盖四条线：集群健康、生产链路、消费链路和资源容量，并把它们与业务指标放在同一时间线。22.1 监控分层business metrics  -&gt; application metrics  -&gt; rocketmq client metrics  -&gt; proxy metrics  -&gt; broker metrics  -&gt; storage / network / os metrics单看 Broker TPS 正常并不能证明业务正常；单看消费成功也不代表下游数据正确。监控要支持端到端追踪。22.2 集群健康核心指标：            指标      含义                  broker_alive      Broker 是否在线              broker_role      主从角色              broker_epoch      角色任期              nameserver_alive      NameServer 健康              controller_leader      Controller 是否有主              replica_sync_diff      副本差距              disk_usage_ratio      磁盘使用率              file_descriptor_count      文件句柄      告警示例：  Broker 离线；  无 Controller leader；  副本数量低于预期；  副本同步差距持续扩大；  磁盘使用率超过阈值；  频繁切换角色；  NameServer 路由不一致。22.3 生产监控客户端指标：producer_send_totalproducer_send_success_totalproducer_send_failure_totalproducer_send_latency_msproducer_retry_totalproducer_timeout_totalproducer_thread_waitinglocal_outbox_pending重点看：  成功率；  P95 / P99 延迟；  超时率；  重试率；  本地待发送事件数量；  按 Topic 和服务维度聚合；  灰度版本差异。发送异常必须记录 Topic、messageId、业务键、SendStatus 和错误码。22.4 消费监控指标：consumer_group_onlineconsumer_lagconsumer_lag_bytesconsumer_oldest_message_ageconsumer_pull_totalconsumer_consume_totalconsumer_success_totalconsumer_failure_totalconsumer_retry_totalconsumer_dead_letter_totalconsumer_consume_latency_msconsumer_thread_pool_active关键问题判断：            问题      可能原因                  消费组不在线      实例崩溃、发布失败、配置错误              lag 增长且耗时高      处理能力不足              lag 增长但耗时低      订阅、位点或队列分配问题              重试增长      下游异常或代码缺陷              死信增长      无法自动恢复消息增加              消息年龄增长      积压严重      22.5 存储监控指标：broker_put_tpsbroker_get_tpsbroker_put_latency_mscommitlog_flush_latency_msdispatch_lagcommitlog_file_countdisk_read_iopsdisk_write_iopsdisk_io_utildisk_io_waitpage_cache_ratio典型判断：  写延迟与磁盘 util 同升，疑似磁盘瓶颈；  dispatch lag 增长，索引构建落后；  冷读导致 page cache 命中下降；  拉取延迟高但磁盘低，可能是网络或过滤开销；  文件数量异常增长，检查队列和 Topic 扩张。22.6 Proxy 监控如果使用 Proxy 模式：proxy_active_connectionsproxy_request_totalproxy_error_totalproxy_request_latency_msproxy_upstream_latency_msproxy_route_refresh_totalproxy_auth_failure_totalproxy_memory_usage重点：  连接增长趋势；  请求队列；  入口延迟与上游延迟差；  路由刷新异常；  认证失败；  优雅停机时间。22.7 告警设计告警要区分级别：            级别      场景                  P0      核心集群不可写、数据缺失、多副本不可用              P1      核心消费组长时间积压、死信快速增长              P2      副本落后、磁盘接近阈值、延迟升高              P3      非核心 Topic 异常      避免只告警数量：bad: dead letter &gt; 100good: dead letter unhandled age &gt; 30m每条告警应包含：  集群和环境；  Topic 或消费组；  影响范围；  关键指标；  处理入口；  值班手册链接。22.8 仪表盘推荐仪表盘：  集群总览；  Broker 详情；  Topic 流量；  消费组健康；  生产应用视图；  消费应用视图；  死信治理；  容量和预测；  变更与事件时间线。每张图都应支持按环境、集群、Broker、Topic、消费组、应用版本过滤。22.9 日志与链路日志统一携带：traceIdmessageIdeventIdbusinessKeytopicconsumerGroupqueueIdoffset与消息轨迹联动：business exception  -&gt; search event key  -&gt; view message trace  -&gt; locate application log  -&gt; inspect downstream result本章小结RocketMQ 监控要从业务结果反推技术链路，覆盖生产端、Broker、存储、副本、消费端、死信和 Proxy。告警要关注趋势、年龄和影响范围，而不是静态数量。端到端的业务键与消息轨迹是高效排障的关键。思考题  lag 增长但消费耗时正常，可能是什么问题？  为什么死信年龄比死信数量更有意义？  生产重试率升高为什么要与 Broker 指标一起看？  dispatch lag 会造成什么误判？  Proxy 延迟和 Broker 延迟如何区分？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。容量规划是把“业务量”翻译成“机器、磁盘、网络、队列、线程和人员流程”的过程。RocketMQ 集群出问题，常见原因不是峰值 TPS 本身，而是保留时间、消费落后、重试风暴和冷读查询没有被纳入模型。21.1 输入指标规划前先收集：            指标      说明                  peak TPS      分钟或秒级峰值              message size      平均值和 P99              consumer lag      正常和异常峰值              retention      数据保留时间              topic count      Topic 和队列数量              burst factor      促销、重试、重放              recovery window      故障恢复时间              replica count      副本数              query load      消息查询和轨迹      不要只用日均值规划。消息系统容量通常被峰值、尾部延迟和故障恢复场景压垮。21.2 写入容量估算：write throughput = peak tps × avg message size × replica countdaily bytes = average bytes per second × timedisk required = daily bytes × retention days × expansion factor示例：peak tps = 20,000 msg/savg size = 1 KiBreplicas = 2write throughput = 40 MiB/s还要叠加：  网络协议开销；  索引开销；  轨迹消息；  重试消息；  峰值持续时间；  磁盘写入放大。21.3 磁盘容量磁盘水位建议：            水位      动作                  60%      关注增长趋势              70%      评估扩容或治理              80%      高优处理              90%      冻结非关键变更，启动预案              拒写水位      保护数据一致性      预留空间要覆盖：  最长消费积压周期；  磁盘故障恢复时间；  备份和迁移窗口；  突发流量；  系统文件和日志；  轨迹与死信；  一个可控告警响应周期。21.4 队列与消费并行度估算：required consumers = target tps / per-consumer tpsqueues &gt;= consumer instances × useful parallelism示例：target = 8,000 msg/sone consumer instance = 1,000 msg/sinstances = 8queues = 16 or 32如果单条消息依赖数据库事务，消费能力通常先到数据库连接池或下游 RPC 上限，而不是客户端线程上限。21.5 网络容量单条消息产生的流量不止 body：client -&gt; broker requestbroker -&gt; replica replicationbroker -&gt; consumer deliveryconsumer -&gt; broker ackmetrics and trace规划：  生产带宽；  复制带宽；  消费带宽；  跨可用区带宽；  备份带宽；  管理和查询流量。跨机房同步副本时，网络延迟直接影响同步复制写入延迟。21.6 高可用余量N+1 原则示例：normal load = 60% capacityone broker down = remaining can hold 100% peak需要验证：  剩余磁盘增长速度；  剩余 Broker 写入延迟；  副本数量是否下降；  消费者是否重平衡；  故障恢复窗口；  Controller 仲裁是否健康。21.7 多租户隔离不同业务风险不同：            级别      示例      策略                  核心      支付、订单      独立集群或独立 Broker 组              重要      用户通知      配额和优先级              普通      行为日志      采样、限流、低成本盘              批量      重放、补偿      独立窗口和限速      至少要做到：  Topic 配额；  消息大小限制；  消费组隔离；  重试风暴熔断；  查询限流；  关键业务不与批处理混部。21.8 压测模型压测场景：  峰值写入；  峰值消费；  写读混合；  冷查询；  重试风暴；  Broker 故障；  磁盘高水位；  消费者重平衡；  长时间稳定性。记录结果：tpsp95 / p99 latencydisk throughputnetwork throughputcpu usagepage cache behaviorlag recovery timeerror rate压测数据要保留，作为容量模型修正依据。21.9 容量评审清单  峰值 TPS 和消息大小；  保留时间与最大 lag；  副本和跨可用区拓扑；  队列数与消费并行度；  磁盘和网络余量；  轨迹、重试、死信、系统 Topic；  备份和迁移窗口；  多租户隔离；  故障演练结果；  扩容触发条件。本章小结容量规划要把业务峰值、消息大小、保留时间、副本数、消费能力、重试流量、查询负载和故障恢复窗口全部纳入模型。磁盘不是唯一指标，队列数、网络、下游数据库和多租户隔离同样关键。模型必须通过压测和真实流量持续修正。思考题  为什么日均值不适合作为唯一容量依据？  副本数如何影响磁盘和网络？  消费者数量为什么常受下游限制？  重试风暴如何纳入容量模型？  N+1 余量如何验证？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。RocketMQ 的扩缩容不只是加减机器。Broker、Topic 队列、消费者、Proxy 和存储都有不同伸缩边界。目标是让写入容量、消费并行度、磁盘保留和网络带宽与业务负载匹配，并在变更中保持路由、位点和高可用状态可控。20.1 容量瓶颈分层            层      瓶颈信号                  Producer      发送超时、线程阻塞、本地事件积压              Broker      写入延迟、磁盘繁忙、请求堆积              存储      磁盘水位、文件增长过快              Consumer      lag 增长、消费耗时高、死信增加              Network      带宽、重传、跨机房延迟              Proxy      连接数、请求队列、转发延迟      先判断瓶颈层级，再决定扩容对象。盲目扩消费者无法解决磁盘满，扩 Broker 也无法解决下游数据库慢。20.2 Broker 扩容新增 Broker 后，新 Broker 默认主要承接新 Topic 或新队列，已有 Topic 数据不会自动迁移。变更步骤：prepare capacity  -&gt; install broker  -&gt; configure replication and acl  -&gt; register to nameserver  -&gt; create or move queues  -&gt; validate route  -&gt; gradual traffic检查项：  Broker 版本一致；  副本分布合理；  磁盘目录独立；  告警和指标接入；  Topic 权限同步；  管理工具可达；  高可用仲裁健康。20.3 队列扩容队列数影响：  写入分散度；  消费最大并行度；  顺序消息路由；  位点管理复杂度；  索引文件数量。示例：before: 4 queuesafter:  8 queues新增队列从末尾开始写入，消费者重平衡后可以分配新队列。减少队列要确认旧队列消费完成，且顺序业务不会受影响。20.4 消费者扩容消费者有效并行度受队列数限制：8 queues4 consumer instances  -&gt; useful10 consumer instances -&gt; at least 2 idle扩容顺序：  先确认是消费处理瓶颈；  优化慢 SQL 和下游调用；  增加消费实例；  增加消费线程；  最后考虑增加队列；  观察重平衡和重复。20.5 存储扩容方式：            方式      特点                  扩磁盘      简单，适合云盘              增加 Broker      分散新写入              Topic 队列迁移      需要治理旧数据              降低保留时间      减少容量，但影响回溯              归档冷数据      适合审计场景      磁盘满的处理顺序：stop risky growth  -&gt; confirm oldest data requirement  -&gt; clean expired files  -&gt; expand disk  -&gt; rebalance traffic  -&gt; review capacity model不能在未确认消费位点前删除旧数据。20.6 缩容流程Broker 缩容：  确认节点是否仍有主副本；  迁移或等待 Topic 队列不再写入；  确认消费者位点完成；  摘除路由；  停止流量；  保留数据备份；  最后下线节点。顺序：readiness check  -&gt; route change  -&gt; drain  -&gt; shutdown  -&gt; backup  -&gt; delete缩容最容易出问题的不是停机，而是路由残留和数据仍被依赖。20.7 自动伸缩适合自动伸缩：  Proxy 无状态层；  消费应用实例；  云主机规格调整；  前置网络带宽。谨慎自动伸缩：  Broker 有状态节点；  副本仲裁拓扑；  Topic 队列数；  存储目录。自动策略应以 lag、消息年龄、消费耗时、磁盘水位等多指标组合判断，避免单指标抖动引发频繁变更。20.8 变更验证扩缩容后检查：route correctnessbroker disk balancequeue assignmentconsumer lagsend latencyconsume latencyretry and dead letterreplica sync statebusiness reconciliation保留回滚窗口：  原配置可恢复；  原节点可重新加入；  旧路由可回滚；  监控对比扩容前后；  业务指标确认正常。20.9 常见错误            错误      后果              消费者超过队列数      实例空转              直接减少队列      历史消息漏消费或顺序破坏              Broker 版本不一致      兼容性问题              新 Broker 无权限配置      生产失败              存储与日志混盘      扩容后仍磁盘瓶颈              未演练重平衡      变更窗口消费抖动              磁盘满后立即删文件      数据不可恢复      本章小结弹性扩缩容要区分接入层、计算层、队列并行度和有状态存储层。消费者和 Proxy 可以较容易水平扩展，Broker、队列和副本拓扑则需要严谨的数据与路由治理。所有变更都应有容量评估、灰度窗口、验证清单和回滚方案。思考题  为什么新增 Broker 后旧 Topic 流量通常不会自动迁移？  消费者实例数和队列数是什么关系？  减少队列前要确认什么？  哪些层适合自动伸缩，哪些不适合？  磁盘满时为什么不能直接删除最旧文件？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Proxy 模式是 RocketMQ 5.x 的重要架构形态：客户端接入 Proxy，由 Proxy 转发或协调请求到 Broker。它让接入层、协议适配和计算逻辑与存储节点解耦，更适合云原生、多语言客户端和统一治理场景。19.1 架构位置Client  -&gt; Proxy     -&gt; NameServer     -&gt; BrokerProxy 可以提供：            能力      价值                  接入层隔离      客户端不直连 Broker              多协议适配      gRPC、remoting 等              认证与限流      统一入口治理              流量调度      灰度、就近、负载均衡              运维抽象      Broker 演进对客户端透明      Proxy 不是简单负载均衡器，它理解消息语义和路由状态。19.2 Local 与 Cluster 模式常见部署模式：            模式      说明                  Local      Proxy 与 Broker 同进程或同节点部署              Cluster      Proxy 独立部署成接入层集群      Local 模式部署简单，适合传统架构逐步演进。Cluster 模式更适合：  多机房统一接入；  大规模客户端连接；  多语言 gRPC 接入；  计算存储分离；  云环境弹性伸缩。19.3 客户端连接客户端从连接 Broker 地址改为连接 Proxy 地址：namesrv.addr -&gt; proxy endpoint配置示例：rocketmq.proxy.endpoint=rocketmq-proxy:8081迁移时必须确认：  客户端版本支持；  协议类型匹配；  TLS 和 ACL 策略；  超时和重试参数；  Proxy 到 Broker 网络连通；  现有消息轨迹和治理系统兼容。19.4 请求路径发送：producer  -&gt; proxy receive  -&gt; validate and route  -&gt; broker append  -&gt; proxy return result消费：consumer  -&gt; proxy subscribe/pull  -&gt; broker read  -&gt; proxy return  -&gt; consumer process  -&gt; proxy commit offset每个跳点都会增加少量延迟，但也带来集中观测和治理能力。19.5 无状态化与伸缩Cluster 模式的 Proxy 应尽量减少本地状态：  路由从 NameServer 或 Broker 获取；  位点保存在 Broker；  会话可重建；  指标集中采集；  优雅摘除流量。扩容前确认：CPUmemoryconnectionsnetwork bandwidthrequest queueupstream latencyProxy 扩容不能解决 Broker 磁盘瓶颈。19.6 可用性设计Proxy 故障不应成为单点：  多实例部署；  客户端配置多个 endpoint；  负载均衡健康检查；  优雅停机；  与 Broker 故障域分离；  控制连接耗尽；  请求重试有退避。故障判断：            现象      层次                  Proxy 连不上      接入层或负载均衡              Proxy 健康但请求失败      Broker、存储、权限              只有部分 Topic 失败      路由、权限、队列              延迟整体升高      Proxy 或网络              发送成功消费失败      消费链路或订阅      19.7 多语言支持5.x 的 gRPC 接口降低多语言客户端成本：  Java、Go、Python 等语言可接入；  使用标准 gRPC 生态做连接管理；  序列化契约由客户端 SDK 定义；  仍需复用平台级鉴权和重试策略；  不同语言 SDK 成熟度需评估。建议核心链路先压测，再统一 SDK 版本和超时规范。19.8 监控指标proxy_active_connectionsproxy_request_totalproxy_request_error_totalproxy_request_latency_msproxy_upstream_latency_msproxy_request_queue_sizeproxy_route_refresh_totalproxy_auth_failure_totalproxy_graceful_close_duration_ms将客户端指标、Proxy 指标和 Broker 指标放在同一时间线中观察，才能区分接入层问题和存储层问题。19.9 迁移策略  新业务先走 Proxy；  非核心旧业务灰度；  双写或双消费只在验证环境使用；  对比消息轨迹和业务对账；  保留回滚配置；  明确客户端 SDK 版本；  分批切换；  切换窗口准备容量余量。本章小结Proxy 模式让 RocketMQ 的接入层和存储层解耦，带来多语言、云原生和统一治理优势。Local 模式适合渐进部署，Cluster 模式适合大规模平台化架构。引入 Proxy 后，要额外治理连接数、转发延迟、路由刷新、安全策略和多一层故障定位。思考题  Proxy 模式解决了哪些直连 Broker 的治理问题？  Local 与 Cluster 模式的适用场景是什么？  Proxy 扩容为什么不能解决存储瓶颈？  Proxy 故障和 Broker 故障如何区分？  从旧客户端迁移到 Proxy 需要哪些兼容性验证？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Controller 模式是 RocketMQ 5.x 高可用架构的重要演进方向，用独立的控制器参与副本选主、角色切换和副本一致性裁决。相比传统手工主从或基于内嵌共识组件的模式，它把“谁能当主”这件事从人工操作和节点自判中抽离出来。18.1 传统主从的问题传统主从部署中，如果主节点故障：master down  -&gt; ops detects  -&gt; promote replica  -&gt; update route  -&gt; client reconnect风险：  人工介入时间不可控；  提升哪个副本需要判断位点；  老主恢复后可能出现双主；  切换期间写入不可用；  消费位点可能超过数据位点。自动高可用要解决的不只是“切换快”，还包括“怎么选最安全的副本”和“如何避免脑裂”。18.2 Controller 的职责Controller 常见职责：            职责      说明                  副本选举      选择可提升为主 的副本              角色裁决      决定 master / replica              epoch 管理      通过递增任期隔离旧主              复制状态      跟踪副本同步进度              路由联动      与 NameServer 协同更新              异常恢复      处理节点重新上线      不同小版本的功能范围可能变化，部署前应以当前官方文档和配置说明为准。18.3 选主流程示意流程：master heartbeat timeout  -&gt; controller detects failure  -&gt; select replica with latest durable state  -&gt; verify replica synchronization  -&gt; increase epoch  -&gt; promote replica to master  -&gt; notify brokers and nameservers  -&gt; old master rejoins as replica关键判断是副本位点，而不是简单选择编号最小的节点。18.4 Epoch 与 fencingepoch 或 term 用于隔离旧 leader：epoch 10 old masterepoch 11 new master当旧主恢复后：  发现已有更高 epoch；  停止接受写入；  对齐新主数据；  转为副本；  不再以旧身份返回成功。如果缺乏有效 fencing，客户端可能仍连接旧主，造成双写或数据回退。18.5 部署形态常见部署：  Controller 独立部署多节点；  Controller 与 Broker 混合部署；  云托管平台托管控制器；  Controller 使用 Raft 或其他共识机制维持自身可用性。建议：  Controller 至少 3 个投票节点；  与 Broker 分故障域部署；  使用低延迟稳定网络；  明确仲裁节点分布；  不与高负载存储盘混抢资源；  保留运维命令和配置审计。18.6 故障场景            故障      行为目标                  主 Broker 宕机      选举同步副本              副本宕机      主继续服务，副本不足时告警              Controller 宕机      多数派仍可用              网络分区      多数派继续，少数派不可提升              NameServer 故障      已有路由可服务，新发现受影响              机房故障      跨可用区副本参与恢复      注意：Controller 保证的是副本编排层面的高可用，不替代备份、监控和容量规划。18.7 客户端影响切换期间客户端可能遇到：  连接断开；  发送超时；  路由更新延迟；  队列重分配；  消费重平衡；  重试增加。应用应配置：send timeoutretry timesbackoffconsume timeoutcircuit breakerlocal compensation不要在发送失败时无退避地猛打重试。18.8 监控指标controller_leader_existscontroller_epochcontroller_voting_quorum_sizebroker_rolebroker_sync_statereplica_sync_offset_diffmaster_switch_totalmaster_switch_duration_msbroker_offline_total告警：  无 Controller leader；  仲裁节点不可用；  副本长期未同步；  频繁切换；  epoch 异常变化；  副本数量低于预期。18.9 演练清单  重启主 Broker；  重启副本；  关闭一个 Controller；  关闭多数 Controller；  模拟网络分区；  磁盘满；  NameServer 不可用；  客户端重连；  旧主恢复；  跨可用区断连。演练要验证数据位点、消息完整性、路由状态和业务对账结果，而不只是看服务是否恢复。本章小结Controller 模式把自动选主、角色裁决和 fencing 引入 RocketMQ 高可用体系，降低人工恢复成本和脑裂风险。高可用能力依赖仲裁拓扑、副本同步、NameServer 路由和客户端重试策略共同工作。生产上必须监控 epoch、副本差距和切换次数，并通过真实故障演练验证。思考题  自动选主为什么要选择位点最新的副本？  epoch 如何防止旧主继续写入？  Controller 集群为什么需要奇数投票节点？  NameServer 故障时客户端为什么可能仍能发送？  为什么副本长期不同步比一次切主更危险？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。Broker 是 RocketMQ 的存储与服务节点。它接收生产者请求，维护 Topic 路由和队列，写入 CommitLog，构建消费索引，向消费者提供拉取服务，并参与权限控制、延迟调度、事务回查和高可用切换。17.1 整体组件Broker  |-- remoting server       网络通信  |-- topic manager         Topic、队列、权限  |-- message store         CommitLog、ConsumeQueue、Index  |-- consumer manager      消费组、位点、订阅  |-- transaction service   半消息与回查  |-- schedule service      延迟或定时消息  |-- replication           主从复制  |-- admin service         运维接口  `-- stats / metrics       指标与审计Broker 不是简单转发进程，大多数核心逻辑都围绕本地存储状态展开。17.2 请求处理链路发送：client request  -&gt; decode protocol  -&gt; auth and rate limit  -&gt; validate topic  -&gt; append message  -&gt; replicate / flush  -&gt; response消费：consumer pull request  -&gt; check subscription  -&gt; read consumequeue  -&gt; filter message  -&gt; read commitlog  -&gt; response  -&gt; consumer commit offset later理解链路有助于判断瓶颈在 CPU、内存、磁盘、网络还是下游服务。17.3 Topic 与路由Broker 维护：            对象      内容                  TopicConfig      队列数、权限、类型              QueueData      Broker、queueNum、权限              RouteInfo      NameServer 汇总后的路由      NameServer 保存路由快照，不负责强一致事务。Broker 配置修改后要确认所有 NameServer 的视图一致。17.4 消费组管理Broker 记录：  消费组名称；  订阅关系；  队列位点；  客户端连接；  重试和死信配置。订阅关系必须一致：group: order-consumerinstance A -&gt; OrderTopic, TagAinstance B -&gt; OrderTopic, TagB同一消费组订阅不同 Topic 或 Tag，会导致消费异常、队列分配混乱或位点不正确。17.5 线程模型常见线程类型：            线程      作用                  Accept / EventLoop      网络连接和 IO              Request worker      请求处理              PutMessage      消息写入              PullMessage      消息读取              Reput      索引分发              Flush      刷盘              Clean      文件回收              Admin      运维命令      线程堆积通常不是“加线程数”能解决的问题，要先看锁竞争、磁盘延迟、页缓存和下游状态。17.6 内存与磁盘内存主要用于：  网络缓冲；  热点队列索引；  消息查询；  线程栈；  页缓存。磁盘主要用于：  CommitLog；  ConsumeQueue；  IndexFile；  配置和 checkpoint；  日志。生产建议：  数据盘与系统盘分离；  日志目录单独监控；  避免多个存储型服务抢盘；  关注 inode、文件句柄、目录项；  使用与集群规模匹配的磁盘类型。17.7 限流与保护Broker 可以从以下维度保护：            维度      示例                  Topic      限制写入 TPS              消息大小      拒绝超大消息              队列      防止单队列热点              消费拉取      限制空拉和过载              请求      限制 admin 和查询              磁盘      高水位拒写      应用侧也应设置生产并发和重试上限，避免 Broker 故障时客户端重试风暴。17.8 安全边界Broker 层安全包括：  ACL 账号；  Topic 读写权限；  管理接口鉴权；  TLS 传输加密；  IP 白名单；  审计日志。最小权限示例：order-service:  OrderTopic        READ_WRITE  OrderDLQTopic     READ  admin topic       DENY不要给业务应用统一管理员账号。17.9 观测指标broker_active_connectionsbroker_request_queue_sizebroker_put_tpsbroker_get_tpsbroker_put_latency_p99broker_pull_latency_p99broker_thread_pool_activecommitlog_dispatch_lagbroker_disk_usagebroker_exception_total排障时先固定一个视角：时间线  -&gt; 客户端现象  -&gt; Broker 指标  -&gt; 磁盘和网络  -&gt; 代码或配置变更17.10 常见故障            现象      可能原因                  Broker 退出      OOM、磁盘损坏、系统重启、误操作              请求堆积      磁盘慢、热点 Topic、线程池满              Topic 不存在      配置丢失、环境错误、权限              路由不更新      NameServer 连接异常              消费位点丢失      配置损坏、异常恢复、误操作              查询慢      冷读、索引重、磁盘竞争      本章小结Broker 的核心职责是把网络请求转换为可靠的本地存储状态，并维护 Topic、队列、消费组、事务和复制的一致性。读懂数据流和线程模型，才能判断性能瓶颈与故障根因。生产环境必须同时治理磁盘、路由、订阅、权限、限流和指标。思考题  Broker 与 NameServer 的职责边界是什么？  为什么同一消费组订阅关系必须一致？  哪些问题会表现为请求线程堆积？  Broker 高磁盘水位应该如何处理？  为什么业务应用不应使用管理员账号？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。刷盘决定单机数据在机器故障下的持久性，复制决定多机数据在节点故障下的可用性。RocketMQ 的可靠性不是单个开关，而是“客户端确认 + 刷盘策略 + 复制策略 + 故障切换 + 运维流程”的组合结果。16.1 可靠性层次Producer receive OK  -&gt; Broker memory  -&gt; local disk  -&gt; replica memory  -&gt; replica disk每前进一层，抗故障能力增强，延迟和成本也增加。            故障      需要的保护                  生产进程崩溃      发送状态与补偿              Broker 进程崩溃      操作系统页缓存              宿主机断电      本地刷盘              单机磁盘损坏      异地副本或备份              机房故障      跨可用区或跨地域容灾      16.2 同步刷盘与异步刷盘            模式      返回时机      特点                  SYNC_FLUSH      消息落盘后返回      单机可靠性高，延迟受磁盘影响              ASYNC_FLUSH      写入后异步刷盘      吞吐高，宿主机断电可能丢失      异步刷盘并非没有价值。配合同步复制和多副本，可以在性能与可靠性之间取得平衡。选择建议：  交易、支付、账务类事件优先高可靠配置；  行为日志可接受较低成本配置；  性能结论必须基于自身磁盘和压测；  任何模式都要有业务对账；  不要只看参数名，要确认版本语义。16.3 复制模式传统主从模式常见配置：            模式      说明                  SYNC_MASTER      主节点等待至少一个从节点确认              ASYNC_MASTER      主节点不等待从节点              SLAVE      只读副本，可承载消费拉取      同步复制流程：master append message  -&gt; flush local  -&gt; replicate to slave  -&gt; slave persist  -&gt; slave ack  -&gt; master return success异步复制流程：master append message  -&gt; return success  -&gt; replicate later16.4 高可用架构演进常见模式：  主从读写分离；  DLedger 自动切换；  Controller 模式；  5.x Proxy 与计算存储分离；  云托管多可用区部署。演进逻辑：手工运维  -&gt; 自动选主  -&gt; 元数据中心化  -&gt; 计算接入层与存储层解耦不同模式的部署要求、客户端兼容性和恢复行为不同，不能只比较功能名。16.5 副本一致性关注三个位点：            位点      含义                  master commit offset      主节点已确认位点              slave replica offset      从节点已复制位点              consumer offset      消费组确认位点      故障切换时必须处理：  未复制到新主的尾部消息；  消费位点是否超过数据位点；  老主恢复后是否脑裂；  客户端路由何时更新；  事务和定时消息状态；  运维操作审计。16.6 脑裂与 fencing脑裂指两个节点同时认为自己是主。常见防线：  Controller 或 DLedger 多数派仲裁；  epoch 或 term 递增；  共享磁盘锁；  客户端路由校验；  网络分区时禁止双写；  恢复流程强制对齐位点。生产环境不应只依赖人工确认角色，要依赖仲裁机制和版本 fencing。16.7 跨可用区部署典型拓扑：zone A: broker-a-master, broker-b-replicazone B: broker-a-replica, broker-b-master收益：  单可用区故障可恢复；  流量分布更均衡；  副本不集中在一个故障域。代价：  同步复制延迟增加；  带宽成本增加；  运维复杂度提高；  机房间网络抖动影响写入；  需要验证 NameServer 与客户端路由策略。16.8 监控与演练指标：broker_flush_latency_msreplica_sync_latency_msreplica_diff_bytesbroker_rolebroker_epochunsynced_replica_countmaster_changes_totaldisk_usage_ratio必做演练：  kill Broker 进程；  宿主机断电重启；  断开从节点网络；  机房间网络抖动；  磁盘故障；  主从位点不一致恢复；  客户端重连和路由更新。16.9 常见问题            现象      排查                  发送延迟高      同步刷盘慢、同步复制等待              从节点落后      网络带宽、从节点磁盘、写入热点              切主后消息缺失      异步复制尾部未同步              双主      仲裁异常、配置错误、脑裂              副本无法同步      角色、地址、权限、版本              磁盘告警      保留策略、消费落后、容量不足      本章小结刷盘和复制决定消息持久化边界。同步刷盘增强单机断电能力，同步复制增强节点故障能力，自动选主增强可用性，但都伴随延迟与成本。生产设计要明确业务容忍度，压测验证，并持续监控副本差距和演练故障恢复。思考题  异步刷盘最怕什么故障？  同步复制能防止磁盘损坏导致的丢失吗？  为什么切主可能造成尾部消息差异？  脑裂为什么必须依赖仲裁和 fencing？  跨可用区部署的主要代价是什么？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。ConsumeQueue 把 CommitLog 中的物理消息组织成 Topic 和 Queue 的逻辑视图，IndexFile 提供按 Key 和时间查询的索引。两者都是派生数据，但它们直接决定消费效率和问题排查效率。15.1 ConsumeQueue 结构每个 Topic 的每个队列对应一个 ConsumeQueue 目录：store/consumequeue/OrderTopic/  0/  1/  2/  3/每个条目通常包含：CommitLog offsetmessage sizetag hashcode消费者流程：read ConsumeQueue entry  -&gt; get CommitLog offset and size  -&gt; read message from CommitLog15.2 逻辑位点消费者位点指的是队列中的逻辑偏移：Queue offset: 0, 1, 2, 3 ...Broker 最大位点来自 ConsumeQueue 条目数：Broker Offset = ConsumeQueue entriesDelayed = Broker Offset - Consumer Offset同一个逻辑位点在不同 Broker 或重建后的集群中不一定指向相同物理消息，因此迁移和重放要格外谨慎。15.3 Tag 过滤ConsumeQueue 条目中保存 Tag hashcode，Broker 可以先做粗过滤：consumer subscribes TagA  -&gt; compare entry tag hashcode  -&gt; candidate message sent to consumer  -&gt; client validates real tag特点：  减少不必要消息传输；  hash 冲突由客户端最终校验；  订阅关系必须一致；  Tag 修改会影响过滤效果；  复杂表达式会消耗 Broker CPU。15.4 IndexFileIndexFile 支持按消息 Key 和时间范围查询：query key = O202608250001  -&gt; hash to slot  -&gt; scan index entry list  -&gt; filter by key and time  -&gt; read CommitLog常见字段：  key hash；  CommitLog offset；  message size；  timestamp；  index chain。IndexFile 便于排查，不是业务数据库查询引擎。高频业务查询应使用数据库或搜索引擎，而不是依赖消息索引。15.5 索引构建Broker 在消息写入 CommitLog 后异步分发：CommitLog append  -&gt; ReputMessageService  -&gt; build ConsumeQueue  -&gt; build IndexFile如果分发落后，可能出现：  消息已写入但消费者暂时看不到；  按消息 ID 查询和按 Key 查询结果不一致；  Broker 流量高时索引构建延迟。监控 dispatch lag 和队列最大位点，避免误判消息丢失。15.6 重建与恢复ConsumeQueue 和 IndexFile 理论上可以从 CommitLog 重建：scan CommitLog  -&gt; parse message  -&gt; rebuild queue index  -&gt; rebuild key index注意：  重建需要磁盘、CPU 和时间；  必须先备份原始 CommitLog；  重建期间影响服务；  需要验证队列位点；  严格按当前版本运维手册操作；  有副本时优先从副本恢复。15.7 容量规划估算：ConsumeQueue size ≈ queue message count × entry sizeIndex size ≈ key count × index entry size × expansion factorCommitLog size ≈ message body + overhead规划时还要考虑：  Topic 数量；  队列数量；  消息大小；  Key 数量；  保留时间；  重试和死信；  轨迹 Topic；  运维余量。15.8 常见问题            问题      排查                  消费者看不到新消息      ConsumeQueue 构建延迟、位点、权限              按 Key 查不到      未设置 Key、索引延迟、索引过期              延迟突然增大      消费慢、Index 冷读、磁盘瓶颈              磁盘被索引占满      Topic、队列或 Key 过多              队列位点不一致      异常关机、手工重置、迁移              重建后查询异常      索引不完整或时间范围错误      本章小结ConsumeQueue 是 Topic 队列的逻辑索引，Index 是面向排查的 Key 和时间索引。它们让 RocketMQ 兼顾顺序写吞吐和多维度读取，但也带来构建延迟、容量和恢复复杂度。生产治理要同时关注 CommitLog、ConsumeQueue、Index 和消费位点的一致性。思考题  消费位点为什么是队列逻辑位点而不是 CommitLog 偏移量？  Tag 粗过滤为什么仍需要客户端校验？  Index 为什么不适合作为业务查询引擎？  dispatch lag 会造成什么误判？  重建索引前为什么必须备份 CommitLog？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。CommitLog 是 RocketMQ Broker 的核心存储文件，所有 Topic 的消息都会顺序追加到同一个 CommitLog 中。理解 CommitLog，才能理解 RocketMQ 的写入性能、磁盘布局、文件回收和恢复机制。14.1 存储全景Producer  -&gt; Broker     -&gt; CommitLog      所有消息的物理正文     -&gt; ConsumeQueue   每个队列的逻辑索引     -&gt; IndexFile      Key 和时间查询索引  -&gt; Consumer消息正文只存一份，ConsumeQueue 保存的是定位信息：ConsumeQueue entry:  CommitLog offset  message size  tag hashcode这种设计让写入集中在少量文件上，有利于顺序写和页缓存，同时仍能按队列消费。14.2 文件布局典型目录：store/  commitlog/    00000000000000000000    00000000001073741824    00000000002147483648  consumequeue/    OrderTopic/      0/      1/  index/    20260825000000000  config/  checkpointCommitLog 文件名通常表示该文件起始偏移量。文件大小常见为 1GB，具体默认值随版本和配置变化。14.3 写入流程validate message  -&gt; get or create MappedFile  -&gt; append message to CommitLog  -&gt; build ConsumeQueue and Index dispatch  -&gt; flush according to policy  -&gt; replicate according to role关键组件：            组件      职责                  PutMessage 线程      接收并写入消息              ReputMessageService      构建 ConsumeQueue 和 Index              FlushCommitLogService      刷盘              GroupTransferService      同步复制等待              CleanCommitLogService      过期文件回收      14.4 MappedFile 与页缓存RocketMQ 使用内存映射文件写入 CommitLog。写入先进入页缓存，何时落盘取决于刷盘策略和操作系统回写机制。风险：  宿主机断电可能丢失未刷盘数据；  页缓存污染会影响延迟；  大量冷读会挤占页缓存；  内存映射异常需要观察 Broker 日志和磁盘状态。生产建议：  独立数据盘；  使用满足延迟和可靠性要求的文件系统；  关注 iowait、脏页和写入延迟；  避免与日志、搜索索引混盘；  大规模冷读改走备份或对象存储。14.5 消息大小与格式CommitLog 中每条消息包含：  消息长度；  Topic；  properties；  body；  queueId；  storeTime；  校验信息；  物理偏移量相关信息。版本不同，具体编码和校验字段可能有差异。应用侧应避免构造超大消息，优先采用“小消息 + 对象存储引用”的模式。14.6 文件过期与删除保留策略通常由文件保留时间和磁盘水位控制：if file is fully expired and disk usage below threshold:    delete fileelif disk usage exceeds threshold:    force clean old files or reject writes治理要点：  保留时间要大于最长消费延迟和故障恢复窗口；  死信和重试 Topic 也要纳入容量；  磁盘高水位会触发告警或拒写；  不能在消费者长期落后时随意删除数据；  扩容前先评估磁盘增长速度。14.7 恢复机制Broker 启动时会校验并恢复存储：read checkpoint  -&gt; load commitlog files  -&gt; validate message  -&gt; recover consumequeue  -&gt; rebuild dispatch if needed异常断电后：  最后一笔未完整写入的消息可能被截断；  副本之间需要比较位点；  Controller 或 DLedger 模式参与选主；  恢复时间与 CommitLog 数量和损坏程度相关。不要在未确认文件副本和位点前手工删除“看起来异常”的存储文件。14.8 性能观测指标：broker_put_requests_totalbroker_put_latency_mscommitlog_flush_latency_mscommitlog_mapped_file_countdisk_usage_ratiodisk_write_iopsdisk_write_throughputpage_cache_hit_ratiodispatch_lag异常判断：            现象      可能原因                  写入延迟升高      磁盘瓶颈、刷盘慢、复制等待              dispatch lag      Reput 线程积压              磁盘增长快      保留过长、消费落后、重试风暴              页缓存命中率下降      冷读过多              文件创建异常      磁盘满、权限、文件句柄      14.9 生产实践  CommitLog 使用独立高性能盘；  根据可靠性选择刷盘和复制策略；  控制单条消息大小；  设置磁盘告警和拒写水位；  预估至少一个故障恢复周期的保留容量；  压测写入、消费、冷查混合场景；  定期演练 Broker 重启恢复；  备份关键 Topic 和配置。本章小结CommitLog 用“全局顺序追加 + 队列索引”的方式兼顾写入吞吐和队列消费模型。它决定了 RocketMQ 的磁盘形态、恢复逻辑和容量上限。生产环境要重点关注刷盘、复制、页缓存、文件回收和恢复时间，而不是只看发送 TPS。思考题  为什么所有 Topic 共用 CommitLog 有利于顺序写？  ConsumeQueue 保存的是消息正文还是索引？  异步刷盘在什么故障下可能丢数据？  保留时间为什么要大于消费延迟窗口？  Broker 启动恢复时为什么要校验最后写入的数据？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。消息系统通常提供至少一次投递语义，重复是常态而不是异常。幂等设计的目标是：同一条消息、同一个事件或同一个业务指令被处理多次，最终业务结果只生效一次。13.1 为什么会重复常见来源：producer send timeout -&gt; internal retry -&gt; duplicateconsumer process success -&gt; offset commit fail -&gt; redeliverconsumer timeout -&gt; broker retry -&gt; duplicatedead letter replay -&gt; duplicatecompensation task -&gt; duplicatenetwork retry -&gt; duplicate重复不能完全避免，必须在消费端和业务端处理。13.2 幂等边界先定义“什么算同一次”：            粒度      幂等键                  事件      eventId              订单操作      orderNo + eventType + version              支付请求      paymentId              库存变更      changeId              用户任务      taskId              外部回调      requestId      不要用消息 ID 作为唯一业务幂等依据。消息 ID 标识一次物理消息，业务重发可能产生不同消息 ID，但代表同一业务事件。13.3 数据库唯一约束事件表：CREATE TABLE processed_event (  event_id VARCHAR(64) PRIMARY KEY,  event_type VARCHAR(64) NOT NULL,  aggregate_id VARCHAR(64) NOT NULL,  consumed_at DATETIME(6) NOT NULL,  result_status VARCHAR(20) NOT NULL,  UNIQUE KEY uk_event_type_id (event_type, event_id));处理：@Transactionalpublic void handle(OrderCreatedEvent event) {    try {        processedEventRepository.insert(event.eventId(),                "OrderCreated", event.orderNo(), "SUCCESS");        orderService.create(event);    } catch (DuplicateKeyException e) {        log.info("duplicate event ignored, eventId={}", event.eventId());    }}事件插入和业务处理必须在同一个本地事务中。13.4 状态机幂等状态变更必须带前置条件：UPDATE ordersSET status = 'PAID', paid_at = NOW(6), version = version + 1WHERE order_no = ?  AND status = 'WAIT_PAY'  AND version = ?;结果判断：            更新行数      含义                  1      首次生效              0      已处理、状态不允许或版本不匹配      不能只执行“无条件 update”，否则重复事件可能覆盖较新的状态。13.5 业务动作唯一键扣减库存：INSERT INTO inventory_change(  change_id, sku_id, order_no, quantity, created_at) VALUES (?, ?, ?, ?, NOW(6));用 change_id 唯一约束控制重复扣减，再通过触发器或应用事务更新库存汇总。账户入账：INSERT INTO account_transaction(  transaction_id, account_id, amount, direction, created_at) VALUES (?, ?, ?, ?, NOW(6));金融场景还应对账：sum(account_transaction) = account.balance13.6 Redis 幂等Redis 适合做快速拦截：Boolean first = redis.opsForValue()        .setIfAbsent("idempotent:" + event.eventId(), "PROCESSING", Duration.ofMinutes(10));if (Boolean.FALSE.equals(first)) {    return;}try {    handleInDatabase(event);} catch (Exception e) {    redis.delete("idempotent:" + event.eventId());    throw e;}限制：  Redis 可能丢失；  过期后仍会重复；  主从切换可能带来窗口；  不能替代数据库唯一约束；  只能作为性能优化。最终裁决应落在业务数据库或账务表。13.7 并发控制同一消息可能被并发重试：thread A -&gt; insert eventthread B -&gt; insert event处理方式：  数据库唯一键；  分布式锁，但锁只用于减少冲突；  按聚合 ID 分片；  顺序消费单 key；  乐观锁版本；  条件更新。不要依赖“重试不会并发”的假设。13.8 幂等测试必测场景：  同一 eventId 连续处理两次；  同一 eventId 并发处理；  处理成功但位点提交失败；  处理失败后重试；  死信重放；  补偿任务与消息并发；  版本旧事件晚到；  Redis 幂等键过期。断言示例：handle(event);handle(event);assertEquals(1, inventoryRepository.findReserved(event.orderNo()).size());13.9 常见错误            错误      后果                  只判断内存 Set      重启后失效              只使用 Redis      缓存丢失后重复              事件表与业务不同事务      部分成功              无条件更新状态      新状态被旧事件覆盖              用消息 ID 做业务幂等      重发绕过              先业务后插事件且不同事务      异常时漏记      本章小结幂等要从业务语义出发，选择稳定的事件 ID 和业务唯一键，并把最终一致性落在数据库唯一约束、事务和状态机上。Redis 可以降低冲突和数据库压力，但不能作为唯一依据。所有幂等逻辑都应针对重复、并发、重放和乱序进行测试。思考题  为什么消息 ID 不适合作为业务幂等键？  事件表为什么要和业务处理同事务？  Redis 幂等在什么情况下失效？  状态机版本如何防止旧事件覆盖新状态？  如何验证死信重放不会重复扣款？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。消息轨迹记录消息从生产、存储到消费的全过程，是定位“是否发出、何时入队、谁消费、是否重试”的关键数据。没有轨迹，消息问题往往只能靠日志和时间猜测。12.1 轨迹内容一条完整轨迹通常包含：            阶段      信息                  Produce      Topic、Tag、Key、生产组、客户端 IP、耗时、结果              Broker      存储时间、Broker、QueueId、Offset、消息大小              Consume      消费组、客户端 IP、线程、耗时、结果、重试次数              Exception      错误码、异常、失败时间      示意：10:00:00.100 producer 10.1.1.10 send success cost=8ms10:00:00.104 broker-a queue=3 offset=10001 store10:00:00.150 consumer 10.1.2.20 pull success10:00:00.170 consumer 10.1.2.20 consume success cost=15ms12.2 开启轨迹生产者：DefaultMQProducer producer = new DefaultMQProducer(        "order-producer-group", true);producer.setNamesrvAddr("rocketmq-namesrv:9876");producer.start();消费者 API 随版本差异较大，常见方式是在构造函数或 DefaultMQPushConsumerImpl 中启用轨迹开关。使用前应确认客户端版本对应 API，避免复制不同版本的示例。开启轨迹会带来额外消息和磁盘开销，生产环境应评估采样率与保留周期。12.3 轨迹 Topic轨迹默认写入系统 Topic，常见名称类似：RMQ_SYS_TRACE_TOPIC治理要点：  控制保留时间；  监控轨迹 Topic 磁盘；  不让业务 Topic 与轨迹 Topic 互相抢占关键磁盘；  高吞吐系统可采样；  关键链路全量开启；  将轨迹导出到日志或观测平台。12.4 查询方式按消息 Key 查询：Key: O202608250001推荐消息契约中携带：message key = orderNouser property traceId = 7f0c...user property eventId = 01J8...这样可以把 RocketMQ 轨迹、应用日志和链路追踪串起来：traceId  -&gt; gateway log  -&gt; order service log  -&gt; RocketMQ message  -&gt; consumer log  -&gt; inventory service log12.5 问题定位消息未到达 Broker检查：  生产者是否调用成功；  SendStatus 是否为 OK；  Topic 和环境是否正确；  网络是否超时；  ACL 是否通过；  本地事件表是否有记录。Broker 有消息但未消费检查：  消费组是否在线；  订阅关系是否一致；  Tag 过滤是否排除；  队列是否分配；  消费位点是否落后；  是否处于重试挂起。已拉取但业务未生效检查：  消费结果；  消费耗时和异常；  业务事务是否提交；  幂等是否提前返回；  下游是否失败；  是否死信。12.6 采样设计            链路      建议                  支付、订单      全量              用户行为      采样              日志类事件      可关闭或低采样              异常消息      强制全量              灰度服务      全量      示例规则：boolean sample = isCriticalEvent(event) || random.nextInt(100) &lt; 10;异常和重试消息应始终保留轨迹，否则最需要定位的时刻反而缺数据。12.7 安全与合规轨迹可能包含业务标识、账号、手机号或错误详情：  敏感字段脱敏；  不把完整报文无限制写入轨迹；  控制查询权限；  设置保留周期；  记录轨迹查询审计；  导出外部系统时继续执行访问控制。12.8 常见问题            问题      排查                  轨迹为空      客户端未开启、Broker 不支持、权限不足              只有生产没有消费      消费组、订阅、位点、过滤问题              只有拉取没有结果      消费线程异常或进程退出              查询不到 Key      生产未设置或时间范围错误              轨迹延迟      轨迹 Topic 积压或查询系统延迟              磁盘增长快      全量开启且保留过长      本章小结消息轨迹把生产、存储、拉取、消费和异常串成一条可查询的时间线。开启前要评估开销，开启后要控制敏感信息、采样率、保留周期和查询权限。定位问题时，用同一业务键和 traceId 贯穿 RocketMQ 与应用日志，效率最高。思考题  轨迹能证明哪些“没有发生”的事实？  为什么异常消息应强制保留轨迹？  轨迹 Topic 的磁盘如何治理？  traceId 和消息 Key 如何配合？  轨迹中哪些字段需要脱敏？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。重试与死信是消费链路的最后防线。重试解决临时故障，死信收集无法自动恢复的消息。设计目标不是无限重试，而是在延迟、吞吐、数据安全和人工介入之间取得平衡。11.1 消费重试流程集群模式下，消费失败的消息进入重试队列：Consumer  -&gt; consume fail  -&gt; RECONSUME_LATER  -&gt; retry topic: %RETRY%consumer-group  -&gt; delay by retry times  -&gt; retry consume  -&gt; final fail  -&gt; dead letter topic: %DLQ%consumer-group重试次数由消费组配置控制。超过上限后进入死信队列，具体默认值和级别与客户端、Broker 版本相关，应以实际版本配置为准。11.2 可重试与不可重试            异常      建议                  数据库连接超时      重试              下游服务 503      重试              网络抖动      重试              参数格式错误      记录后确认              业务状态不允许      记录后确认              权限不足      人工处理              反序列化失败      死信治理      示例：try {    handle(msg);    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;} catch (BusinessRejectException e) {    deadLetterService.save(msg, e);    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;} catch (TemporaryException e) {    return ConsumeConcurrentlyStatus.RECONSUME_LATER;} catch (Exception e) {    deadLetterService.save(msg, e);    return ConsumeConcurrentlyStatus.RECONSUME_LATER;}不可修复异常直接进入死信或治理表，可以避免集群被脏消息拖垮。11.3 重试延迟重试延迟随次数增长，常见趋势：10s -&gt; 30s -&gt; 1m -&gt; 2m -&gt; ... -&gt; hours设计原则：  首次重试不要过短，避免故障放大；  后续延迟指数增长；  设置最大重试次数；  核心业务保留人工处理入口；  对同一事件的重试做并发控制；  监控重试年龄。11.4 死信队列死信 Topic 命名通常为：%DLQ%order-consumer-group死信不是垃圾箱，而是待处理任务池。治理动作包括：  查看原消息、异常和堆栈；  修复代码或配置；  修复下游数据；  校验业务状态；  选择重放或放弃；  记录处理结论；  沉淀告警规则。建议保存结构化治理记录：{  "messageId": "msg-id",  "topic": "OrderTopic",  "consumerGroup": "order-consumer-group",  "retryTimes": 16,  "firstFailureAt": "2026-08-25T10:00:00+08:00",  "lastError": "InventoryService 503",  "action": "REPLAY",  "operator": "ops@example.com"}11.5 重放策略重放前必须确认：  消费逻辑已修复；  消息体可解析；  下游容量足够；  幂等逻辑有效；  不会覆盖更新的业务状态；  顺序消息不会破坏时序；  批量重放有限速。安全流程：导出死信  -&gt; 人工或自动校验  -&gt; 灰度小批量重放  -&gt; 对比业务结果  -&gt; 分批处理剩余  -&gt; 记录处理结论11.6 幂等与重试重试天然带来重复执行：consumer -&gt; deduct inventory successconsumer -&gt; commit offset failbroker   -&gt; redeliver message处理方式：@Transactionalpublic void handle(OrderEvent event) {    if (processedEventRepository.insertIfAbsent(event.eventId()) == 0) {        return;    }    inventoryService.reserve(event.orderNo());}同时为业务动作设计唯一键或状态机条件更新，避免“事件表唯一但业务重复执行”。11.7 监控指标consumer_retry_totalconsumer_retry_delay_secondsconsumer_retry_activedead_letter_totaldead_letter_oldest_age_secondsdead_letter_unhandled_countmessage_consume_age_secondsbusiness_reject_total告警建议：  重试率突增；  单一错误类型集中出现；  死信持续增长；  死信未处理时间超过 SLA；  重试队列消息年龄过高；  消费成功率下降。11.8 常见问题            问题      原因                  消息一直重试      异常未分类、下游持续失败              死信快速增加      代码缺陷、消息格式变化、权限问题              重放重复扣款      幂等缺失              找不到重试 Topic      消费模式、版本或权限问题              顺序消息卡住      有序消费挂起未处理              死信处理后被覆盖      状态机缺少版本      本章小结重试适合处理临时故障，死信负责承接无法自动恢复的消息。消费逻辑必须区分可重试与不可重试异常，设置有限重试和治理流程，并通过幂等、状态机、监控和审计保证重放安全。不要把死信当成终点，它是事件治理的起点。思考题  为什么参数错误不适合无限重试？  死信队列和业务治理表如何配合？  重放前必须验证哪些条件？  重试为什么会放大下游故障？  死信未处理时间为什么比死信数量更适合告警？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。事务消息解决“本地数据库事务”和“消息发送”之间的原子性问题：先写本地事务，再提交消息；如果本地事务成功但消息提交失败，通过回查补齐状态。它不是分布式事务协议，也不是 XA 事务，而是基于最终一致的事件发送机制。10.1 问题背景常见错误写法：begin transaction  insert order  send messagecommit消息发送成功后数据库回滚，会产生“订单不存在但事件已发出”的脏事件。数据库提交成功后进程崩溃，则可能漏发事件。正确思路：half message  -&gt; execute local transaction  -&gt; commit or rollback message10.2 核心流程Producer                Broker                Consumer  |--- half message ---&gt;  |  |&lt;-- half ok ---------- |  |                       |  | execute local tx      |  | commit / rollback     |  |--- commit ----------&gt; |--- real message ---&gt; |  |                       |  |&lt;------ checkback ---- |  |--- commit/rollback -&gt; |状态：            状态      含义                  COMMIT_MESSAGE      半消息转为真实消息              ROLLBACK_MESSAGE      删除半消息，不投递              UNKNOW      稍后回查      10.3 生产者实现public class OrderTransactionListener implements TransactionListener {    private final OrderService orderService;    private final EventRecordRepository eventRecordRepository;    @Override    public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {        OrderCreateCommand command = (OrderCreateCommand) arg;        try {            orderService.createWithEvent(command, msg.getTransactionId());            return LocalTransactionState.COMMIT_MESSAGE;        } catch (Exception e) {            log.error("local transaction failed, orderNo={}", command.orderNo(), e);            return LocalTransactionState.ROLLBACK_MESSAGE;        }    }    @Override    public LocalTransactionState checkLocalTransaction(MessageExt msg) {        String transactionId = msg.getTransactionId();        return eventRecordRepository.findByTransactionId(transactionId)                .map(record -&gt; switch (record.getStatus()) {                    case COMMITTED -&gt; LocalTransactionState.COMMIT_MESSAGE;                    case ROLLED_BACK -&gt; LocalTransactionState.ROLLBACK_MESSAGE;                    case PENDING -&gt; LocalTransactionState.UNKNOW;                })                .orElse(LocalTransactionState.UNKNOW);    }}发送：TransactionMQProducer producer = new TransactionMQProducer("order-tx-producer");producer.setNamesrvAddr("rocketmq-namesrv:9876");producer.setTransactionListener(new OrderTransactionListener(orderService, repository));producer.start();Message message = new Message("OrderTransactionTopic", "OrderCreated",        event(command).getBytes(StandardCharsets.UTF_8));TransactionSendResult result = producer.sendMessageInTransaction(message, command);10.4 本地事务表事务消息仍推荐与本地事件表配合：CREATE TABLE outbox_event (  id BIGINT PRIMARY KEY AUTO_INCREMENT,  event_id VARCHAR(64) NOT NULL,  transaction_id VARCHAR(64) NOT NULL,  aggregate_id VARCHAR(64) NOT NULL,  event_type VARCHAR(64) NOT NULL,  status VARCHAR(20) NOT NULL,  payload JSON NOT NULL,  created_at DATETIME(6) NOT NULL,  updated_at DATETIME(6) NOT NULL,  UNIQUE KEY uk_event_id (event_id),  UNIQUE KEY uk_transaction_id (transaction_id),  KEY idx_status_time (status, created_at));本地事务内：INSERT INTO orders(...);INSERT INTO outbox_event(...);回查时以 outbox_event 为准，而不是根据内存对象或不确定的日志判断。10.5 回查设计回查必须满足：  幂等；  可持久查询；  返回确定状态；  不依赖已经丢失的内存上下文；  有超时和最大回查限制；  对异常返回 UNKNOW；  状态最终落库。推荐回查逻辑：query outbox by transactionId  found COMMITTED    -&gt; COMMIT_MESSAGE  found ROLLED_BACK  -&gt; ROLLBACK_MESSAGE  found PENDING      -&gt; UNKNOW  not found          -&gt; check timeout      before timeout -&gt; UNKNOW      after timeout  -&gt; ROLLBACK_MESSAGE 或人工治理10.6 消费端语义事务消息只约束生产端提交关系，不保证消费端与下游数据库强一致：Broker -&gt; Consumer -&gt; downstream DB消费端仍需要：  幂等；  重试；  死信治理；  对账；  业务状态机；  补偿任务。如果消费失败，生产端事务不会自动回滚。不要把事务消息当成同步分布式事务。10.7 与本地消息表对比            方案      优点      限制                  RocketMQ 事务消息      有回查机制，减少轮询      依赖客户端和 Broker 能力              本地消息表      简单直观，易审计      需要定时扫描和重发              Outbox + CDC      解耦清晰      引入 CDC 组件      中大型系统可以组合使用：事务消息负责即时提交，本地表负责审计和补偿。10.8 生产注意事项  生产者实例与监听器正确绑定；  回查接口响应要快；  回查逻辑必须有持久状态；  UNKNOW 不能无限返回；  记录 half message ID、transactionId 和业务单号；  监控半消息数量和回查次数；  升级客户端前验证事务 API 兼容性；  生产环境演练进程崩溃和主备切换。10.9 常见错误            错误      后果                  本地事务内存判断      重启后无法回查              捕获异常后返回 COMMIT      本地失败但消息投递              消费失败期待生产事务回滚      语义理解错误              回查无超时      半消息长期悬挂              未记录 transactionId      无法定位事件              未做幂等      补发导致重复消费      本章小结事务消息通过半消息、本地事务和回查机制，降低数据库提交与消息发送不一致的概率。它提供的是生产端最终一致，不等于全局分布式事务。可靠的落地关键是本地事务表、确定性回查、幂等消费和完善的监控补偿。思考题  半消息为什么对消费者不可见？  回查为什么必须查询持久化状态？  消费失败时生产端事务是否会回滚？  事务消息和本地消息表如何组合？  半消息数量持续增长说明什么问题？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。延迟消息用于“现在提交，未来某个时间触发”的场景，例如订单超时关闭、预约提醒、延迟重试和冷却期控制。RocketMQ 历史上提供固定级别延迟，5.x 引入任意时间延迟能力，具体实现和限制应以所使用版本文档为准。9.1 典型场景            场景      延迟                  未支付订单关闭      30 分钟              支付成功后发放券      5 分钟              失败任务重试      指数退避              会议提醒      固定时间              风控冷却      秒到小时              数据归档触发      天级      延迟消息比定时扫表更适合离散到期时间的业务，但到期精度通常受调度周期、集群负载和消费者处理能力影响。9.2 固定级别延迟RocketMQ 4.x 常见延迟级别：1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2hJava 示例：Message message = new Message("OrderTimeoutTopic", "OrderTimeout",        timeoutEvent(orderNo).getBytes(StandardCharsets.UTF_8));message.setDelayTimeLevel(16); // 30mproducer.send(message);如果业务需要 25 分钟，只能选择接近的级别，例如 30 分钟，或在消费端再判断实际到期时间。9.3 5.x 定时消息RocketMQ 5.x 支持按时间戳设置定时消息：Message message = new Message("AppointmentTopic", "Remind",        remindEvent(appointmentId).getBytes(StandardCharsets.UTF_8));message.setDeliverTimeMs(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(30));producer.send(message);注意事项：  使用 Broker 和客户端都支持的版本；  确认 Topic 的定时消息能力已开启；  了解最大可延迟时间；  了解精度和调度周期；  避免瞬时大量相同到期时间造成消费洪峰；  集群升级时验证存量定时消息兼容性。9.4 到期处理消费端不能假设消息一定准时：long now = System.currentTimeMillis();long deliverAt = msg.getDeliverTimeMs();if (deliverAt &gt; now) {    log.warn("timer message arrived early, waitMs={}", deliverAt - now);    return ConsumeConcurrentlyStatus.RECONSUME_LATER;}if (now - deliverAt &gt; TimeUnit.MINUTES.toMillis(5)) {    metric.lateTimeout();}processTimeout(msg);业务执行前应再次判断状态：UPDATE ordersSET status = 'CLOSED', close_reason = 'TIMEOUT'WHERE order_no = ? AND status = 'WAIT_PAY';如果更新行数为 0，说明订单已支付或已关闭，应记录日志并确认消费。9.5 幂等与补偿延迟消息可能重复投递，也可能因迁移和重放再次出现：  以订单号或任务 ID 做幂等键；  状态机只允许合法转换；  记录任务处理结果；  定时对账未关闭订单；  人工处理死信；  对重复到期保留审计。补偿任务示例：SELECT order_noFROM ordersWHERE status = 'WAIT_PAY'  AND created_at &lt; NOW() - INTERVAL 35 MINUTELIMIT 1000;9.6 设计模式固定超时create order -&gt; send 30m delay -&gt; close if WAIT_PAY取消超时下单 -&gt; 延迟关单支付 -&gt; 状态变更为 PAID到期 -&gt; 关单条件失败，不执行如果业务支持显式取消，需要保证取消事件和到期事件不会互相覆盖，通常以数据库状态机为最终裁决。指数退避retry delay = base * 2^attemptdelay = min(delay, maxDelay)attempt = attempt + 1每次消费时计算下一次延迟，并记录尝试次数。9.7 容量与洪峰大量任务在同一秒到期会产生集中消费：10:00:00  100,000 reminders优化方式：  创建时间随机化；  提醒时间加随机抖动；  拆分 Topic 和消费组；  控制消费线程；  下游限流排队；  预估队列数和实例数；  提前压测。9.8 版本与迁移迁移建议：  固定延迟与定时消息分 Topic 管理；  新旧生产者灰度切换；  验证 Broker 支持能力和容量；  对比消息轨迹和到期时间；  保留补偿扫描；  回滚方案保持旧路径可用。不要只改客户端 API 就完成迁移，Broker 端能力和运维策略同样关键。9.9 常见故障            现象      排查                  消息不到期      版本不支持、延迟时间超出限制              全部延迟很久      定时调度积压、消费积压              提前消费      版本兼容、时间解析错误              大量重复      重试、重放或补偿并发              到期洪峰      相同到期时间集中              状态错误      未做状态机条件更新      本章小结延迟消息把未来的触发点交给消息系统，减少扫表和轮询。4.x 以固定级别为主，5.x 提供更强的定时能力，但都必须确认版本限制、到期精度、容量和兼容性。业务侧仍要依靠状态机、幂等和补偿对账保证最终正确。思考题  延迟消息为什么不能保证精确到毫秒触发？  固定级别延迟如何近似 25 分钟？  到期后为什么还要检查订单状态？  相同到期时间为什么会造成洪峰？  延迟消息迁移时为什么要验证 Broker 能力？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。顺序消息保证同一个分区键内的消息按发送顺序消费，不保证所有消息全局有序。最常见的错误是把全局顺序当成默认能力，或在顺序消费中混入并发处理，导致业务以为有序而实际无序。8.1 局部顺序与全局顺序局部顺序：Order O1001 -&gt; Queue 0 -&gt; O1001-create, O1001-paid, O1001-shippedOrder O1002 -&gt; Queue 1 -&gt; O1002-create, O1002-paid, O1002-shipped全局顺序：All messages -&gt; Queue 0            类型      队列数      吞吐      适用                  局部顺序      多队列      较高      订单、账户、库存              全局顺序      1 队列      低      强全局时序场景      大多数业务只需要局部顺序。使用一个队列追求全局顺序，会同时牺牲吞吐和可用性。8.2 发送顺序消息使用 MessageQueueSelector 把相同业务键路由到同一队列：String orderNo = "O202608250001";Message created = new Message("OrderSequentialTopic", "Created",        event(orderNo, "CREATED"));Message paid = new Message("OrderSequentialTopic", "Paid",        event(orderNo, "PAID"));producer.send(created, (queues, msg, arg) -&gt; {    int index = Math.floorMod(arg.hashCode(), queues.size());    return queues.get(index);}, orderNo);producer.send(paid, (queues, msg, arg) -&gt; {    int index = Math.floorMod(arg.hashCode(), queues.size());    return queues.get(index);}, orderNo);注意：队列选择逻辑必须稳定，发送重试时也应尽量保持相同队列。8.3 顺序消费DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("order-seq-consumer");consumer.subscribe("OrderSequentialTopic", "*");consumer.registerMessageListener((MessageListenerOrderly) (msgs, context) -&gt; {    try {        for (MessageExt msg : msgs) {            handle(msg);        }        return ConsumeOrderlyStatus.SUCCESS;    } catch (Exception e) {        context.setSuspendCurrentQueueTimeMillis(1000);        return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;    }});如果使用 MessageListenerConcurrently，即使发送端按队列写入，消费端仍可能并发乱序。8.4 顺序边界顺序范围由业务键决定：            场景      排序键                  订单状态      orderNo              账户流水      accountId              商品库存      skuId              用户消息      userId              设备指令      deviceId      不要随意使用随机数或请求 ID 作为排序键。排序键必须与业务状态归属一致。8.5 重试策略顺序消费不能随意跳过失败消息，否则后续消息会先被处理：Queue: A1(success) -&gt; A2(fail) -&gt; A3挂起等待 -&gt; retry A2 -&gt; success -&gt; consume A3推荐策略：  设置较短消费超时；  设置有限重试次数；  达到阈值后告警；  可人工处理失败消息；  处理完成后恢复队列；  对不可修复消息记录证据后再跳过。无限挂起会造成队列积压，并影响同一队列内其他业务键的消息。8.6 扩缩容影响队列数或消费者数变化会影响队列分配：扩容前：8 queues -&gt; 2 consumers，每个消费者 4 queues扩容后：8 queues -&gt; 4 consumers，每个消费者 2 queues对单个业务键而言，写入队列通常仍由选择器决定；但重平衡期间可能出现短暂消费暂停。对顺序性要求极高的场景，扩缩容要安排在低峰期。8.7 异常场景            问题      原因                  同一订单乱序      选择器不一致、发送重试换队列、使用并发消费              消费卡住      有序监听器持续挂起              队列积压      单 key 热点或消费异常              重平衡后抖动      消费者变化导致队列重新分配              全局吞吐低      只有一个队列      排查顺序：确认业务键  -&gt; 查看消息实际 QueueId  -&gt; 检查 MessageQueueSelector  -&gt; 检查监听器类型  -&gt; 查看消费重试和挂起时间8.8 项目实践推荐流程：  在需求中明确是否真的需要顺序；  定义排序键和状态机；  生产端按排序键选队列；  消费端使用有序监听器；  幂等条件使用“事件 ID + 状态版本”；  非核心逻辑异步旁路处理；  对失败消息建立治理入口；  监控队列积压和消息年龄。本章小结顺序消息是“相同排序键、相同队列、顺序消费”三者共同成立的结果。业务上优先采用局部顺序，并通过稳定队列选择器、有序监听器、有限重试和状态机校验保证正确性。顺序会降低吞吐和可用弹性，应该只用在确有业务必要的地方。思考题  局部顺序和全局顺序的区别是什么？  为什么请求 ID 通常不适合作为排序键？  顺序消费失败为什么不能直接跳过？  扩消费者数量对顺序性有什么影响？  如何证明一次乱序问题发生在生产端还是消费端？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。普通消息是最常用的消息模型：生产者把消息发送到某个 Topic 的一个队列，消费者按消费组拉取并处理。它适合事件通知、异步解耦、削峰填谷，不承诺同一业务 key 的全局顺序。7.1 发送流程Producer  -&gt; 从 NameServer 获取 Topic 路由  -&gt; 选择 Broker 和 Queue  -&gt; 构造消息  -&gt; 写入 Broker  -&gt; 返回 SendResult完整发送示例：DefaultMQProducer producer = new DefaultMQProducer("order-producer-group");producer.setNamesrvAddr("rocketmq-namesrv:9876");producer.setSendMsgTimeout(3000);producer.setRetryTimesWhenSendFailed(2);producer.start();try {    Message message = new Message(            "OrderTopic",            "OrderCreated",            "O202608250001".getBytes(StandardCharsets.UTF_8));    message.setKeys("O202608250001");    message.putUserProperty("source", "order-service");    SendResult result = producer.send(message);    System.out.printf("status=%s, msgId=%s, queue=%s%n",            result.getSendStatus(),            result.getMsgId(),            result.getMessageQueue());} finally {    producer.shutdown();}setKeys 不影响路由，但会写入索引，后续可按业务键查询消息。7.2 消息体设计推荐使用明确版本化的 JSON 或 Avro：{  "eventId": "01J8ZC9Q7M6Q",  "eventType": "OrderCreated",  "version": 1,  "occurredAt": "2026-08-25T10:00:00+08:00",  "data": {    "orderNo": "O202608250001",    "userId": "U10001",    "amount": 199.00  }}规范：  必须有全局唯一 eventId；  必须有事件类型和版本；  时间带时区；  消息体只放必要字段；  大对象存对象存储，消息只放引用；  不依赖线程上下文自动生成隐式字段。7.3 Tag 与属性Tag 用于订阅过滤：consumer.subscribe("OrderTopic", "OrderCreated || OrderPaid");User Property 用于复杂 SQL 过滤：message.putUserProperty("region", "cn-east");message.putUserProperty("level", "vip");consumer.subscribe("OrderTopic", MessageSelector.bySql("region = 'cn-east' AND level = 'vip'"));选择建议：            方式      特点                  Tag      简单、常用、性能好              SQL92      表达能力强，需要 Broker 开启支持              业务端过滤      灵活但会消耗消费带宽      不要把核心业务逻辑建立在过度复杂的过滤表达式上，复杂规则更适合由业务服务判断。7.4 同步、异步和单向发送            模式      是否等待结果      适用                  sync      是      重要业务事件              async      回调返回      链路长、并发高的场景              oneway      否      日志、指标等可容忍丢失      异步发送：producer.send(message, new SendCallback() {    @Override    public void onSuccess(SendResult result) {        metric.success();    }    @Override    public void onException(Throwable e) {        log.error("send failed, key={}", "O202608250001", e);        metric.failure();    }});异步发送失败必须落盘、重投或交给补偿任务处理，不能只打印日志。7.5 发送结果SendStatus 常见值：            状态      含义      处理                  SEND_OK      发送成功      继续业务              FLUSH_DISK_TIMEOUT      刷盘超时      根据刷盘策略评估风险              FLUSH_SLAVE_TIMEOUT      从节点同步超时      关注副本状态              SLAVE_NOT_AVAILABLE      从节点不可用      告警并检查集群      发送方不能只判断是否抛异常，还应记录 SendStatus 和消息键，便于对账。7.6 消费普通消息DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("order-consumer-group");consumer.setNamesrvAddr("rocketmq-namesrv:9876");consumer.subscribe("OrderTopic", "OrderCreated");consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -&gt; {    for (MessageExt msg : msgs) {        handle(msg);    }    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;});consumer.start();处理建议：  解析失败记录后确认，避免无限重试；  临时异常返回重试；  幂等键使用 eventId；  外部调用设置超时；  不在消费线程里做长时间阻塞；  消费结果必须可观测。7.7 丢失与重复普通消息通常提供至少一次投递语义，生产端和消费端都可能产生重复。降低丢失风险：业务落库  -&gt; 发送消息  -&gt; 根据发送结果更新事件状态  -&gt; 定时补偿未确认事件关键点：  生产端保存事件发送状态；  重要消息使用同步发送；  Broker 使用合适的刷盘和复制策略；  消费成功后业务确认；  建立消息对账；  消费端幂等。7.8 性能实践            项目      建议                  生产者      复用实例，避免每次创建              消息体      控制大小，大文件走对象存储              队列数      与消费并行度匹配              批量      只在业务允许时使用              超时      覆盖网络和 Broker 写入时间              重试      与业务可重复性匹配      生产者实例启动成本较高，应在应用生命周期内复用，并在关闭时调用 shutdown()。7.9 常见故障            现象      排查                  发送超时      NameServer、Broker 地址、网络、磁盘、队列热点              Topic 不存在      未创建、权限不足、环境错误              消息查不到      未设置 Key、时间范围错、已过期              消费乱序      使用了并发消费，普通消息本不保序              消息重复      发送重试或消费重试              消息丢失      生产未确认、存储策略、消费跳过      本章小结普通消息的核心是可靠发送、明确消息契约、合理使用 Tag 和属性、消费端幂等。它不保证全局顺序，但胜于通用性和吞吐能力。生产环境要把发送状态、消费结果、消息轨迹和对账串联起来，才能有效控制丢失与重复。思考题  同步、异步、单向发送分别适合什么业务？  为什么消息必须包含 eventId 和版本？  SendStatus 为什么要持久化或打点？  普通消息出现乱序是否是缺陷？  如何用补偿任务降低生产端消息丢失风险？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。管理控制台是观察集群、Topic、消费组和消息的第一入口。它适合日常巡检、快速定位和低风险运维；涉及位点重置、Topic 删除、Broker 下线等操作时，必须先确认影响范围，再按变更流程执行。6.1 控制台能力RocketMQ Dashboard 常用功能：            模块      典型用途                  Cluster      查看 Broker、队列、磁盘、流量              Topic      创建、更新、路由、状态、发送消息              Consumer      查看消费组、位点、延迟、客户端连接              Message      按 Key、Topic、Message ID 查询消息              Message Trace      查看消息轨迹              Ops      查看控制台配置      控制台版本不同，功能入口和指标名称可能有差异。生产环境应以实际部署版本的页面说明和官方文档为准。6.2 安装与连接使用 Docker 快速启动：docker run -d \  --name rocketmq-dashboard \  -p 8080:8080 \  -e "JAVA_OPTS=-Drocketmq.namesrv.addr=rocketmq-namesrv:9876" \  apache/rocketmq-dashboard:latest建议生产环境固定镜像版本，不建议直接使用 latest。如果 Dashboard 与 NameServer 存在网络隔离，需要先确认端口连通：telnet rocketmq-namesrv 98766.3 集群视图Cluster 页面重点关注：  Broker 是否全部在线；  主从角色和副本状态；  磁盘使用率；  今日发送和消费流量；  队列分布是否均匀；  Broker 版本和地址是否符合预期。示例：broker-a-master    192.168.1.11:10911  disk 62%broker-a-replica   192.168.1.12:10911  disk 61%broker-b-master    192.168.1.13:10911  disk 75%broker-b-replica   192.168.1.14:10911  disk 74%当某个 Broker 磁盘明显更高时，需要检查 Topic 队列分布、写入流量和历史数据保留策略。6.4 Topic 管理查看 Topic 状态：Topic: OrderTopicBroker        Queue              MinOffset   MaxOffset   LastUpdatebroker-a      0                  1000        5000        2026-08-25 10:00:00broker-a      1                  1000        4800        2026-08-25 10:00:00broker-b      0                  900         5100        2026-08-25 10:00:00broker-b      1                  900         4900        2026-08-25 10:00:00创建 Topic 时要明确：            配置      建议                  queueNum      按消费并行度和流量评估，避免一次性过大              perm      生产通常只授予必要读写权限              topicType      区分普通、顺序、事务等场景      更新队列数一般可以增加，减少队列可能影响历史消息消费和顺序性。生产环境应先确认消费进度是否已到达末尾。6.5 消费组管理Consumer 页面可以查看：  消费组订阅关系；  每个队列的 Commit Offset；  Broker Offset；  延迟量；  客户端连接信息；  消费状态。延迟计算：Delayed = Broker Max Offset - Consumer Commit Offset排查消费延迟：查看客户端是否在线  -&gt; 查看订阅 Topic 和 Tag 是否正确  -&gt; 查看队列是否有消费者  -&gt; 查看消费耗时  -&gt; 查看重试和死信不要在未确认业务含义时直接重置位点。重置到较早位置会重复消费，重置到最新位置会跳过未消费消息。6.6 消息查询常用查询方式：            方式      适用场景                  Message ID      精确定位单条消息              Message Key      按业务键追踪              Topic + 时间范围      辅助缩小范围      示例业务 Key：orderId=O202608250001userId=U10001traceId=7f0c...查询后可以查看：  消息体；  Tag；  Key；  属性；  存储时间；  重试次数；  所在队列和位点。如果消息按 Key 查不到，可能是生产者没有设置 Key，或查询时间范围不正确。6.7 权限与安全生产控制台建议：  仅暴露在内网或运维网络；  接入统一认证和授权；  按团队隔离 Topic 权限；  高危操作开启审批；  记录操作审计；  与集群 ACL 账号联动；  不在公共网络明文暴露。最小权限示例：只读巡检账号：查询集群、Topic、消息业务运维账号：管理指定业务 Topic平台管理员：全量管理，但操作需审批6.8 常见问题            问题      排查                  集群为空      Dashboard 连接 NameServer 地址错误、网络不通              Topic 查不到      权限不足、环境不一致、Topic 未创建              消费组无数据      消费者未启动、订阅错误、分组错误              消息查不到      Key 未设置、时间范围错误、消息过期              页面能看但不能操作      ACL 权限或控制台只读配置              磁盘告警      检查保留时间、写入量、磁盘容量      本章小结管理控制台用于集群巡检、Topic 与消费组治理、消息查询和轨迹定位。生产使用时必须固定版本、控制网络暴露范围、接入认证授权，并对位点重置和 Topic 变更保持变更管理纪律。看懂数据的关键是把 Broker Offset、消费位点和消息轨迹串联起来。思考题  为什么生产环境不建议使用 latest 控制台镜像？  消费延迟等于什么两个位点之差？  重置消费位点有哪些风险？  Topic 队列数减少可能影响什么？  如何为控制台设计只读和高危操作权限？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。消费者决定消息最终是否真正被业务处理。核心原则：业务成功后确认，失败有限重试，异常进入死信，消费幂等，处理有超时，指标可观测。5.1 初始化消费者DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("order-consumer-group");consumer.setNamesrvAddr("rocketmq-namesrv:9876");consumer.subscribe("OrderTopic", "OrderCreated || OrderPaid");consumer.setConsumeThreadMin(4);consumer.setConsumeThreadMax(8);consumer.setConsumeTimeout(15);consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -&gt; {    for (MessageExt msg : msgs) {        handle(msg);    }    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;});consumer.start();关闭：consumer.shutdown();消费组命名应包含：业务域-服务-用途order-inventory-consumer5.2 集群消费与广播消费            模式      行为                  CLUSTERING      同组分摊队列              BROADCASTING      每个实例消费全量      集群消费：  适合业务事件；  位点保存在 Broker；  支持重试和死信；  实例扩容提升并行度。广播消费：  适合本地缓存刷新；  每个实例独立进度；  新实例可能从最新或配置位点开始；  通常不使用重试队列语义；  消息丢失影响本地副本。5.3 Push 与 PullRocketMQ Java 客户端常见 Push 消费本质是长轮询加内部拉取。Push：  API 简单；  自动管理拉取和位点；  常用于业务消费者。Pull：  自己控制拉取节奏；  适合批处理和特殊回放；  位点管理更复杂；  需要处理队列分配和异常。一般业务优先 Push，只有特殊回放、大批量迁移才考虑 Pull。5.4 消费监听器并发消费：(MessageListenerConcurrently) (msgs, context) -&gt; {    try {        handle(msgs);        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;    } catch (BusinessRejectException e) {        log.warn("business reject, key={}", e.getKey());        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;    } catch (Exception e) {        return ConsumeConcurrentlyStatus.RECONSUME_LATER;    }}顺序消费：(MessageListenerOrderly) (msgs, context) -&gt; {    try {        handle(msgs);        return ConsumeOrderlyStatus.SUCCESS;    } catch (Exception e) {        return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;    }}顺序消费挂起会阻塞当前队列，必须设置重试上限和告警。5.5 消费结果处理            场景      返回                  处理成功      CONSUME_SUCCESS              业务明确拒绝但已记录      CONSUME_SUCCESS              下游临时异常      RECONSUME_LATER              参数错误      建议记录死信并成功确认              未知异常      有限重试      不要无条件返回 RECONSUME_LATER。不可修复的消息会反复进入重试，最终仍进入死信，期间浪费资源并制造噪声。5.6 幂等消费事件：public record OrderCreatedEvent(        String eventId,        String orderNo,        String userId,        int version) {}处理：@Transactionalpublic void handle(OrderCreatedEvent event) {    if (consumedEventRepository.exists(event.eventId())) {        return;    }    inventoryService.reserve(event.orderNo());    consumedEventRepository.save(event.eventId());}兜底：  业务表唯一约束；  状态机条件更新；  乐观锁；  Redis 预判；  对账。Redis 只能优化，不能作为唯一幂等依据。5.7 消费线程与批量相关参数：            参数      说明                  consumeThreadMin      最小消费线程              consumeThreadMax      最大消费线程              consumeMessageBatchMaxSize      单次处理条数              pullBatchSize      拉取批次              consumeTimeout      消费超时      设置原则：  看下游可承受并发；  看数据库连接池；  看每条消息耗时；  看是否破坏顺序；  看消费实例数。盲目增加线程可能压垮数据库或下游服务。5.8 队列分配与扩容Topic 8 queues  Consumer A -&gt; 4 queues  Consumer B -&gt; 4 queues新增 Consumer C  A -&gt; 3  B -&gt; 3  C -&gt; 2限制：  有效消费者并行度不超过队列数；  顺序消息扩容要考虑 key 分散变化；  重平衡期间可能有短暂抖动；  消费者实例数应与队列数匹配；  扩队列后需重新分配。5.9 消费监控指标：consumer_lagconsumer_latencyconsumer_success_totalconsumer_failure_totalconsumer_retry_totaldead_letter_totalmessage_ageconsume_thread_activedownstream_latency告警：  lag 持续增长；  消费耗时 P99 超标；  重试增长；  死信增长；  消息年龄超过业务容忍；  消费线程持续满。处理积压顺序：定位慢原因  -&gt; 先降级非关键逻辑  -&gt; 提升下游容量  -&gt; 再增加消费者  -&gt; 最后评估扩队列5.10 常见问题            问题      原因                  消息不消费      Tag、位点、权限、队列不可读              重复消费      至少一次、超时重试              消费积压      处理慢、下游故障、实例不足              顺序乱      使用并发监听器或扩缩队列              消费卡住      顺序队列挂起、下游超时              死信增长      持续异常未处理              位点异常      手工重置、客户端版本或权限问题      本章小结消费者要区分集群与广播、并发与顺序，业务成功后确认，失败按可恢复性重试，不可恢复异常记录后进入死信治理。所有消费逻辑必须幂等，线程数要匹配下游容量。消费 lag、耗时、重试、死信和消息年龄是核心监控指标。思考题  Push 消费为什么仍称为拉取模型？  参数错误消息为什么不应无限重试？  顺序消费卡住时如何避免阻塞所有队列？  消费幂等为什么不能只靠 Redis？  消费积压时为什么不能先盲目扩线程？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。生产者的目标不是简单调用 send，而是在消息可靠性、延迟、顺序、幂等和故障降级之间做出明确选择。本章介绍 RocketMQ Java 客户端常用发送方式与生产实践。4.1 初始化生产者依赖：&lt;dependency&gt;    &lt;groupId&gt;org.apache.rocketmq&lt;/groupId&gt;    &lt;artifactId&gt;rocketmq-client&lt;/artifactId&gt;    &lt;version&gt;5.3.1&lt;/version&gt;&lt;/dependency&gt;传统客户端：DefaultMQProducer producer = new DefaultMQProducer("order-producer-group");producer.setNamesrvAddr("rocketmq-namesrv:9876");producer.setSendMsgTimeout(3000);producer.setRetryTimesWhenSendFailed(2);producer.start();关闭：producer.shutdown();生产者通常是单例，不要每次请求创建和销毁。4.2 构建消息Message message = new Message();message.setTopic("OrderTopic");message.setTags("OrderCreated");message.setKeys(order.orderNo());message.setBody(JsonUtils.toBytes(event));message.putUserProperty("traceId", TraceContext.currentId());message.putUserProperty("eventType", "OrderCreated");message.putUserProperty("schemaVersion", "2");字段建议：            字段      用途                  Topic      业务域              Tag      事件类型              keys      查询和业务关联              traceId      链路追踪              schemaVersion      契约版本              occurredAt      业务发生时间      消息体应使用稳定契约对象，避免暴露内部实体。4.3 同步发送SendResult result = producer.send(message);if (result.getSendStatus() != SendStatus.SEND_OK) {    throw new MessageSendException(result.getSendStatus().name());}适用：  订单事件；  支付事件；  关键审计；  不允许静默丢失的业务。必须处理：  超时；  网络异常；  Broker 拒绝；  消息过大；  本地降级策略。4.4 异步发送producer.send(message, new SendCallback() {    @Override    public void onSuccess(SendResult result) {        log.info("message sent, msgId={}, status={}", result.getMsgId(), result.getSendStatus());    }    @Override    public void onException(Throwable e) {        log.error("message send failed, orderNo={}", orderNo, e);        saveToLocalRetryQueue(orderNo);    }});适合日志、通知、指标类消息。注意：  失败不能只打印；  回调线程不宜执行重逻辑；  需要设置发送缓冲区大小；  应用关闭前等待在途请求；  高可靠业务仍建议本地 Outbox。4.5 单向发送producer.sendOneway(message);特点：  不等待响应；  不关心结果；  性能高；  可能丢失。适合：  运行指标；  非关键日志；  采样埋点。订单、支付、库存等关键消息禁止使用单向发送。4.6 顺序发送SendResult result = producer.send(message, (mqs, msg, arg) -&gt; {    long index = Math.abs((long) arg) % mqs.size();    return mqs.get((int) index);}, order.orderNo());同一个 orderId 会选择同一队列。要求：  Sharding Key 稳定；  消费端串行；  不随意扩缩队列；  生产失败重试不能改变 key；  异常消息进入重试后可能破坏严格顺序，需要业务补偿。RocketMQ 顺序是分区内顺序，不是全局顺序。4.7 发送重试同步发送可设置：producer.setRetryTimesWhenSendFailed(2);重试考虑：  Broker 短暂不可用可重试；  消息非法不应重试；  超时重试可能造成重复；  重试增加下游压力；  消费端必须幂等。更可靠的模式：业务本地事务  -&gt; 写业务表  -&gt; 写 outbox  -&gt; 后台投递 RocketMQ  -&gt; 失败重试4.8 消息大小默认单条消息大小有限制，具体默认值与版本有关。大消息策略：  精简字段；  压缩；  引用对象存储 key；  拆分批次；  使用流式通道。错误：订单事件携带完整商品详情、用户信息、日志和图片列表正确：订单事件只带 orderId、版本、关键字段消费者按需查询详情4.9 生产者监控指标：rocketmq_producer_send_totalrocketmq_producer_success_totalrocketmq_producer_failure_totalrocketmq_producer_latencyrocketmq_producer_timeout_totalrocketmq_producer_retry_totaloutbox_pending_total日志必须包含：topictagkeys / orderIdmessageIdsendStatuscostbrokerqueueIdtraceId告警：  发送失败率；  P99 发送耗时；  超时次数；  本地重试队列增长；  关键业务发送为 0。4.10 常见问题            问题      排查                  No route info      Topic 未创建或路由未同步              Send timeout      网络、Broker 压力、消息过大              Message too large      检查大小限制              Topic not exist      autoCreateTopicEnable 和权限              RemotingTooMuchRequest      发送并发或客户端压力              发送成功但消费不到      Tag、队列、消费位点、权限              重复消息      超时重试，需要幂等      本章小结生产者应根据业务可靠性选择同步、异步或单向发送。关键业务必须使用同步或 Outbox，并携带业务 key、事件版本和 traceId。顺序消息通过 Sharding Key 绑定队列，但消费端也必须串行。所有至少一次语义下的重复都可能发生，幂等是消费端必做工作。思考题  哪些消息可以使用 oneway？  同步发送超时后消息是否一定失败？  顺序消息为什么不是全局顺序？  如何设计生产端失败兜底？  生产者需要记录哪些日志字段？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。理解 RocketMQ 的核心概念，是正确设计 Topic、消费组、位点、重试和死信的前提。本章把对象模型和生产语义集中梳理。3.1 对象模型NameServer  -&gt; Broker     -&gt; Topic        -&gt; MessageQueue           -&gt; CommitLog offset           -&gt; ConsumeQueue indexConsumer Group  -&gt; Consumer instance  -&gt; MessageQueue assignment  -&gt; ConsumeOffset核心对象：            对象      说明                  NameServer      路由注册与发现              Broker      消息存储与服务节点              Topic      逻辑消息分类              MessageQueue      Topic 内并行单元              ProducerGroup      生产者逻辑分组              ConsumerGroup      消费进度和重试隔离单位              Tag      Topic 内过滤标签              Key      消息业务键，用于查询              Offset      队列内消息位点      3.2 Topic 与 MessageQueue一个 Topic 有多个队列：OrderTopic  |-- queue 0  |-- queue 1  |-- queue 2  |-- queue 3队列作用：  并行写入；  并行消费；  顺序隔离；  扩容并行度；  分配给消费组实例。读写队列数：            参数      含义                  writeQueueNums      可写入队列数              readQueueNums      可读取队列数      扩容时通常先加写队列再扩读队列，缩容相反，避免消息不可读。3.3 消费组集群模式下：Consumer Group order-service  |-- Consumer A -&gt; queue 0, queue 1  |-- Consumer B -&gt; queue 2, queue 3特点：  同组消费者分摊队列；  消费进度按组隔离；  重试和死信按组隔离；  同组逻辑应一致；  组内实例扩容上限受队列数影响。广播模式下：Consumer A 消费 queue 0-3 全量Consumer B 消费 queue 0-3 全量广播进度通常保存在消费者本地，适合本地缓存刷新等场景。3.4 消息标识每条消息常见标识：            字段      用途                  messageId      Broker 生成的消息 ID              uniqKey      客户端生成的唯一键              keys      业务 key，可多个，用于查询              tag      Topic 内过滤              shardingKey      顺序消息选择队列              transactionId      事务消息 ID      业务建议：keys = orderId / orderNotag = OrderCreated / OrderPaidproperty: eventId / traceId不要依赖 messageId 做业务幂等，应使用业务唯一键。3.5 消息过滤Tag 过滤：consumer.subscribe("OrderTopic", "OrderCreated || OrderPaid");SQL92 过滤：consumer.subscribe("OrderTopic", MessageSelector.bySql("region = 'east'"));            方式      特点                  Tag      简单，Broker 端先过滤              SQL92      表达式更强，需 Broker 开启              客户端过滤      灵活但浪费网络      过滤不能替代领域模型。如果多个事件语义差异巨大，应评估拆 Topic。3.6 消费位点位点记录消费组在队列中的进度：queue maxOffset = 1000consumer offset = 800lag = 200位点提交原则：  集群模式业务成功后提交；  失败进入重试；  不能为了跳过异常提前提交；  重置位点必须审批和备份；  位点错误可能导致漏消息或重复消费。RocketMQ 默认语义是至少一次，因此消费必须幂等。3.7 重试队列消费失败后，消息会进入消费组对应的重试队列。命名通常形如：%RETRY%order-consumer-group特点：  按消费组隔离；  有递增延迟；  达到最大重试次数进入死信；  重试次数可配置；  异常类型应区分可重试与不可重试。不可重试异常：  参数缺失；  JSON 格式错误；  业务规则明确拒绝；  版本不兼容。这类消息应进入死信并人工处理，而不是无限重试。3.8 死信队列命名通常形如：%DLQ%order-consumer-group治理要求：  监控死信数量；  查看原始消息和异常；  修复后支持重放；  无法处理要有业务闭环；  定期清理归档；  记录处理人、原因和结果。死信不是垃圾桶，而是待处理异常任务池。3.9 消息语义            语义      说明                  At most once      可能丢，不会重复              At least once      不丢，可能重复              Exactly once      端到端严格一次      RocketMQ 常规业务消费按至少一次设计。要达到业务上的“一次效果”，必须：  消息带唯一业务 ID；  消费端幂等；  数据库唯一约束；  状态机限制；  对账兜底。3.10 常见设计错误            错误      后果                  一个 Topic 混所有业务      权限、治理和过滤复杂              Topic 过细      管理成本高              消费组混用不同逻辑      位点和重试互相影响              依赖自动创建 Topic      资源失控              用 messageId 做幂等      无法表达业务语义              重置位点不当      漏消息或重复风暴              死信无人处理      业务事实丢失              队列数随意扩缩      顺序和分配异常      本章小结RocketMQ 以 Topic 和 MessageQueue 组织并行度，以 ConsumerGroup 隔离消费进度、重试和死信。消息应携带业务 key 和事件 ID，消费按至少一次设计并实现幂等。重试队列和死信队列是业务可靠性的一部分，必须有监控、重放和处理闭环。思考题  Topic、Tag 和消费组分别适合什么隔离粒度？  readQueueNums 和 writeQueueNums 扩缩容要注意什么？  消费位点提前提交会造成什么风险？  哪些异常不应该重试？  如何治理死信队列？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。本章从单机、Docker 到生产集群逐步搭建 RocketMQ 环境。学习环境可以简化部署，生产环境必须考虑多副本、磁盘、监控、安全和管理工具。2.1 版本选择常见版本：            版本      定位                  RocketMQ 4.x      传统 NameServer + Broker 架构，生产使用广泛              RocketMQ 5.x      引入 Proxy、Controller、新客户端与云原生能力      新项目建议选择当前稳定 5.x 版本，同时评估：  客户端版本兼容性；  是否使用 Proxy；  Controller 或 DLedger 高可用模式；  运维平台支持；  社区文档和问题修复情况。不要在生产中直接使用最新快照版本。2.2 下载与目录wget https://archive.apache.org/dist/rocketmq/5.3.1/rocketmq-all-5.3.1-bin-release.zipunzip rocketmq-all-5.3.1-bin-release.zipcd rocketmq-all-5.3.1-bin-release目录结构：bin/       启动脚本conf/      配置文件lib/       依赖 jarlogs/      日志目录如果下载地址失效，以 Apache RocketMQ 官方下载页为准。2.3 启动 NameServerLinux：nohup sh bin/mqnamesrv &gt; logs/namesrv.log 2&gt;&amp;1 &amp;验证：jps -lnetstat -lntp | grep 9876NameServer 默认监听 9876。学习环境可单节点，生产至少部署多个节点。2.4 启动 Brokernohup sh bin/mqbroker -n localhost:9876 \  -c conf/broker.conf \  &gt; logs/broker.log 2&gt;&amp;1 &amp;关键配置：brokerClusterName=DefaultClusterbrokerName=broker-abrokerId=0namesrvAddr=localhost:9876brokerIP1=192.168.1.10listenPort=10911storePathRootDir=/data/rocketmq/storeautoCreateTopicEnable=false验证进程：jps -ltail -f logs/broker.log2.5 命令行验证创建 Topic：sh bin/mqadmin updateTopic -n localhost:9876 \  -c DefaultCluster \  -t OrderTopic \  -r 8 \  -w 8查看 Topic：sh bin/mqadmin topicList -n localhost:9876sh bin/mqadmin topicStatus -n localhost:9876 -t OrderTopic生产消息：sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer消费消息：sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer官方示例包中的默认 Topic 和地址可能随版本变化，使用时按当前源码修改。2.6 关闭服务sh bin/mqshutdown brokersh bin/mqshutdown namesrv顺序说明：  先停应用流量；  再停 Broker；  最后停 NameServer；  生产环境按节点逐个操作；  停止前确认副本同步状态。2.7 Docker Compose示例 docker-compose.yml：services:  namesrv:    image: apache/rocketmq:5.3.1    command: sh mqnamesrv    ports:      - "9876:9876"  broker:    image: apache/rocketmq:5.3.1    command: sh mqbroker -n namesrv:9876    depends_on:      - namesrv    ports:      - "10911:10911"    volumes:      - ./broker.conf:/home/rocketmq/conf/broker.conf注意：  brokerIP1 必须是客户端可访问 IP；  数据目录要挂载；  容器内存要足够；  生产不建议单容器单副本；  网络要固定，避免路由漂移。2.8 DashboardRocketMQ Dashboard 常用于查看 Topic、消费组、消息和位点。git clone https://github.com/apache/rocketmq-dashboard.gitcd rocketmq-dashboardmvn spring-boot:run配置：rocketmq.config.namesrvAddr=localhost:9876Dashboard 功能：  Topic 管理；  消费组状态；  消息查询；  位点重置；  Broker 状态；  死信查看。生产必须开启认证和权限控制，避免误操作重置位点。2.9 生产环境部署清单1. 至少多个 NameServer2. Broker 主从或多副本3. 独立数据盘和监控盘4. RAID 或云盘性能验证5. 时钟同步6. JVM 参数固定7. 日志滚动8. 监控 exporter9. 控制台权限10. 备份和恢复演练建议 Linux 参数：ulimit -n 102400磁盘目录：/data/rocketmq/store/data/rocketmq/commitlog/data/rocketmq/consumequeue/data/rocketmq/index2.10 常见启动问题            问题      排查                  Broker 注册失败      namesrvAddr、网络、防火墙              客户端连接失败      brokerIP1 配置错误              启动内存不足      JVM 堆配置过大              Topic 不存在      autoCreateTopicEnable 或手动创建              磁盘满      保留策略和监控              进程消失      OOM、磁盘、systemd 限制              权限不足      数据目录属主      查看日志：tail -200 logs/broker.logtail -200 logs/store.logtail -200 logs/rocketmqlogs/broker.log不同发行包日志目录可能不同，以实际文件为准。本章小结学习环境可以用二进制包或 Docker 快速启动 NameServer 和 Broker，并用 mqadmin 创建 Topic 验证收发。生产环境必须关闭自动创建 Topic、配置客户端可访问的 brokerIP1、部署多副本、规划磁盘和日志，并提前部署监控与管理工具。思考题  为什么生产不建议开启 autoCreateTopicEnable？  brokerIP1 配错会造成什么问题？  单机环境和生产环境的核心差异有哪些？  RocketMQ Dashboard 需要重点控制哪些权限？  如何设计一个最小三节点测试集群？</li>
  <li>这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开，代码块保留了原书可直接运行的版本。RocketMQ 是阿里巴巴开源的分布式消息中间件，后来成为 Apache 顶级项目。它以业务消息见长，广泛用于订单事件、交易解耦、异步通知、削峰填谷、事务消息、延迟消息和流式集成。如果你已经读过 Kafka，可以把 RocketMQ 理解为另一种消息系统取舍：Kafka 更偏向高吞吐日志流和流处理生态，RocketMQ 更强调业务消息语义，例如事务消息、延迟消息、重试队列、死信队列和消息轨迹。1.1 消息系统解决什么问题假设订单服务创建订单后要做六件事：创建订单  -&gt; 扣库存  -&gt; 发优惠券  -&gt; 发短信  -&gt; 更新积分  -&gt; 同步搜索索引  -&gt; 风控审计同步调用的弊端：  任何一个下游失败都会影响下单；  下游耗时累加，接口延迟变高；  流量高峰时容易雪崩；  新增下游要修改订单服务；  失败重试和状态恢复难以统一治理。引入消息后：订单服务  -&gt; 保存订单  -&gt; 发送 OrderCreated 事件下游消费者  -&gt; 库存服务  -&gt; 营销服务  -&gt; 通知服务  -&gt; 搜索同步服务  -&gt; 风控服务消息系统的价值：            能力      说明                  解耦      生产者不需要知道所有下游              异步      主链路只做核心事务              削峰      突发流量先进入队列              重试      消费失败自动重试              死信      异常消息可隔离治理              广播      一条事件被多个消费组消费              顺序      同一 key 的消息可按顺序消费              审计      事件可作为系统事实流      1.2 RocketMQ 的核心角色RocketMQ 4.x 主要由 NameServer、Broker、Producer、Consumer 组成。flowchart LR    P[Producer] --&gt;|发送消息| B[Broker]    C[Consumer] --&gt;|拉取消息| B    NS[NameServer] -.路由发现.- P    NS -.路由发现.- C    NS -.心跳注册.- BNameServerNameServer 是轻量级注册中心，负责保存 Topic 路由信息。特点：  无状态，可集群部署；  Broker 定时注册；  客户端定时拉取路由；  相比强一致注册中心，部署更轻；  路由更新存在短暂延迟。BrokerBroker 是消息存储和服务节点，负责：  接收生产者消息；  持久化 CommitLog；  维护 ConsumeQueue；  处理消费者拉取；  管理消费位点；  处理重试和死信；  主从同步；  管理延迟消息和事务回查。Producer生产者负责发送消息。常见发送方式：            模式      说明                  同步发送      等待 Broker 确认，可靠性高              异步发送      回调处理结果，延迟低              单向发送      不等待结果，允许丢失      Consumer消费者从 Broker 拉取消息并执行业务处理。消费模式：            模式      说明                  集群消费      一个消费组分摊队列，适合业务事件              广播消费      每个消费者都消费全量，适合本地缓存刷新      1.3 Topic、Queue 与消费组RocketMQ 的逻辑模型：Topic  +-- MessageQueue 0  +-- MessageQueue 1  +-- MessageQueue 2一个 Topic 有多个 MessageQueue。生产者选择队列写入，消费者组中的实例分摊队列。消费位点每个消费组对每个队列维护一个消费位点 offset。位点表示：这个消费组已经消费到哪里重要原则：  业务处理成功后再提交位点；  消费失败会进入重试；  位点不能随意重置；  消费组隔离，不同组互不影响；  位点积压是最重要的监控指标。1.4 RocketMQ 5.x 架构变化RocketMQ 5.x 引入了 Proxy 和新的客户端架构。Client  -&gt; Proxy     -&gt; BrokerProxy 的价值：  客户端接入层标准化；  支持 gRPC 协议；  简化多语言客户端；  支持云原生部署形态；  将接入逻辑与存储逻辑分离。5.x 仍保留对 4.x Java 客户端的兼容，但新项目应评估：  客户端版本；  Proxy Local / Cluster 模式；  Controller 模式；  存算分离能力；  与现有运维工具的兼容性。1.5 RocketMQ 的消息类型普通消息无顺序要求、无定时要求的一般业务事件。顺序消息同一 Sharding Key 的消息进入同一队列，消费者对队列串行处理。典型场景：  同一订单的状态流；  同一用户的积分流水；  同一设备的指令顺序。延迟消息消息发送后延迟一段时间才可消费。典型场景：  订单 30 分钟未支付自动取消；  延迟检查任务；  定时提醒。事务消息解决“本地事务和消息发送”的一致性问题。典型流程：发送 half 消息  -&gt; 执行本地事务  -&gt; 提交或回滚消息  -&gt; Broker 回查未知状态事务消息不是分布式事务的万能方案，它保证的是“本地事务成功后消息最终可见”。1.6 存储模型概览RocketMQ 的核心存储文件：            文件      作用                  CommitLog      所有 Topic 消息顺序写入的主文件              ConsumeQueue      每个队列的逻辑索引              IndexFile      消息 Key 或时间查询索引              Checkpoint      刷盘和恢复位点              abort      异常停机标记      写入路径：Producer 消息  -&gt; Broker 接收  -&gt; 写 CommitLog  -&gt; 构建 ConsumeQueue  -&gt; 刷盘  -&gt; 主从复制所有消息追加到 CommitLog，可以让磁盘写入保持顺序 IO，这是 RocketMQ 高吞吐的重要基础。1.7 和 Kafka 的对比            维度      Kafka      RocketMQ                  定位      日志流、流处理生态      业务消息中间件              存储      Partition 分文件日志      CommitLog + ConsumeQueue              事务      流事务语义      本地事务消息              延迟消息      需自行实现      原生支持              重试队列      消费者自行处理      原生支持              死信队列      需自行实现      原生支持              消息轨迹      依赖生态      原生能力              流处理      Kafka Streams / Flink 生态强      相对偏业务集成      选择建议：  日志采集、流计算、高吞吐管道优先考虑 Kafka；  订单、交易、营销等业务事件优先考虑 RocketMQ；  两者也可以共存，不要强行用一个系统覆盖所有场景；  迁移时要评估语义、运维、客户端生态和团队经验。1.8 生产使用的基本要求一个生产级 RocketMQ 集群至少要有：  多个 NameServer；  Broker 主从或多副本；  监控消息积压；  监控发送失败率；  监控消费失败和死信；  消息发送幂等；  消费幂等；  死信人工处理流程；  容量规划和压测；  故障降级预案。常见红线：  消息发送失败不能只打印日志；  消费者不能吞掉异常；  不能随意重置消费位点；  不能让死信队列无限增长；  Topic 扩队列要评估顺序性影响；  生产者不能无限重试造成雪崩；  消费逻辑不能无超时；  关键业务不能使用单向发送。本章小结RocketMQ 是面向业务事件的分布式消息系统，核心角色包括 NameServer、Broker、Producer 和 Consumer。它用 CommitLog 顺序写保证吞吐，用 ConsumeQueue维护消费索引，并提供事务消息、延迟消息、顺序消息、重试队列和死信队列等业务语义。理解和 Kafka 的差异，才能在架构中正确选择。思考题  RocketMQ 的 NameServer 和 Kafka 的元数据机制有什么差异？  CommitLog 和 ConsumeQueue 分别解决什么问题？  什么场景必须使用顺序消息？顺序消息会牺牲什么？  事务消息解决的是哪个一致性问题？它不是什么？  如何设计消息消费幂等？</li>
</ul>
