<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>RocketMQ on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/rocketmq/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Fri, 13 Mar 2026 13:00:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/rocketmq/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>多 Worker 分布式渲染：从 HTTP 轮询到 RocketMQ</title>
      <link>https://ftmao.com/blog/posts/roketmq/</link>
      <pubDate>Fri, 13 Mar 2026 13:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/roketmq/</guid>
      <description>&lt;h1 id=&#34;多-worker-分布式渲染从-http-轮询到-rocketmq&#34;&gt;多 Worker 分布式渲染：从 HTTP 轮询到 RocketMQ&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;我开发的方糖猫平台的核心链路最后一步是视频渲染。用户提交生成任务后，系统需要把故事板、配音、素材合成为最终的视频文件。这个步骤 CPU/GPU 密集、耗时长、失败率高，单机渲染很快成为瓶颈。这篇文章会复盘我们从 HTTP 轮询架构迁移到 RocketMQ Push 架构的全过程。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一渲染任务的特性&#34;&gt;一、渲染任务的特性&lt;/h2&gt;
&lt;p&gt;AI 视频平台的渲染任务有几个典型特征：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;特性&lt;/th&gt;
					&lt;th&gt;影响&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;耗时长&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;一个 60 秒视频渲染可能需要 30 秒到 5 分钟&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;资源密集&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;CPU/GPU 占用高，单机并发有限&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;失败率高&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;素材缺失、字体缺失、内存不足、网络超时都可能失败&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;不均衡&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;不同分辨率、不同时长任务耗时差异大&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;需要重试&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;失败后最好换一台 Worker 重试，而不是一直卡在原机&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这些特性决定了渲染不能放在主服务里同步执行，必须用异步任务队列 + 多 Worker 架构。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二第一代架构http-轮询&#34;&gt;二、第一代架构：HTTP 轮询&lt;/h2&gt;
&lt;h3 id=&#34;21-设计思路&#34;&gt;2.1 设计思路&lt;/h3&gt;
&lt;p&gt;最早为了快速验证产品，我们用了最简单的方案：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant A as API 服务
    participant W as Worker 服务
    A-&amp;gt;&amp;gt;W: POST 任务
    A-&amp;gt;&amp;gt;W: 查询状态
    W--&amp;gt;&amp;gt;A: 渲染完成&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;API 服务把渲染任务通过 HTTP POST 发给某个 Worker&lt;/li&gt;
&lt;li&gt;Worker 开始渲染，API 服务定时轮询状态&lt;/li&gt;
&lt;li&gt;渲染完成后，Worker 回调 API 服务&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;22-代码示例&#34;&gt;2.2 代码示例&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; requests
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; time
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RenderService&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;submit&lt;/span&gt;(self, task_id, render_params):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        worker_url &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pick_worker()  &lt;span style=&#34;color:#75715e&#34;&gt;# 简单轮询选一个&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        requests&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;post(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;worker_url&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/render&amp;#34;&lt;/span&gt;, json&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;render_params, timeout&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 轮询等待完成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; _ &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            time&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;sleep(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            status &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; requests&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;worker_url&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/status/&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;task_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;json()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; status[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;]:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; status[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;23-问题很快暴露&#34;&gt;2.3 问题很快暴露&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;问题&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Worker 负载不均&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;轮询分配无法感知 Worker 当前负载&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;单点故障&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;某个 Worker 挂了，上面的任务就卡住&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;扩缩容麻烦&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;新增 Worker 需要改 API 服务配置&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;失败重试复杂&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;需要 API 服务记录每个任务发给了哪个 Worker&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Windows 开发环境问题&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;开发环境只有一台机器，无法模拟多 Worker&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这个方案支撑了产品早期验证，但当日均任务量超过几百条后，稳定性和扩展性都跟不上了。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三第二代架构rocketmq-push&#34;&gt;三、第二代架构：RocketMQ Push&lt;/h2&gt;
&lt;h3 id=&#34;31-为什么选-rocketmq&#34;&gt;3.1 为什么选 RocketMQ&lt;/h3&gt;
&lt;p&gt;我们对比了几种消息队列：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方案&lt;/th&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;HTTP 轮询&lt;/td&gt;
					&lt;td&gt;简单&lt;/td&gt;
					&lt;td&gt;负载不均、失败处理差&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;RabbitMQ&lt;/td&gt;
					&lt;td&gt;功能全面&lt;/td&gt;
					&lt;td&gt;高可用配置复杂&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Kafka&lt;/td&gt;
					&lt;td&gt;吞吐高&lt;/td&gt;
					&lt;td&gt;消费端管理重，延迟不如 RocketMQ&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;RocketMQ&lt;/td&gt;
					&lt;td&gt;负载均衡好、顺序消息、延迟消息、监控完善&lt;/td&gt;
					&lt;td&gt;部署稍重&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;选择 RocketMQ 主要是因为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原生支持 Push Consumer，自动负载均衡&lt;/li&gt;
&lt;li&gt;NameServer 架构适合弹性扩缩容&lt;/li&gt;
&lt;li&gt;消息重试、死信队列机制完善&lt;/li&gt;
&lt;li&gt;团队对阿里系中间件比较熟悉&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;32-新架构设计&#34;&gt;3.2 新架构设计&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;API 服务&amp;#34;] -- &amp;#34;发送渲染任务&amp;#34; --&amp;gt; T[&amp;#34;RocketMQ Topic: video-render&amp;#34;]
    T --&amp;gt; W1[&amp;#34;Worker-1&amp;#34;]
    T --&amp;gt; W2[&amp;#34;Worker-2&amp;#34;]
    T --&amp;gt; WN[&amp;#34;Worker-N&amp;#34;]
    W1 --&amp;gt; D[&amp;#34;渲染完成后更新数据库&amp;#34;]
    W2 --&amp;gt; D
    WN --&amp;gt; D
    D --&amp;gt; S[&amp;#34;SSE 推送进度给用户&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;关键变化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API 服务只负责发消息，不关心任务被哪个 Worker 消费&lt;/li&gt;
&lt;li&gt;Worker 从 RocketMQ 拉取任务，自动负载均衡&lt;/li&gt;
&lt;li&gt;渲染完成后 Worker 更新数据库，并通过 SSE 通知前端&lt;/li&gt;
&lt;li&gt;新增 Worker 只需启动新实例，自动加入消费组&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;33-生产者实现&#34;&gt;3.3 生产者实现&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; rocketmq.client &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; Producer, Message
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;producer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Producer(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;render-producer-group&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;producer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;set_name_server_address(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;localhost:9876&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;producer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;start()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;submit_render_task&lt;/span&gt;(task_id: str, params: dict):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;dumps({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;task_id&amp;#34;&lt;/span&gt;: task_id,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;params&amp;#34;&lt;/span&gt;: params,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;submitted_at&amp;#34;&lt;/span&gt;: time&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;time()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    msg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Message(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;video-render&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    msg&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;set_keys(task_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    msg&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;set_tags(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;normal&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    msg&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;set_body(body)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    producer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;send_sync(msg)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;34-消费者实现&#34;&gt;3.4 消费者实现&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; rocketmq.client &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; PushConsumer, ConsumeStatus
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RenderConsumer&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__init__&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;consumer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; PushConsumer(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;render-consumer-group&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;consumer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;set_name_server_address(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;localhost:9876&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;consumer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;subscribe(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;video-render&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;, self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;on_message)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;on_message&lt;/span&gt;(self, msg):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            data &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;loads(msg&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;body)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            task_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;task_id&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            params &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;params&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# 幂等检查&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;is_task_processed(task_id):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ConsumeStatus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;CONSUME_SUCCESS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# 更新任务状态为处理中&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;update_task_status(task_id, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processing&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# 执行渲染&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;render(params)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# 更新任务状态为完成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;update_task_status(task_id, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;completed&amp;#34;&lt;/span&gt;, result)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ConsumeStatus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;CONSUME_SUCCESS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Exception&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            logger&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;error(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Render failed: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;e&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ConsumeStatus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;RECONSUME_LATER
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;start&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;consumer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;start()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;四关键设计细节&#34;&gt;四、关键设计细节&lt;/h2&gt;
&lt;h3 id=&#34;41-幂等处理&#34;&gt;4.1 幂等处理&lt;/h3&gt;
&lt;p&gt;消息队列可能重复投递，渲染任务又是耗时操作，必须做幂等：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is_task_processed&lt;/span&gt;(task_id: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; bool:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;基于数据库状态做幂等判断&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    task &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; db&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_task(task_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; task&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;status &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;completed&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processing&amp;#34;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;如果任务已经是 &lt;code&gt;processing&lt;/code&gt; 状态，说明可能被其他 Worker 在处理，需要进一步判断心跳时间，避免任务永远卡住。&lt;/p&gt;
&lt;h3 id=&#34;42-心跳与任务认领&#34;&gt;4.2 心跳与任务认领&lt;/h3&gt;
&lt;p&gt;每个 Worker 在处理任务时会定时更新心跳：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;update_task_status&lt;/span&gt;(task_id, status, result&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    db&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;execute(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        UPDATE render_task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        SET status = &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            result = &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            worker_id = &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;            heartbeat_at = NOW()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        WHERE task_id = &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;, (status, result, WORKER_ID, task_id))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;如果某个 Worker 挂了，心跳超过阈值的任务会被标记为失败，重新进入队列重试。&lt;/p&gt;
&lt;h3 id=&#34;43-失败重试与死信队列&#34;&gt;4.3 失败重试与死信队列&lt;/h3&gt;
&lt;p&gt;RocketMQ 支持消费失败自动重试，默认 16 次，间隔递增。如果还是失败，消息进入死信队列：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 消费失败时返回重试&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ConsumeStatus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;RECONSUME_LATER&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;对于死信消息，我们单独处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分析失败原因&lt;/li&gt;
&lt;li&gt;通知运营或用户&lt;/li&gt;
&lt;li&gt;部分场景自动降级（比如降低分辨率重试）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;44-并发控制&#34;&gt;4.4 并发控制&lt;/h3&gt;
&lt;p&gt;每个 Worker 同时能处理几个任务，取决于机器配置。我们通过线程池控制：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; concurrent.futures &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; ThreadPoolExecutor
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 根据 CPU/GPU 核心数设置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;executor &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ThreadPoolExecutor(max_workers&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;on_message&lt;/span&gt;(self, msg):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    future &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; executor&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;submit(self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;handle_render, msg)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 注意：PushConsumer 是阻塞回调，这里需要等待结果&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; future&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;result()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;实际部署中，我们更推荐一个 Worker 进程只消费一个任务，通过启动多个 Worker 进程来提升并发。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五windows-开发环境兼容&#34;&gt;五、Windows 开发环境兼容&lt;/h2&gt;
&lt;h3 id=&#34;51-问题&#34;&gt;5.1 问题&lt;/h3&gt;
&lt;p&gt;RocketMQ 在 Windows 上部署比较麻烦，开发环境有时候只有一台机器。为了不影响开发效率，我们设计了一个降级策略：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;生产环境：RocketMQ Push Consumer
开发环境：HTTP 轮询模拟（单 Worker）&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;52-抽象层设计&#34;&gt;5.2 抽象层设计&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TaskConsumer&lt;/span&gt;(ABC):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@abstractmethod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;start&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RocketMQConsumer&lt;/span&gt;(TaskConsumer):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;生产环境使用&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HttpPollConsumer&lt;/span&gt;(TaskConsumer):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;开发环境使用&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 根据配置切换&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;consumer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; RocketMQConsumer() &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; env &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;production&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; HttpPollConsumer()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;这样业务逻辑完全一致，只是消息消费方式不同。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六监控与告警&#34;&gt;六、监控与告警&lt;/h2&gt;
&lt;h3 id=&#34;61-关键指标&#34;&gt;6.1 关键指标&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;指标&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;队列堆积量&lt;/td&gt;
					&lt;td&gt;判断是否需要扩容 Worker&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;任务平均处理时间&lt;/td&gt;
					&lt;td&gt;评估渲染性能和资源需求&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;任务成功率&lt;/td&gt;
					&lt;td&gt;健康度核心指标&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Worker 在线数量&lt;/td&gt;
					&lt;td&gt;消费组健康状态&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;重试次数分布&lt;/td&gt;
					&lt;td&gt;发现系统性问题&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;62-告警规则&#34;&gt;6.2 告警规则&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;队列堆积超过 100 条，持续 5 分钟 → 扩容提醒&lt;/li&gt;
&lt;li&gt;任务成功率低于 95% → 人工介入&lt;/li&gt;
&lt;li&gt;Worker 数量异常减少 → 服务异常告警&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七演进效果&#34;&gt;七、演进效果&lt;/h2&gt;
&lt;p&gt;迁移到 RocketMQ 后，渲染系统的稳定性明显提升：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;指标&lt;/th&gt;
					&lt;th&gt;HTTP 轮询&lt;/th&gt;
					&lt;th&gt;RocketMQ Push&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;平均等待时间&lt;/td&gt;
					&lt;td&gt;X 分钟&lt;/td&gt;
					&lt;td&gt;Y 分钟&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;任务成功率&lt;/td&gt;
					&lt;td&gt;X%&lt;/td&gt;
					&lt;td&gt;Y%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Worker 利用率&lt;/td&gt;
					&lt;td&gt;不均&lt;/td&gt;
					&lt;td&gt;均衡&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;扩容成本&lt;/td&gt;
					&lt;td&gt;需要改配置&lt;/td&gt;
					&lt;td&gt;启动实例即可&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;失败重试&lt;/td&gt;
					&lt;td&gt;自建逻辑&lt;/td&gt;
					&lt;td&gt;原生支持&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;（待补充真实数据）&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八踩过的坑&#34;&gt;八、踩过的坑&lt;/h2&gt;
&lt;h3 id=&#34;81-消息体过大&#34;&gt;8.1 消息体过大&lt;/h3&gt;
&lt;p&gt;早期的渲染参数里包含完整的素材 URL 列表，消息体很大。RocketMQ 默认单条消息限制 4MB，我们遇到过消息发送失败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：消息体只传 &lt;code&gt;task_id&lt;/code&gt; 和关键参数，Worker 消费后自己从数据库/redis 拉取完整参数。&lt;/p&gt;
&lt;h3 id=&#34;82-消费组订阅不一致&#34;&gt;8.2 消费组订阅不一致&lt;/h3&gt;
&lt;p&gt;不同 Worker 用同一个消费组但订阅了不同 Tag，导致消息分发混乱。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：严格规范消费组命名和订阅规则，每个消费组只负责一个 Topic。&lt;/p&gt;
&lt;h3 id=&#34;83-任务卡住没有超时释放&#34;&gt;8.3 任务卡住没有超时释放&lt;/h3&gt;
&lt;p&gt;某个 Worker 处理到一半进程挂了，任务状态一直是 &lt;code&gt;processing&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：增加心跳检测，心跳超时的任务自动重置为 &lt;code&gt;pending&lt;/code&gt;，重新入队。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九总结&#34;&gt;九、总结&lt;/h2&gt;
&lt;p&gt;视频渲染是 AI 视频平台里最典型的「重任务」场景，必须用异步队列 + 分布式 Worker 来解决。几个关键经验：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不要过早优化，但也不能过度将就&lt;/strong&gt;。HTTP 轮询能验证产品，但流量起来后必须升级。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RocketMQ 的 Push Consumer 很适合这种场景&lt;/strong&gt;，负载均衡和重试机制省去很多自建成本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;幂等和心跳是必须的&lt;/strong&gt;，否则任务会丢或卡住。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监控要跟上&lt;/strong&gt;，队列堆积和成功率是最核心的两个指标。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;如果你也在做类似的异步任务处理系统，欢迎交流消息队列选型和 Worker 调度经验。&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>消息队列总结：RabbitMQ、Kafka、RocketMQ 与 Redis MQ 选型对比与实践避坑</title>
      <link>https://ftmao.com/blog/posts/mq-comparison-rabbitmq-kafka-rocketmq/</link>
      <pubDate>Tue, 30 Jun 2020 10:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/mq-comparison-rabbitmq-kafka-rocketmq/</guid>
      <description>&lt;h1 id=&#34;消息队列总结rabbitmqkafkarocketmq-与-redis-mq-选型对比与实践避坑&#34;&gt;消息队列总结：RabbitMQ、Kafka、RocketMQ 与 Redis MQ 选型对比与实践避坑&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;消息队列是分布式系统里最常见的「异步管道」。这篇笔记把 RabbitMQ、Kafka、RocketMQ 和 Redis MQ 放在一起比较，重点回答：什么时候该用哪个？推和拉到底怎么选？长连接有什么影响？以及实际使用中的避坑和异常处理经验。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一为什么需要消息队列&#34;&gt;一、为什么需要消息队列？&lt;/h2&gt;
&lt;p&gt;在没有 MQ 的系统中，A 服务调用 B 服务通常是同步的：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;A ──同步调用──▶ B ──同步调用──▶ C
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     等待返回      等待返回&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;链路越长，响应越慢，容错越差。MQ 的核心价值是把「同步依赖」变成「异步管道」：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;A ──发送消息──▶ MQ ──接收消息──▶ B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   立即返回         异步处理&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;11-mq-解决的三大问题&#34;&gt;1.1 MQ 解决的三大问题&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;解耦&lt;/strong&gt;：生产方只负责发消息，不用关心谁消费、怎么消费。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步&lt;/strong&gt;：把非核心链路（发短信、记日志、发券）从主流程剥离，降低接口 RT。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;削峰填谷&lt;/strong&gt;：突发流量先写入队列，下游按自身能力消费，避免被压垮。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;12-什么时候必须引入-mq&#34;&gt;1.2 什么时候必须引入 MQ？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;上下游处理速度差异大，同步调用会导致阻塞或超时。&lt;/li&gt;
&lt;li&gt;需要保证某些操作最终执行，但不需要实时返回结果。&lt;/li&gt;
&lt;li&gt;系统拆分后，多个服务需要感知同一事件。&lt;/li&gt;
&lt;li&gt;大促/活动场景下，需要缓冲突发流量。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二四种-mq-横向对比&#34;&gt;二、四种 MQ 横向对比&lt;/h2&gt;
&lt;p&gt;RabbitMQ、Kafka、RocketMQ 是主流企业级 MQ，Redis 也能当轻量 MQ 用，但定位不同。&lt;/p&gt;
&lt;h3 id=&#34;21-核心定位&#34;&gt;2.1 核心定位&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;RocketMQ&lt;/th&gt;
					&lt;th&gt;RabbitMQ&lt;/th&gt;
					&lt;th&gt;Kafka&lt;/th&gt;
					&lt;th&gt;Redis MQ&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;出身与设计目标&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;阿里开源，面向在线交易/金融级消息&lt;/td&gt;
					&lt;td&gt;Erlang 实现，面向通用企业消息&lt;/td&gt;
					&lt;td&gt;LinkedIn 开源，面向日志采集与流处理&lt;/td&gt;
					&lt;td&gt;内存数据库，轻量级队列/发布订阅&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;数据模型&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Topic + Queue，支持 Tag 过滤&lt;/td&gt;
					&lt;td&gt;Exchange + Queue，路由灵活&lt;/td&gt;
					&lt;td&gt;Topic + Partition，分区有序&lt;/td&gt;
					&lt;td&gt;List / Stream / PubSub&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;默认消费方式&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Push（长轮询封装）+ Pull&lt;/td&gt;
					&lt;td&gt;Push（AMQP 推送）&lt;/td&gt;
					&lt;td&gt;Pull（消费者主动拉取）&lt;/td&gt;
					&lt;td&gt;Push（PubSub）/ Pull（BLPOP）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;顺序消息&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;分片内有序，Sharding Key 控制&lt;/td&gt;
					&lt;td&gt;单 Queue 有序&lt;/td&gt;
					&lt;td&gt;Partition 内有序&lt;/td&gt;
					&lt;td&gt;单 Stream/列表有序&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;延迟消息&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;原生支持 18 个级别&lt;/td&gt;
					&lt;td&gt;需插件或死信实现&lt;/td&gt;
					&lt;td&gt;不原生支持，需借助外部组件&lt;/td&gt;
					&lt;td&gt;无原生支持&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;事务消息&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;原生支持&lt;/td&gt;
					&lt;td&gt;不支持原生事务消息&lt;/td&gt;
					&lt;td&gt;不支持原生事务消息&lt;/td&gt;
					&lt;td&gt;不支持&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;消息持久化&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;磁盘持久化，支持同步/异步刷盘&lt;/td&gt;
					&lt;td&gt;磁盘持久化&lt;/td&gt;
					&lt;td&gt;磁盘持久化，顺序写&lt;/td&gt;
					&lt;td&gt;默认内存，可持久化但非强项&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;消息轨迹&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;原生支持&lt;/td&gt;
					&lt;td&gt;需额外配置&lt;/td&gt;
					&lt;td&gt;需额外组件&lt;/td&gt;
					&lt;td&gt;无&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;22-性能对比&#34;&gt;2.2 性能对比&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;RocketMQ&lt;/th&gt;
					&lt;th&gt;RabbitMQ&lt;/th&gt;
					&lt;th&gt;Kafka&lt;/th&gt;
					&lt;th&gt;Redis MQ&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;单机吞吐&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;10 万级 TPS&lt;/td&gt;
					&lt;td&gt;万级 TPS&lt;/td&gt;
					&lt;td&gt;百万级 TPS（批量场景）&lt;/td&gt;
					&lt;td&gt;十万级 TPS（内存操作）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;延迟&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;毫秒级&lt;/td&gt;
					&lt;td&gt;微秒-毫秒级&lt;/td&gt;
					&lt;td&gt;毫秒级，批量时更高&lt;/td&gt;
					&lt;td&gt;微秒-毫秒级&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;消息堆积能力&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;强，适合削峰&lt;/td&gt;
					&lt;td&gt;一般，堆积过多影响性能&lt;/td&gt;
					&lt;td&gt;极强，专为日志设计&lt;/td&gt;
					&lt;td&gt;弱，内存容量受限&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;批量效率&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;中等&lt;/td&gt;
					&lt;td&gt;一般&lt;/td&gt;
					&lt;td&gt;极高&lt;/td&gt;
					&lt;td&gt;一般&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;说明&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kafka 吞吐数字通常来自批量、压缩、顺序写的日志场景；单条小消息低延迟不如 RocketMQ。&lt;/li&gt;
&lt;li&gt;RabbitMQ 延迟低，但高吞吐和海量堆积不是强项。&lt;/li&gt;
&lt;li&gt;RocketMQ 在「中等吞吐 + 低延迟 + 强堆积」之间取得了较好平衡。&lt;/li&gt;
&lt;li&gt;Redis MQ 性能高，但消息堆积、持久化、事务、延迟消息都不完善，适合轻量、临时场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;23-成本与生态&#34;&gt;2.3 成本与生态&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;RocketMQ&lt;/th&gt;
					&lt;th&gt;RabbitMQ&lt;/th&gt;
					&lt;th&gt;Kafka&lt;/th&gt;
					&lt;th&gt;Redis MQ&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;部署复杂度&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;中等（NameServer + Broker）&lt;/td&gt;
					&lt;td&gt;低（单节点即可运行）&lt;/td&gt;
					&lt;td&gt;高（ZooKeeper/KRaft + Broker）&lt;/td&gt;
					&lt;td&gt;低（Redis 单实例/集群）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;运维成本&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;中等，阿里系文档丰富&lt;/td&gt;
					&lt;td&gt;低，但 Erlang 问题排查门槛高&lt;/td&gt;
					&lt;td&gt;高，调优项多&lt;/td&gt;
					&lt;td&gt;低，Redis 团队普遍熟悉&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;云服务成熟度&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;阿里云 RocketMQ 成熟&lt;/td&gt;
					&lt;td&gt;各云厂商都有托管版&lt;/td&gt;
					&lt;td&gt;各云厂商 Kafka 托管版成熟&lt;/td&gt;
					&lt;td&gt;云 Redis 托管版成熟&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;学习曲线&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;中等&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
					&lt;td&gt;高&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;大数据生态&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;一般，可与 Flink/Spark 对接&lt;/td&gt;
					&lt;td&gt;弱&lt;/td&gt;
					&lt;td&gt;极强，流处理事实标准&lt;/td&gt;
					&lt;td&gt;弱&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;语言客户端&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Java 最完善，其他语言有社区版&lt;/td&gt;
					&lt;td&gt;极其丰富&lt;/td&gt;
					&lt;td&gt;极其丰富&lt;/td&gt;
					&lt;td&gt;极其丰富&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;24-适用场景推荐&#34;&gt;2.4 适用场景推荐&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;推荐&lt;/th&gt;
					&lt;th&gt;原因&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;电商/金融订单、交易消息&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;延迟低、事务消息、顺序消息、监控完善&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;异步任务、分布式 Worker、视频渲染&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;PushConsumer 自动负载均衡，失败重试完善&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;传统企业应用、RPC 解耦、路由复杂&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;简单易用，Exchange 路由灵活，快速上线&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;日志采集、埋点、实时数仓、流处理&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;吞吐和生态碾压，分区模型适合流计算&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;事件总线、多语言异构系统&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ / Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;客户端生态更丰富&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;需要事务消息且不想自己实现&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;原生事务消息是差异化能力&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;轻量异步通知、缓存队列、临时任务&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;部署简单、延迟低，但不要把核心交易交给它&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;已有 Redis 基础设施，不想引入新组件&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;作为过渡方案或辅助队列可用&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;25-一句话选型&#34;&gt;2.5 一句话选型&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;可靠交易、事务消息、顺序消息、在线业务  →  RocketMQ
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;快速搭建、路由灵活、团队规模小          →  RabbitMQ
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;日志/流处理/大数据管道、吞吐优先          →  Kafka
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;轻量通知、临时队列、已有 Redis 生态       →  Redis MQ&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;很多大厂内部是「Kafka 做日志流 + RocketMQ 做业务消息 + RabbitMQ 做轻量任务 + Redis 做缓存/通知」组合使用，不是单选题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三底层架构与核心差异&#34;&gt;三、底层架构与核心差异&lt;/h2&gt;
&lt;h3 id=&#34;31-四种-mq-架构对比&#34;&gt;3.1 四种 MQ 架构对比&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph RocketMQ
        P1[Producer] --&amp;gt; NS[NameServer]
        NS --&amp;gt; B1[Broker Master]
        B1 --&amp;gt; B2[Broker Slave]
        B1 --&amp;gt; C1[Consumer]
    end

    subgraph Kafka
        P2[Producer] --&amp;gt; KZ[ZooKeeper / KRaft]
        KZ --&amp;gt; KB1[Broker 1]
        KZ --&amp;gt; KB2[Broker 2]
        KB1 --&amp;gt; C2[Consumer]
    end

    subgraph RabbitMQ
        P3[Producer] --&amp;gt; EX[Exchange]
        EX --&amp;gt; Q1[Queue A]
        EX --&amp;gt; Q2[Queue B]
        Q1 --&amp;gt; C3[Consumer A]
        Q2 --&amp;gt; C4[Consumer B]
    end

    subgraph RedisMQ
        P4[Producer] --&amp;gt; R[(Redis)]
        R --&amp;gt; C5[Consumer BLPOP]
        R --&amp;gt; C6[Subscriber]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;32-存储模型&#34;&gt;3.2 存储模型&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;存储结构&lt;/th&gt;
					&lt;th&gt;核心特点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;CommitLog + ConsumeQueue&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;所有 Topic 的消息顺序写入同一个 CommitLog，再用 ConsumeQueue 存每个 Queue 的偏移索引。顺序写磁盘，I/O 效率高。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Partition Segment + Index&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;每个 Partition 是独立日志目录，顺序写入 Segment，配合稀疏索引。Partition 间物理隔离。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Queue 独立存储&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;每个 Queue 维护独立索引和存储，Queue 越多元数据开销越大。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;内存 List / Stream&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;基于内存操作，速度快，但容量受内存限制，持久化可靠性不如专业 MQ。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    subgraph RocketMQ_Storage[&amp;#34;RocketMQ 存储模型&amp;#34;]
        CL[CommitLog&amp;lt;br/&amp;gt;所有消息顺序写]
        CQ1[ConsumeQueue A&amp;lt;br/&amp;gt;偏移索引]
        CQ2[ConsumeQueue B&amp;lt;br/&amp;gt;偏移索引]
        CL --&amp;gt; CQ1
        CL --&amp;gt; CQ2
    end

    subgraph Kafka_Storage[&amp;#34;Kafka 存储模型&amp;#34;]
        KP1[TopicA-P0 Log&amp;lt;br/&amp;gt;独立 Partition]
        KP2[TopicA-P1 Log&amp;lt;br/&amp;gt;独立 Partition]
    end

    subgraph RabbitMQ_Storage[&amp;#34;RabbitMQ 存储模型&amp;#34;]
        MQ1[Queue A&amp;lt;br/&amp;gt;独立索引]
        MQ2[Queue B&amp;lt;br/&amp;gt;独立索引]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;33-路由与元数据管理&#34;&gt;3.3 路由与元数据管理&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;注册/路由中心&lt;/th&gt;
					&lt;th&gt;设计哲学&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;NameServer&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;无状态集群，Broker 主动上报路由，Producer/Consumer 定时拉取。最终一致，轻量。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;ZooKeeper / KRaft&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;老版本依赖 ZooKeeper 存元数据、选 Controller；新版本用 KRaft 自洽协议。强一致要求更高。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;内置 Mnesia 数据库&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;集群节点共享元数据，Erlang 进程模型天然分布式，但集群扩展性相对有限。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;无&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;依赖 Redis 自身的 Cluster/哨兵做高可用，没有独立路由层。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;34-复制与高可用&#34;&gt;3.4 复制与高可用&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;复制方式&lt;/th&gt;
					&lt;th&gt;特点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Master-Slave 同步/异步复制&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;同步复制保证不丢消息，异步复制性能更高。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Partition 多副本 + ISR 机制&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;自动 Failover，成熟度高。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;普通队列 + 镜像队列&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;普通队列只存在于一个节点；镜像队列复制到多个节点但吞吐下降。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;主从 + 哨兵 / Cluster&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Redis 自身的高可用机制，不是为消息队列专门设计。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四推拉模式与长连接&#34;&gt;四、推、拉模式与长连接&lt;/h2&gt;
&lt;h3 id=&#34;41-push-vs-pull-对比&#34;&gt;4.1 Push vs Pull 对比&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;Push（推）&lt;/th&gt;
					&lt;th&gt;Pull（拉）&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;控制权&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;在 Broker&lt;/td&gt;
					&lt;td&gt;在 Consumer&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;实时性&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;高，Broker 有消息就发&lt;/td&gt;
					&lt;td&gt;依赖拉取间隔，实时性可调&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;背压能力&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;较弱，Consumer 处理慢会堆积&lt;/td&gt;
					&lt;td&gt;强，Consumer 自己控制速率&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;实现复杂度&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;低，业务写回调即可&lt;/td&gt;
					&lt;td&gt;高，需自管 offset、拉取循环&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;适用场景&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;实时性要求高、消费轻量&lt;/td&gt;
					&lt;td&gt;批量处理、消费重、需要控速&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;42-四种-mq-的推拉实现&#34;&gt;4.2 四种 MQ 的推拉实现&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;消费方式&lt;/th&gt;
					&lt;th&gt;是否长连接&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;长轮询 Pull 封装成 Push&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
					&lt;td&gt;Consumer 与 Broker 保持长连接，Broker hold 请求 5 秒左右，有新消息立即返回。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;消费者主动 Pull&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;否（可保持连接但非必需）&lt;/td&gt;
					&lt;td&gt;Consumer 自己决定何时拉、拉多少，灵活性最高。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Broker 真 Push（AMQP）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
					&lt;td&gt;Channel 长连接，Broker 把消息塞给 Consumer，处理完 ACK。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;PubSub 推 / BLPOP 拉&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
					&lt;td&gt;PubSub 是长连接推送；BLPOP 是阻塞拉取，也算长连接。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;43-长连接的影响&#34;&gt;4.3 长连接的影响&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph 长连接优势
        A1[低延迟]
        A2[实时推送]
        A3[减少建连开销]
    end

    subgraph 长连接代价
        B1[连接数消耗大]
        B2[需要心跳保活]
        B3[网络断开感知延迟]
        B4[Consumer 慢会拖垮 Broker]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;长连接的好处&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消息到达可以立刻推送给 Consumer，延迟低。&lt;/li&gt;
&lt;li&gt;避免频繁建立/断开 TCP 连接的开销。&lt;/li&gt;
&lt;li&gt;适合在线业务、实时通知类场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;长连接的代价&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Broker 需要维护大量连接，连接数成为重要资源。&lt;/li&gt;
&lt;li&gt;必须有心跳机制，否则无法及时发现 Consumer 宕机。&lt;/li&gt;
&lt;li&gt;Consumer 处理慢时，消息会堆积在 Broker 内存或磁盘，容易把 Broker 压垮。&lt;/li&gt;
&lt;li&gt;网络闪断后需要重连、重平衡，可能带来消费抖动。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;44-选择原则&#34;&gt;4.4 选择原则&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[选择消费模式] --&amp;gt; B{实时性要求高?}
    B --&amp;gt;|是| C{消费逻辑轻量?}
    B --&amp;gt;|否| D[Pull 模式]
    C --&amp;gt;|是| E[Push 模式]
    C --&amp;gt;|否| F[Pull 模式 或 限流 Push]
    D --&amp;gt; G[批量处理/ETL/数据同步]
    E --&amp;gt; H[在线业务/实时通知]
    F --&amp;gt; I[重任务/视频渲染/大数据]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;五使用注意点与避坑指南&#34;&gt;五、使用注意点与避坑指南&lt;/h2&gt;
&lt;h3 id=&#34;51-rocketmq-避坑&#34;&gt;5.1 RocketMQ 避坑&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;坑&lt;/th&gt;
					&lt;th&gt;现象&lt;/th&gt;
					&lt;th&gt;解决&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;消费组订阅不一致&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;同一个 ConsumerGroup 订阅不同 Topic/Tag，重平衡混乱&lt;/td&gt;
					&lt;td&gt;一个 ConsumerGroup 只订阅一个 Topic + 一套 Tag&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Tag 用得太细&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;管理混乱，消费者过滤复杂&lt;/td&gt;
					&lt;td&gt;Topic 按业务域划分，Tag 做粗粒度过滤&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;消息体过大&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;超过 4MB 默认限制，发送失败&lt;/td&gt;
					&lt;td&gt;消息体只传 ID 和必要字段，完整数据从 DB/OSS 拉取&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;顺序消息误用&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;全局顺序严重拖垮吞吐&lt;/td&gt;
					&lt;td&gt;只在真正需要局部顺序的场景用 Sharding Key&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;NameServer 路由延迟&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Broker 扩缩容后发送到已下线节点&lt;/td&gt;
					&lt;td&gt;理解最终一致性，扩缩容留足等待时间&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;自动创建 Topic&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;生产环境订阅失败或路由错误&lt;/td&gt;
					&lt;td&gt;提前创建 Topic 和 ConsumerGroup&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;52-kafka-避坑&#34;&gt;5.2 Kafka 避坑&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;坑&lt;/th&gt;
					&lt;th&gt;现象&lt;/th&gt;
					&lt;th&gt;解决&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Partition 数设置不当&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;太少并行度不够，太多元数据压力大&lt;/td&gt;
					&lt;td&gt;根据吞吐和 Consumer 数合理规划&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;消费者 Rebalance 频繁&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;消费停滞，组员加入/退出频繁&lt;/td&gt;
					&lt;td&gt;避免频繁扩缩容，调整 session.timeout.ms&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Offset 提交策略不当&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;重复消费或消息丢失&lt;/td&gt;
					&lt;td&gt;重要消息手动提交，处理完再 commit&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Producer  acks=0/1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;丢消息&lt;/td&gt;
					&lt;td&gt;关键业务用 acks=all&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;单 Partition 热点&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;某个 Partition 消费滞后&lt;/td&gt;
					&lt;td&gt;合理设计 Key，避免 Key 倾斜&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;53-rabbitmq-避坑&#34;&gt;5.3 RabbitMQ 避坑&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;坑&lt;/th&gt;
					&lt;th&gt;现象&lt;/th&gt;
					&lt;th&gt;解决&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;镜像队列性能下降&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;开镜像后吞吐明显降低&lt;/td&gt;
					&lt;td&gt;只对关键队列开镜像&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;队列堆积过多&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Broker 内存/磁盘告警，性能下降&lt;/td&gt;
					&lt;td&gt;控制生产速度，及时扩容 Consumer&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ACK 模式用错&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;消息丢失或重复&lt;/td&gt;
					&lt;td&gt;手动 ACK，处理完再确认&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Exchange 路由复杂&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;消息去向难以追踪&lt;/td&gt;
					&lt;td&gt;规范命名，做好监控&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Connection/Channel 滥用&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;连接数耗尽&lt;/td&gt;
					&lt;td&gt;Channel 复用，避免每个消息新建连接&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;54-redis-mq-避坑&#34;&gt;5.4 Redis MQ 避坑&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;坑&lt;/th&gt;
					&lt;th&gt;现象&lt;/th&gt;
					&lt;th&gt;解决&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;PubSub 消息丢失&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Consumer 断线期间的消息收不到&lt;/td&gt;
					&lt;td&gt;重要消息用 Stream 或专业 MQ&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;List 做队列无 ACK&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Consumer 处理失败消息丢失&lt;/td&gt;
					&lt;td&gt;用 Stream 的 ACK 机制&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;内存不足&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Redis OOM&lt;/td&gt;
					&lt;td&gt;设置合理过期时间，控制队列长度&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;把 Redis 当核心 MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;数据丢失、无事务、无延迟消息&lt;/td&gt;
					&lt;td&gt;核心交易链路用 RocketMQ/Kafka&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;55-通用最佳实践&#34;&gt;5.5 通用最佳实践&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;消息体尽量小&lt;/strong&gt;：传 ID 不传大对象。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;幂等设计&lt;/strong&gt;：所有 Consumer 都要做幂等，MQ 只保证至少一次投递。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监控到位&lt;/strong&gt;：堆积量、消费 TPS、延迟、死信队列、Broker 资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;版本一致&lt;/strong&gt;：服务端和客户端版本不要差距太大。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提前创建资源&lt;/strong&gt;：生产环境不要依赖自动创建 Topic/Queue。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;区分可重试与不可重试异常&lt;/strong&gt;：网络抖动可以重试，参数错误直接进死信。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六异常场景处理分-mq-说明&#34;&gt;六、异常场景处理（分 MQ 说明）&lt;/h2&gt;
&lt;p&gt;下面列出的异常场景在 RocketMQ、RabbitMQ、Kafka、Redis MQ 中都会遇到，但每种 MQ 提供的机制和最佳实践不同。这一节把四种 MQ 放在一起对比说明。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    P[Producer 发送层] --&amp;gt;|发送失败/超时| B[Broker 存储层]
    B --&amp;gt;|刷盘/复制失败| C[Consumer 消费层]
    C --&amp;gt;|重复/失败/卡住| Biz[业务异常兜底]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;61-消息丢失各-mq-如何防范&#34;&gt;6.1 消息丢失：各 MQ 如何防范&lt;/h3&gt;
&lt;p&gt;消息丢失通常发生在三个环节：&lt;strong&gt;Producer 发送失败&lt;/strong&gt;、&lt;strong&gt;Broker 存储失败&lt;/strong&gt;、&lt;strong&gt;Consumer 消费失败未 ACK&lt;/strong&gt;。四种 MQ 的防范方式如下：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;环节&lt;/th&gt;
					&lt;th&gt;RocketMQ&lt;/th&gt;
					&lt;th&gt;RabbitMQ&lt;/th&gt;
					&lt;th&gt;Kafka&lt;/th&gt;
					&lt;th&gt;Redis MQ&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Producer 发送&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;同步发送 &lt;code&gt;SYNC&lt;/code&gt; + 失败重试；避免 &lt;code&gt;ONEWAY&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;使用 &lt;code&gt;confirm&lt;/code&gt; 模式等待 Broker ACK；开启 Publisher Confirms&lt;/td&gt;
					&lt;td&gt;设置 &lt;code&gt;acks=all&lt;/code&gt; + 重试；避免 &lt;code&gt;acks=0/1&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;无发送确认机制，调用成功不代表持久化成功；重要消息不要用 Redis PubSub&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Broker 存储&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;同步刷盘 &lt;code&gt;SYNC_FLUSH&lt;/code&gt; + 同步复制 &lt;code&gt;SYNC_MASTER&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;队列持久化 + 镜像队列复制；消息标记 &lt;code&gt;persistent&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;replication.factor &amp;gt;= 3&lt;/code&gt; + &lt;code&gt;min.insync.replicas&lt;/code&gt; 控制&lt;/td&gt;
					&lt;td&gt;AOF/ RDB 持久化，但默认异步；主从切换可能丢数据&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Consumer 消费&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;先处理业务再返回 &lt;code&gt;CONSUME_SUCCESS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;手动 ACK，处理完再 &lt;code&gt;basic.ack&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;处理完再 commit offset&lt;/td&gt;
					&lt;td&gt;Stream 用 &lt;code&gt;XACK&lt;/code&gt; 确认；List/ PubSub 无 ACK&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;兜底&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;业务对账 + 补偿表&lt;/td&gt;
					&lt;td&gt;业务对账 + 补偿表&lt;/td&gt;
					&lt;td&gt;业务对账 + 补偿表&lt;/td&gt;
					&lt;td&gt;不建议做核心兜底，Redis 本身不是可靠 MQ&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键提醒&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;：&lt;code&gt;SYNC_MASTER&lt;/code&gt; + &lt;code&gt;SYNC_FLUSH&lt;/code&gt; 配置最安全，但性能最低；在线交易通常用 &lt;code&gt;SYNC_MASTER&lt;/code&gt; + &lt;code&gt;ASYNC_FLUSH&lt;/code&gt; 折中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;：默认自动 ACK 最容易丢消息，生产环境一定要改手动 ACK。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kafka&lt;/strong&gt;：&lt;code&gt;acks=all&lt;/code&gt; 配合 &lt;code&gt;min.insync.replicas&lt;/code&gt; 才能保证写入 ISR 多数副本；只配置 &lt;code&gt;acks=all&lt;/code&gt; 不够。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;：Redis 本身不是为消息可靠性设计的，&lt;strong&gt;不要把核心交易消息的防丢失交给 Redis&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;62-消息重复各-mq-的投递语义与幂等&#34;&gt;6.2 消息重复：各 MQ 的投递语义与幂等&lt;/h3&gt;
&lt;p&gt;四种 MQ 大多只保证「至少一次投递」（at-least-once），重复消费要靠业务层幂等。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;MQ&lt;/th&gt;
					&lt;th&gt;默认投递语义&lt;/th&gt;
					&lt;th&gt;重复来源&lt;/th&gt;
					&lt;th&gt;推荐幂等方案&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;At-least-once&lt;/td&gt;
					&lt;td&gt;网络超时重发、Consumer 重启、Broker 重试&lt;/td&gt;
					&lt;td&gt;消息 &lt;code&gt;keys&lt;/code&gt; 做唯一业务 Key + 数据库唯一索引&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;At-least-once&lt;/td&gt;
					&lt;td&gt;连接断开、ACK 未到达 Broker、Consumer 重启&lt;/td&gt;
					&lt;td&gt;消息 &lt;code&gt;message_id&lt;/code&gt; 或业务 Key + 幂等表&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;At-least-once&lt;/td&gt;
					&lt;td&gt;Consumer Rebalance、Offset 提交失败、Producer 重试&lt;/td&gt;
					&lt;td&gt;业务 Key 去重；Kafka 幂等 Producer 只能去重单会话内重复&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;不保证&lt;/td&gt;
					&lt;td&gt;PubSub 不持久化，断线即丢；Stream 相对可靠但无原生重试&lt;/td&gt;
					&lt;td&gt;业务侧用 Redis &lt;code&gt;SETNX&lt;/code&gt; 或数据库唯一索引&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 通用幂等伪代码，适用于四种 MQ&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;consume&lt;/span&gt;(msg):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    biz_key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; extract_biz_key(msg)  &lt;span style=&#34;color:#75715e&#34;&gt;# RocketMQ keys / RabbitMQ message_id / Kafka key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        idempotent_record&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;insert(biz_key&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;biz_key, status&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processing&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; UniqueViolation:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; SUCCESS  &lt;span style=&#34;color:#75715e&#34;&gt;# 已处理过，直接成功&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        do_business(msg)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        idempotent_record&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;update(biz_key, status&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; SUCCESS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; RetryableException:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        idempotent_record&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;update(biz_key, status&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failed&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RETRY
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; NonRetryableException:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        idempotent_record&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;update(biz_key, status&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failed&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; DEAD_LETTER&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;63-消费失败重试与死信机制&#34;&gt;6.3 消费失败：重试与死信机制&lt;/h3&gt;
&lt;p&gt;消费失败后，不同 MQ 的重试和死信（DLQ）机制差异很大：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;MQ&lt;/th&gt;
					&lt;th&gt;重试机制&lt;/th&gt;
					&lt;th&gt;死信队列&lt;/th&gt;
					&lt;th&gt;注意事项&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;默认最多 16 次，间隔阶梯递增（10s、30s、1m&amp;hellip;）&lt;/td&gt;
					&lt;td&gt;自动进入 &lt;code&gt;%DLQ%consumer_group&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;可区分 &lt;code&gt;RECONSUME_LATER&lt;/code&gt; 重试和直接成功；重试次数可在 Broker 配置&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;无内置重试，需业务侧或插件实现；常用 TTL + 死信交换器（DLX）做延迟重试&lt;/td&gt;
					&lt;td&gt;通过 &lt;code&gt;x-dead-letter-exchange&lt;/code&gt; 配置 DLX/DLQ&lt;/td&gt;
					&lt;td&gt;手动 ACK 失败或 NACK + requeue=false 进入死信&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;无内置重试次数，失败时 Consumer 自己决定是否重试或跳过&lt;/td&gt;
					&lt;td&gt;无原生 DLQ，需业务侧或 Kafka Connect 实现&lt;/td&gt;
					&lt;td&gt;常见做法：失败消息写入专用 Error Topic，由补偿服务处理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;无内置重试&lt;/td&gt;
					&lt;td&gt;无原生 DLQ&lt;/td&gt;
					&lt;td&gt;Stream 可配合 Consumer Group 的 Pending List 人工处理；List/ PubSub 无重试能力&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[Consumer 处理失败] --&amp;gt; B{MQ 类型}
    B --&amp;gt;|RocketMQ| C[返回 RECONSUME_LATER]
    B --&amp;gt;|RabbitMQ| D[NACK + requeue=false 进 DLX]
    B --&amp;gt;|Kafka| E[写入 Error Topic 或暂停消费]
    B --&amp;gt;|Redis Stream| F[XCLAIM 或人工处理 Pending]
    C --&amp;gt; G{重试超限?}
    G --&amp;gt;|是| H[进入 DLQ]
    G --&amp;gt;|否| C
    D --&amp;gt; H
    E --&amp;gt; I[补偿服务消费 Error Topic]
    F --&amp;gt; J[业务侧补偿]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;可重试异常&lt;/strong&gt;：网络超时、依赖服务短暂不可用、数据库连接池耗尽。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不可重试异常&lt;/strong&gt;：参数非法、依赖返回 4xx、业务规则冲突、数据不存在。&lt;/p&gt;
&lt;h3 id=&#34;64-业务异常处理&#34;&gt;6.4 业务异常处理&lt;/h3&gt;
&lt;p&gt;业务异常（如参数错误、状态冲突、规则校验失败）和系统异常（网络、DB、依赖故障）要分开处理。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[Consumer 捕获异常] --&amp;gt; B{异常类型}
    B --&amp;gt;|系统异常&amp;lt;br/&amp;gt;网络/DB/依赖| C[MQ 重试]
    B --&amp;gt;|业务异常&amp;lt;br/&amp;gt;参数/规则/状态冲突| D[记录失败明细]
    D --&amp;gt; E{能否修复?}
    E --&amp;gt;|能| F[人工补偿/修复后重投]
    E --&amp;gt;|不能| G[进死信队列或丢弃]
    C --&amp;gt; H{重试成功?}
    H --&amp;gt;|否| I[进入死信/Error Topic]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;MQ&lt;/th&gt;
					&lt;th&gt;业务异常处理建议&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;捕获业务异常后，直接返回 &lt;code&gt;CONSUME_SUCCESS&lt;/code&gt; 并记录失败原因，避免无意义重试；或主动放入自定义补偿 Topic。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;业务异常时 &lt;code&gt;basic.nack(requeue=false)&lt;/code&gt; 直接进死信，不要在 RabbitMQ 里反复重试业务错误。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;业务异常写入 Error Topic，由补偿服务按业务规则处理；Consumer 继续消费后续消息，避免阻塞 Partition。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Redis 不适合复杂异常处理；业务异常建议直接记录到数据库或日志，人工介入。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;业务异常兜底策略&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;记录失败明细&lt;/strong&gt;：消息内容、异常原因、时间、Consumer 实例、业务 Key。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人工补偿平台&lt;/strong&gt;：按业务 Key 重投、跳过、标记已处理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态机兜底&lt;/strong&gt;：订单等核心业务要有最终一致性校验。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;告警分级&lt;/strong&gt;：死信队列增长、消费停滞、重试频繁分级告警。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不要无限重试业务异常&lt;/strong&gt;：参数错误重试 16 次没有意义。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;65-消息卡住消费停滞&#34;&gt;6.5 消息卡住/消费停滞&lt;/h3&gt;
&lt;p&gt;消费停滞是四种 MQ 都会遇到的异常，但原因和处理方式各有侧重：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;MQ&lt;/th&gt;
					&lt;th&gt;常见原因&lt;/th&gt;
					&lt;th&gt;处理手段&lt;/th&gt;
					&lt;th&gt;监控指标&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Consumer 实例少、单条处理慢、Consumer 宕机、下游依赖慢&lt;/td&gt;
					&lt;td&gt;扩容 Consumer（不超过 Queue 数）、优化消费逻辑、限流、降级&lt;/td&gt;
					&lt;td&gt;ConsumeProgress 堆积量、消费 TPS&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;队列堆积导致内存/磁盘告警、Consumer 连接断开、Channel 阻塞&lt;/td&gt;
					&lt;td&gt;扩容 Consumer、控制生产速度、启用队列长度限制&lt;/td&gt;
					&lt;td&gt;Queue 深度、内存使用率、磁盘告警&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Partition 消费滞后、Consumer Rebalance 频繁、单 Partition 热点&lt;/td&gt;
					&lt;td&gt;增加 Partition、优化 Key 设计、调整 &lt;code&gt;session.timeout.ms&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Consumer Lag、Rebalance 频率&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;内存不足、Consumer 断线（PubSub 丢消息）、处理慢&lt;/td&gt;
					&lt;td&gt;控制队列长度、设置过期时间、用 Stream 替代 PubSub&lt;/td&gt;
					&lt;td&gt;Redis 内存、Pending List 长度&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[消息堆积] --&amp;gt; B{原因}
    B --&amp;gt;|Consumer 少| C[扩容 Consumer]
    B --&amp;gt;|单条处理慢| D[优化消费逻辑/异步化]
    B --&amp;gt;|Consumer 宕机| E[心跳超时触发重平衡]
    B --&amp;gt;|下游依赖慢| F[限流/降级/异步处理]
    B --&amp;gt;|Partition/Queue 热点| G[调整 Key 或增加分区]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;66-顺序消息异常&#34;&gt;6.6 顺序消息异常&lt;/h3&gt;
&lt;p&gt;顺序消息一旦某条处理卡住，后续消息都会被阻塞，四种 MQ 的处理方式不同：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;MQ&lt;/th&gt;
					&lt;th&gt;顺序模型&lt;/th&gt;
					&lt;th&gt;异常影响&lt;/th&gt;
					&lt;th&gt;处理建议&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Sharding Key 路由到同一 MessageQueue，单线程消费&lt;/td&gt;
					&lt;td&gt;一条失败会阻塞整个 Queue 的后续消息&lt;/td&gt;
					&lt;td&gt;设置消费超时；失败次数过多时考虑跳过或转移；业务上保证单条处理轻量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;单 Queue 天然有序，单 Consumer 单线程消费&lt;/td&gt;
					&lt;td&gt;一个 Consumer 卡住会阻塞整个 Queue&lt;/td&gt;
					&lt;td&gt;控制单条处理时间；必要时拆分多个 Queue 做局部顺序&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;同一 Partition 内有序，单 Consumer 消费 Partition&lt;/td&gt;
					&lt;td&gt;一条消息处理慢会阻塞整个 Partition&lt;/td&gt;
					&lt;td&gt;合理设计 Key，避免单个 Partition 成为热点；业务异常时写入 Error Topic 避免阻塞&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Redis MQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Stream/ List 单节点内有序&lt;/td&gt;
					&lt;td&gt;单 Consumer 卡住会阻塞后续消费&lt;/td&gt;
					&lt;td&gt;不建议用 Redis 做强顺序消息；处理异常时直接记录并人工处理&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[Queue/Partition 内顺序消费] --&amp;gt; B[消息 1 处理失败或超慢]
    B --&amp;gt; C[消息 2 等待]
    C --&amp;gt; D[消息 3 等待]
    B --&amp;gt; E{如何处理?}
    E --&amp;gt;|跳过| F[破坏顺序性]
    E --&amp;gt;|重试| G[阻塞后续消息]
    E --&amp;gt;|转移| H[进死信/Error Topic]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;顺序消息异常处理原则&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;只在真正需要顺序的场景使用顺序消息。&lt;/li&gt;
&lt;li&gt;单条消息处理要轻量，避免长耗时阻塞队列。&lt;/li&gt;
&lt;li&gt;业务上设计「局部顺序」而不是「全局顺序」。&lt;/li&gt;
&lt;li&gt;顺序消息失败时，优先考虑业务补偿，而不是无限重试或简单跳过。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七总结&#34;&gt;七、总结&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;选型不是单选题&lt;/strong&gt;：RocketMQ 适合在线业务，Kafka 适合日志/流处理，RabbitMQ 适合轻量快速落地，Redis MQ 适合轻量辅助场景。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;推/拉不是对立关系&lt;/strong&gt;：RocketMQ 的 Push 底层是长轮询 Pull；RabbitMQ 是真 Push；Kafka 是真 Pull。选择看「谁来控制消费节奏」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;长连接是双刃剑&lt;/strong&gt;：实时性好，但连接维护、背压、心跳都要考虑。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异常处理要分层&lt;/strong&gt;：发送层确认、Broker 层持久化、消费层幂等 + 重试 + 死信。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;业务异常要兜底&lt;/strong&gt;：区分可重试与不可重试，建立补偿机制和人工介入平台。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;避坑靠规范&lt;/strong&gt;：订阅一致、消息体小、顺序消息慎用、监控到位、版本一致。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://ftmao.com/blog/blog/posts/rocketmq-fundamentals/&#34;&gt;RocketMQ 基础科普：推/拉/通知模式、异常处理与高并发实践&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;《RocketMQ 实战与核心原理》&lt;/li&gt;
&lt;li&gt;《RocketMQ 技术内幕》&lt;/li&gt;
&lt;li&gt;《Kafka 权威指南》&lt;/li&gt;
&lt;li&gt;《RabbitMQ 实战指南》&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;如果对你有帮助，欢迎在评论区交流你在 MQ 选型或异常处理上的经验。&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>RocketMQ 基础科普：推/拉/通知模式、异常处理与高并发实践</title>
      <link>https://ftmao.com/blog/posts/rocketmq-fundamentals/</link>
      <pubDate>Sun, 28 Jun 2020 10:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/rocketmq-fundamentals/</guid>
      <description>&lt;h1 id=&#34;rocketmq-基础科普推拉通知模式异常处理与高并发实践&#34;&gt;RocketMQ 基础科普：推/拉/通知模式、异常处理与高并发实践&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;这篇文章把 RocketMQ 当成一个「分布式异步任务管道」来理解，重点回答六个问题：RocketMQ 和 RabbitMQ、Kafka 怎么选？它们的底层原理差异是什么？消费者到底该推、该拉还是该通知？消息异常了怎么处理？怎么让它扛住高并发？以及那些年我们踩过的坑。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一rocketmq-是什么一句话定位&#34;&gt;一、RocketMQ 是什么？一句话定位&lt;/h2&gt;
&lt;p&gt;RocketMQ 是阿里巴巴开源的&lt;strong&gt;分布式消息中间件&lt;/strong&gt;，核心定位是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;高吞吐、低延迟、可堆积、可扩展的异步消息传输与解耦基础设施。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它通常被用来解决三类问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;解耦&lt;/strong&gt;：调用方发完消息即可返回，不用等下游处理完。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步&lt;/strong&gt;：把非核心链路从同步路径中剥离，比如发券、发短信、记日志。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;削峰填谷&lt;/strong&gt;：突发流量先写入队列，下游按自身能力消费。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;RocketMQ 的核心角色很简单：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    Producer[&amp;#34;Producer（消息生产者）&amp;#34;]
    NameServer[&amp;#34;NameServer（路由发现）&amp;#34;]
    Broker[&amp;#34;Broker（存储与转发消息）&amp;#34;]
    Consumer[&amp;#34;Consumer（拉取/接收消息）&amp;#34;]

    Producer -.路由发现.-&amp;gt; NameServer
    Producer --&amp;gt; Broker
    Consumer -.路由发现.-&amp;gt; NameServer
    Broker --&amp;gt; Consumer&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Producer&lt;/strong&gt;：消息生产者，负责把业务消息发到 Broker。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Broker&lt;/strong&gt;：消息存储和转发节点，分 Master/Slave，负责持久化、投递、重试。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NameServer&lt;/strong&gt;：轻量级路由注册中心，Producer 和 Consumer 通过它发现 Broker。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consumer&lt;/strong&gt;：消息消费者，从 Broker 读取消息并处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二横向对比rocketmq--rabbitmq--kafka&#34;&gt;二、横向对比：RocketMQ / RabbitMQ / Kafka&lt;/h2&gt;
&lt;p&gt;RocketMQ、RabbitMQ、Kafka 是国内最常见的三种消息中间件。它们都能做异步解耦，但设计哲学差异很大，选型时要结合业务场景、团队能力、运维成本一起看。&lt;/p&gt;
&lt;h3 id=&#34;21-核心定位差异&#34;&gt;2.1 核心定位差异&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;RocketMQ&lt;/th&gt;
					&lt;th&gt;RabbitMQ&lt;/th&gt;
					&lt;th&gt;Kafka&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;出身与设计目标&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;阿里开源，面向在线交易/金融级消息&lt;/td&gt;
					&lt;td&gt;Erlang 实现，面向通用企业消息&lt;/td&gt;
					&lt;td&gt;LinkedIn 开源，面向日志采集与流处理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;数据模型&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Topic + Queue，支持 Tag 过滤&lt;/td&gt;
					&lt;td&gt;Exchange + Queue，路由灵活&lt;/td&gt;
					&lt;td&gt;Topic + Partition，分区有序&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;默认消费方式&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Push（长轮询封装）+ Pull&lt;/td&gt;
					&lt;td&gt;Push（AMQP 推送）&lt;/td&gt;
					&lt;td&gt;Pull（消费者主动拉取）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;顺序消息&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;分片内有序，Sharding Key 控制&lt;/td&gt;
					&lt;td&gt;单 Queue 有序&lt;/td&gt;
					&lt;td&gt;Partition 内有序&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;延迟消息&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;原生支持 18 个级别&lt;/td&gt;
					&lt;td&gt;需插件或死信实现&lt;/td&gt;
					&lt;td&gt;不原生支持，需借助外部组件&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;事务消息&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;原生支持&lt;/td&gt;
					&lt;td&gt;不支持原生事务消息&lt;/td&gt;
					&lt;td&gt;不支持原生事务消息&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;消息轨迹&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;原生支持&lt;/td&gt;
					&lt;td&gt;需额外配置&lt;/td&gt;
					&lt;td&gt;需额外组件&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;22-性能对比&#34;&gt;2.2 性能对比&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;RocketMQ&lt;/th&gt;
					&lt;th&gt;RabbitMQ&lt;/th&gt;
					&lt;th&gt;Kafka&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;单机吞吐&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;10 万级 TPS&lt;/td&gt;
					&lt;td&gt;万级 TPS&lt;/td&gt;
					&lt;td&gt;百万级 TPS（批量场景）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;延迟&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;毫秒级&lt;/td&gt;
					&lt;td&gt;微秒-毫秒级&lt;/td&gt;
					&lt;td&gt;毫秒级，批量时更高&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;消息堆积能力&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;强，适合削峰&lt;/td&gt;
					&lt;td&gt;一般，堆积过多影响性能&lt;/td&gt;
					&lt;td&gt;极强，专为日志设计&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;批量效率&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;中等&lt;/td&gt;
					&lt;td&gt;一般&lt;/td&gt;
					&lt;td&gt;极高&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;说明&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kafka 的吞吐数字通常来自批量、压缩、顺序写的日志场景；单条小消息低延迟不如 RocketMQ。&lt;/li&gt;
&lt;li&gt;RabbitMQ 延迟低，但高吞吐和海量堆积不是强项。&lt;/li&gt;
&lt;li&gt;RocketMQ 在「中等吞吐 + 低延迟 + 强堆积」之间取得了较好平衡。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;23-成本对比&#34;&gt;2.3 成本对比&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;RocketMQ&lt;/th&gt;
					&lt;th&gt;RabbitMQ&lt;/th&gt;
					&lt;th&gt;Kafka&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;部署复杂度&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;中等（NameServer + Broker 集群）&lt;/td&gt;
					&lt;td&gt;低（单节点即可运行）&lt;/td&gt;
					&lt;td&gt;高（ZooKeeper/KRaft + Broker）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;运维成本&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;中等，阿里系文档丰富&lt;/td&gt;
					&lt;td&gt;低，但 Erlang 问题排查门槛高&lt;/td&gt;
					&lt;td&gt;高，调优项多，需要专人维护&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;云服务成熟度&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;阿里云 RocketMQ 成熟&lt;/td&gt;
					&lt;td&gt;各云厂商都有托管版&lt;/td&gt;
					&lt;td&gt;各云厂商 Kafka 托管版成熟&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;学习曲线&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;中等&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
					&lt;td&gt;高&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;24-生态对比&#34;&gt;2.4 生态对比&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;RocketMQ&lt;/th&gt;
					&lt;th&gt;RabbitMQ&lt;/th&gt;
					&lt;th&gt;Kafka&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;语言客户端&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Java 最完善，其他语言有社区版&lt;/td&gt;
					&lt;td&gt;极其丰富，几乎所有语言&lt;/td&gt;
					&lt;td&gt;极其丰富，几乎所有语言&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;大数据生态&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;一般，可与 Flink/Spark 对接&lt;/td&gt;
					&lt;td&gt;弱&lt;/td&gt;
					&lt;td&gt;极强，流处理事实标准&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;监控工具&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;自带控制台 + 阿里云监控&lt;/td&gt;
					&lt;td&gt;自带 Management UI + Prometheus&lt;/td&gt;
					&lt;td&gt;Kafka UI + Prometheus + 自建&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;社区活跃度&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;国内活跃，Apache 项目&lt;/td&gt;
					&lt;td&gt;成熟稳定，Pivotal/VMware 背景&lt;/td&gt;
					&lt;td&gt;极其活跃，Confluent 生态&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;25-适用场景推荐&#34;&gt;2.5 适用场景推荐&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;推荐&lt;/th&gt;
					&lt;th&gt;原因&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;电商/金融订单、交易消息&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;延迟低、事务消息、顺序消息、监控完善&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;异步任务、分布式 Worker、视频渲染&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;PushConsumer 自动负载均衡，失败重试完善&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;传统企业应用、RPC 解耦、路由复杂&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;简单易用，Exchange 路由灵活，快速上线&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;日志采集、埋点、实时数仓、流处理&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;吞吐和生态碾压，分区模型适合流计算&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;事件总线、多语言异构系统&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ / Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;客户端生态更丰富&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;需要事务消息且不想自己实现&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;原生事务消息是差异化能力&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;26-一句话选型建议&#34;&gt;2.6 一句话选型建议&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;要可靠交易、事务消息、顺序消息、在线业务&lt;/strong&gt; → RocketMQ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;要快速搭建、路由灵活、团队规模小&lt;/strong&gt; → RabbitMQ&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;要日志/流处理/大数据管道、吞吐优先&lt;/strong&gt; → Kafka&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;很多大厂内部其实是「Kafka 做日志流 + RocketMQ 做业务消息 + RabbitMQ 做轻量任务」组合使用，而不是单选题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;27-底层原理与核心差异&#34;&gt;2.7 底层原理与核心差异&lt;/h3&gt;
&lt;p&gt;表面的功能差异（延迟消息、事务消息）背后，是三种产品在&lt;strong&gt;存储模型、路由发现、复制机制、消费模型&lt;/strong&gt;上的根本不同。理解这些底层差异，才能真正解释「为什么 Kafka 吞吐高」「为什么 RocketMQ 延迟低」「为什么 RabbitMQ 路由灵活」。&lt;/p&gt;
&lt;h4 id=&#34;存储模型&#34;&gt;存储模型&lt;/h4&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;存储结构&lt;/th&gt;
					&lt;th&gt;核心特点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;CommitLog + ConsumeQueue&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;所有 Topic 的消息顺序写入同一个 CommitLog，再利用 ConsumeQueue 存储每个 Queue 的偏移索引。读消息时先查 ConsumeQueue 拿到物理偏移，再读 CommitLog。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Partition Segment + Index&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;每个 Partition 是一个独立的日志目录，顺序写入 Segment 文件，配合稀疏索引加速消费。Partition 之间物理隔离。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Queue 独立存储&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;每个 Queue 维护独立的消息索引和存储，默认写入 Mnesia/ETS，持久化消息写磁盘。Queue 越多，元数据开销越大。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键差异&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RocketMQ 的 CommitLog 是全局顺序写&lt;/strong&gt;，不管有多少 Topic/Queue，磁盘写入都是顺序的，因此单机 I/O 效率很高；读取时需要两次 I/O（ConsumeQueue → CommitLog），但 ConsumeQueue 很小，通常能缓存命中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kafka 的 Partition 是物理隔离的&lt;/strong&gt;，每个 Partition 内部顺序写，但 Partition 多了会形成随机写，所以 Kafka 更适合少量 Topic + 大量 Partition 的日志场景。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RabbitMQ 的 Queue 是逻辑和物理都独立的&lt;/strong&gt;，每条消息进入 Queue 都要维护索引，高吞吐下容易成为瓶颈。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;RocketMQ 存储模型：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    CL[&amp;#34;CommitLog（顺序写）&amp;lt;br/&amp;gt;[msg1][msg2][msg3][msg4][msg5]...&amp;#34;]
    CQ1[&amp;#34;ConsumeQueue&amp;lt;br/&amp;gt;TopicA-Q0&amp;#34;]
    CQ2[&amp;#34;ConsumeQueue&amp;lt;br/&amp;gt;TopicB-Q0&amp;#34;]

    CL -- &amp;#34;写入后分发偏移索引&amp;#34; --&amp;gt; CQ1
    CL -- &amp;#34;写入后分发偏移索引&amp;#34; --&amp;gt; CQ2&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;Kafka 存储模型：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    P0[&amp;#34;TopicA-P0 Log&amp;lt;br/&amp;gt;[msg1][msg2]...&amp;#34;]
    P1[&amp;#34;TopicA-P1 Log&amp;lt;br/&amp;gt;[msg1][msg2]...&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h4 id=&#34;路由与元数据管理&#34;&gt;路由与元数据管理&lt;/h4&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;注册/路由中心&lt;/th&gt;
					&lt;th&gt;设计哲学&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;NameServer&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;无状态集群，Broker 主动上报路由信息，Producer/Consumer 定时拉取。最终一致，轻量。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;ZooKeeper / KRaft&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;老版本依赖 ZooKeeper 存元数据、选 Controller；新版本用 KRaft 自洽协议。强一致要求更高。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;内置 Mnesia 数据库&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;集群节点共享元数据，Erlang 进程模型天然分布式，但集群扩展性相对有限。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键差异&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NameServer 是「轻量级最终一致」&lt;/strong&gt;：Broker 启动时向所有 NameServer 注册，Producer 从 NameServer 拿到路由后缓存使用。Broker 宕机后，NameServer 不会主动通知 Producer，而是靠 Producer 心跳/发送失败时刷新路由。这种设计牺牲了一定的实时性，换来了极简的部署和无状态扩展能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kafka 的 Controller 负责元数据一致性&lt;/strong&gt;：分区副本分配、Leader 选举、ISR 维护都由 Controller 处理，更复杂但也更精确。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RabbitMQ 的元数据在节点间同步&lt;/strong&gt;：小集群简单，大集群（几百个 Queue）容易出现脑裂和同步压力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;复制与高可用&#34;&gt;复制与高可用&lt;/h4&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;复制方式&lt;/th&gt;
					&lt;th&gt;特点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Master-Slave 同步/异步复制&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;一个 Master 对应一个或多个 Slave。同步复制保证不丢消息，异步复制性能更高。Slave 可读可切换（需要人工或脚本介入）。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Partition 多副本 + ISR 机制&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;每个 Partition 有 N 个副本，Leader 写，Follower 拉取；只有 ISR 中的副本才能竞选 Leader。自动 Failover，成熟度高。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;普通队列 + 镜像队列&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;普通队列只存在于一个节点；镜像队列会把消息复制到多个节点，但吞吐下降明显。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键差异&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RocketMQ 的复制是 Broker 级别&lt;/strong&gt;，Master 上所有 Queue 一起复制到 Slave；Kafka 是 Partition 级别，复制粒度更细。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kafka 的 ISR 是动态维护的&lt;/strong&gt;，写入延迟受最慢 Follower 影响；RocketMQ 的同步复制是 Master 等待 Slave ACK，延迟相对可控。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RabbitMQ 默认不复制&lt;/strong&gt;，需要显式配置镜像队列，否则节点宕机就丢队列。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;消费模型与-offset-管理&#34;&gt;消费模型与 Offset 管理&lt;/h4&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;消费方式&lt;/th&gt;
					&lt;th&gt;Offset 管理&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;长轮询 Pull 封装成 Push&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Consumer 本地维护消费进度，定时上报 Broker。支持集群消费和广播消费。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;消费者主动 Pull&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Offset 存在 Kafka 内部 Topic（&lt;code&gt;__consumer_offsets&lt;/code&gt;），Consumer 提交进度。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Broker Push（AMQP）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;无 Offset 概念，消息 ACK 后从 Queue 移除。不支持消息回溯。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键差异&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RocketMQ 的 Push 是「假 Push」&lt;/strong&gt;：Consumer 向 Broker 发起长轮询请求（默认 5 秒），Broker hold 住连接，有新消息时立即返回，没消息时超时返回再轮询。这样既实现了低延迟，又保留了 Pull 的背压能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kafka 的 Pull 是「真 Pull」&lt;/strong&gt;：Consumer 自己决定什么时候拉、拉多少，框架不负责推送，灵活性最高。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RabbitMQ 的 Push 是「真 Push」&lt;/strong&gt;：Broker 把消息塞给 Channel，Consumer 处理完 ACK。如果 Consumer 处理慢，Broker 会堆积在内存或磁盘，容易把 Broker 压垮。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;顺序消息的实现&#34;&gt;顺序消息的实现&lt;/h4&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;实现方式&lt;/th&gt;
					&lt;th&gt;限制&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;同一 Topic 下，相同 Sharding Key 的消息发送到同一个 Message Queue；Consumer 单线程消费该 Queue&lt;/td&gt;
					&lt;td&gt;全局顺序需要所有消息进一个 Queue，吞吐极低&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;同一 Partition 内有序；Producer 按 Key 路由到固定 Partition&lt;/td&gt;
					&lt;td&gt;同 RocketMQ，Partition 内有序，全局有序不可行&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;单 Queue 天然有序；多个 Consumer 竞争消费时会乱序&lt;/td&gt;
					&lt;td&gt;要顺序消费只能单 Consumer 单线程&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;三种 MQ 的所谓「顺序消息」本质上都是&lt;strong&gt;把需要顺序的消息收敛到同一个最小调度单元&lt;/strong&gt;（Queue / Partition），然后单线程消费。不存在真正的全局顺序高吞吐方案。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&#34;延迟消息的实现&#34;&gt;延迟消息的实现&lt;/h4&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;实现方式&lt;/th&gt;
					&lt;th&gt;特点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;内置 18 个延迟级别，消息先进入 SCHEDULE_TOPIC_XXXX，到期后转回真实 Topic&lt;/td&gt;
					&lt;td&gt;时间粒度固定，不支持任意时间；实现成熟可靠&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;无原生支持&lt;/td&gt;
					&lt;td&gt;常用方案：时间轮、RocketMQ 中转、Pulsar 等替代&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;通过 TTL + 死信队列（DLX）实现&lt;/td&gt;
					&lt;td&gt;每个延迟级别需要一个 Queue，灵活但配置繁琐&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&#34;事务消息的实现&#34;&gt;事务消息的实现&lt;/h4&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;产品&lt;/th&gt;
					&lt;th&gt;实现方式&lt;/th&gt;
					&lt;th&gt;特点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RocketMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;半消息 + 事务回查&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Producer 先发「半消息」（对消费者不可见），本地事务成功后 Commit，失败则 Rollback；Broker 会回查超时事务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;无原生事务消息&lt;/td&gt;
					&lt;td&gt;Kafka 有幂等 Producer 和事务 API，但那是「跨分区事务」，不是「本地事务 + 消息发送」的事务消息&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;RabbitMQ&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;无原生支持&lt;/td&gt;
					&lt;td&gt;业务侧自己用本地事务表 + 定时补偿实现&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;RocketMQ 事务消息的核心流程：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;1. Producer 发送 Half Message 到 Broker&amp;#34;] --&amp;gt; B[&amp;#34;2. Producer 执行本地事务（如扣减库存）&amp;#34;]
    B --&amp;gt; C{&amp;#34;本地事务结果&amp;#34;}
    C --&amp;gt;|&amp;#34;成功&amp;#34;| D[&amp;#34;Commit&amp;#34;]
    C --&amp;gt;|&amp;#34;失败&amp;#34;| E[&amp;#34;Rollback&amp;#34;]
    D --&amp;gt; F[&amp;#34;3. Broker 投递消息给消费者&amp;#34;]
    E --&amp;gt; G[&amp;#34;3. Broker 删除半消息&amp;#34;]
    C -. &amp;#34;Producer 无响应&amp;#34; .-&amp;gt; H[&amp;#34;Broker 主动回查事务状态&amp;#34;]
    H --&amp;gt; C&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h4 id=&#34;为什么-rocketmq-更适合在线业务&#34;&gt;为什么 RocketMQ 更适合在线业务？&lt;/h4&gt;
&lt;p&gt;把底层差异串起来看，答案就清晰了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CommitLog + ConsumeQueue 让它在消息量不大时延迟很低&lt;/strong&gt;（两次索引查询 + 顺序读），适合在线交易这种「消息体小、QPS 高、延迟敏感」的场景。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NameServer 轻量无状态&lt;/strong&gt;，部署和扩容简单，不像 Kafka 强依赖 ZooKeeper/KRaft。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原生事务消息和延迟消息&lt;/strong&gt;，是电商、金融场景的刚需，其他两个 MQ 都需要业务侧自己造轮子。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;长轮询 Push 模型&lt;/strong&gt;对业务开发者友好，自动重平衡、失败重试、死信队列开箱即用。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而 Kafka 更适合&lt;strong&gt;海量日志、流计算&lt;/strong&gt;这种「吞吐优先、延迟可接受、需要分区有序」的场景；RabbitMQ 更适合&lt;strong&gt;轻量解耦、路由复杂、快速上线&lt;/strong&gt;的场景。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三推拉通知三种消费模式怎么选&#34;&gt;三、推、拉、通知三种消费模式：怎么选？&lt;/h2&gt;
&lt;p&gt;RocketMQ 的消费端主要提供 &lt;strong&gt;Push&lt;/strong&gt; 和 &lt;strong&gt;Pull&lt;/strong&gt; 两种消费方式，实际工程里还经常配合 &lt;strong&gt;Notify/回调&lt;/strong&gt; 一起用。三者不是非此即彼，而是适用场景不同。&lt;/p&gt;
&lt;h3 id=&#34;31-pull-模式消费者主动拉取&#34;&gt;3.1 Pull 模式：消费者主动拉取&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant C as Consumer
    participant B as Broker
    C-&amp;gt;&amp;gt;B: 有消息吗？
    B-&amp;gt;&amp;gt;C: 有，拿去吧&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消费者按自己的节奏拉消息，控制权在消费端。&lt;/li&gt;
&lt;li&gt;可以灵活控制拉取频率、批量大小、并发量。&lt;/li&gt;
&lt;li&gt;代码稍复杂，需要自己维护 offset、拉取循环、负载均衡。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;适合场景&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消费速度远小于生产速度，需要严格控速。&lt;/li&gt;
&lt;li&gt;批量处理、定时任务、数据同步类场景。&lt;/li&gt;
&lt;li&gt;对实时性要求不高，或者消费逻辑很重。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;权衡&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;控制力强，可背压&lt;/td&gt;
					&lt;td&gt;实现复杂，易写出空轮询&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;消费节奏自主&lt;/td&gt;
					&lt;td&gt;实时性依赖拉取间隔&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;适合批量/重计算&lt;/td&gt;
					&lt;td&gt;需要自管 offset 和重平衡&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;32-push-模式broker-主动推送给消费者&#34;&gt;3.2 Push 模式：Broker 主动推送给消费者&lt;/h3&gt;
&lt;p&gt;RocketMQ 的 PushConsumer 本质上也是 &lt;strong&gt;Pull 的长轮询封装&lt;/strong&gt;，但对业务代码来说更像「Broker 推过来」。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant C as Consumer
    participant B as Broker
    C-&amp;gt;&amp;gt;B: 注册长轮询
    B-&amp;gt;&amp;gt;C: 来消息了，处理一下&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用简单，业务只写一个回调函数。&lt;/li&gt;
&lt;li&gt;RocketMQ 自动处理 offset、重平衡、失败重试。&lt;/li&gt;
&lt;li&gt;实时性好，能立刻感知新消息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;适合场景&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;大多数在线业务场景，尤其是希望「发完就不用管」的时候。&lt;/li&gt;
&lt;li&gt;需要自动负载均衡和失败重试的团队。&lt;/li&gt;
&lt;li&gt;消费逻辑相对轻量、可并发扩展。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;权衡&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;使用简单，自动重平衡&lt;/td&gt;
					&lt;td&gt;对消费速度有隐性要求，太慢会堆积&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;实时性好&lt;/td&gt;
					&lt;td&gt;默认并发策略可能不适合重任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;失败重试原生支持&lt;/td&gt;
					&lt;td&gt;需要理解线程模型，否则容易踩坑&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;33-notify--回调模式处理完主动通知上游&#34;&gt;3.3 Notify / 回调模式：处理完主动通知上游&lt;/h3&gt;
&lt;p&gt;消息队列本身不负责回调，但业务常把 MQ 和回调配合起来用：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[&amp;#34;上游&amp;#34;] --&amp;gt; MQ[&amp;#34;MQ&amp;#34;] --&amp;gt; C[&amp;#34;消费者处理&amp;#34;] --&amp;gt; N[&amp;#34;回调 / 事件总线 / SSE&amp;#34;] --&amp;gt; U[&amp;#34;上游或其他系统&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不是 RocketMQ 原生消费模式，而是业务架构模式。&lt;/li&gt;
&lt;li&gt;适合「异步任务完成后需要通知调用方」的场景，比如视频渲染、订单状态变更。&lt;/li&gt;
&lt;li&gt;通常需要配合幂等、状态机、重试策略一起设计。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;适合场景&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任务完成后需要反向通知 UI、APP、第三方系统。&lt;/li&gt;
&lt;li&gt;长耗时异步任务 + 进度推送。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;34-选择原则总结&#34;&gt;3.4 选择原则总结&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;推荐模式&lt;/th&gt;
					&lt;th&gt;原因&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;普通异步解耦、实时性要求一般&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;PushConsumer&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;简单、自动、够用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;消费很重、需要严格控速/批量&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;PullConsumer&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;控制力强，避免被消息压垮&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据同步、ETL、定时批量&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Pull / 批量拉取&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;按批次处理更高效&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;异步任务完成后要通知调用方&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;Push + 业务回调/Notify&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;MQ 解耦 + 回调闭环&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;不确定怎么选&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;先 Push，遇到瓶颈再切 Pull&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Push 是默认最佳实践&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一个常见误区是认为 Push 一定比 Pull 先进。实际上 RocketMQ 的 Push 底层也是拉，只是框架帮你做了。真正决定选型的不是「推或拉」，而是 &lt;strong&gt;「谁来控制消费节奏」和「实时性与吞吐的优先级」&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四异常处理消息丢了重复了卡住了怎么办&#34;&gt;四、异常处理：消息丢了、重复了、卡住了怎么办？&lt;/h2&gt;
&lt;p&gt;消息队列的异常处理是面试和工程中最核心的部分。RocketMQ 提供了机制，但业务层必须配合。&lt;/p&gt;
&lt;h3 id=&#34;41-消息丢失从哪里可能丢&#34;&gt;4.1 消息丢失：从哪里可能丢？&lt;/h3&gt;
&lt;p&gt;消息丢失通常发生在三个环节：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    P[&amp;#34;Producer&amp;#34;] -- &amp;#34;发送失败&amp;#34; --&amp;gt; B[&amp;#34;Broker&amp;#34;] -- &amp;#34;刷盘/同步失败&amp;#34; --&amp;gt; C[&amp;#34;Consumer&amp;#34;] -- &amp;#34;消费失败未重试&amp;#34; --&amp;gt; Biz[&amp;#34;业务&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;防范措施&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;环节&lt;/th&gt;
					&lt;th&gt;措施&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Producer 发送&lt;/td&gt;
					&lt;td&gt;同步发送 + 失败重试&lt;/td&gt;
					&lt;td&gt;重要消息用 &lt;code&gt;send_sync&lt;/code&gt;，不要用 oneway&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Broker 存储&lt;/td&gt;
					&lt;td&gt;同步刷盘 + 主从同步&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;SYNC_MASTER&lt;/code&gt; + &lt;code&gt;SYNC_FLUSH&lt;/code&gt; 保证落盘&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Consumer 消费&lt;/td&gt;
					&lt;td&gt;先处理业务再返回成功&lt;/td&gt;
					&lt;td&gt;不要先 ACK 再执行业务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;极端情况&lt;/td&gt;
					&lt;td&gt;业务对账/补偿&lt;/td&gt;
					&lt;td&gt;消息 + 数据库状态机双写，定期对账&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;RocketMQ 的发送确认策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SYNC&lt;/strong&gt;：同步等待 Broker ACK，最可靠但最慢。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ASYNC&lt;/strong&gt;：异步发送，失败时回调，吞吐高。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ONEWAY&lt;/strong&gt;：只发不管，最快但不可靠，适合日志等可丢场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;42-消息重复不可避免靠幂等解决&#34;&gt;4.2 消息重复：不可避免，靠幂等解决&lt;/h3&gt;
&lt;p&gt;RocketMQ 保证「至少一次投递」，不保证「恰好一次」。网络抖动、Broker 重试、Consumer 重启都会导致重复消费。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;幂等设计要点&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;唯一业务 Key&lt;/strong&gt;：发送时给消息设置 &lt;code&gt;keys&lt;/code&gt;，消费时用业务 Key 去重。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据库唯一索引&lt;/strong&gt;：把业务 Key 作为幂等表的唯一键，重复插入会失败。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态机防重&lt;/strong&gt;：如订单状态只能 &lt;code&gt;pending → paid → shipped&lt;/code&gt;，重复消息不会触发非法流转。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis 去重&lt;/strong&gt;：短期用 &lt;code&gt;SETNX msg_key 1&lt;/code&gt; 配合过期时间，适合无数据库或高速场景。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 伪代码：基于数据库唯一索引做幂等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;consume&lt;/span&gt;(msg):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    biz_key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; msg&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;keys
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        idempotent_record&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;insert(biz_key&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;biz_key, status&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processing&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; UniqueViolation:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ConsumeStatus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;CONSUME_SUCCESS  &lt;span style=&#34;color:#75715e&#34;&gt;# 已处理过，直接成功&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        do_business(msg)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        idempotent_record&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;update(biz_key, status&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;done&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ConsumeStatus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;CONSUME_SUCCESS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Exception&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        idempotent_record&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;update(biz_key, status&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failed&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ConsumeStatus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;RECONSUME_LATER&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;43-消费失败重试与死信队列&#34;&gt;4.3 消费失败：重试与死信队列&lt;/h3&gt;
&lt;p&gt;RocketMQ 对消费失败的消息会自动重试，默认最多 16 次，间隔逐渐拉长。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;重试间隔（默认值，Broker 端可配置）&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;第几次&lt;/th&gt;
					&lt;th&gt;间隔&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;10 秒&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;30 秒&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;1 分钟&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
					&lt;td&gt;递增&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;16&lt;/td&gt;
					&lt;td&gt;约 2 小时&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;重试仍然失败后，消息进入 &lt;strong&gt;死信队列（DLQ）&lt;/strong&gt;，Topic 名为 &lt;code&gt;%DLQ%consumer_group&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;处理建议&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不要无脑重试&lt;/strong&gt;：如果是参数错误、依赖服务永久不可用，重试再多次也没用，应该直接进死信。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;死信要告警+人工介入&lt;/strong&gt;：DLQ 不是垃圾桶，需要监控和补偿机制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;区分可重试异常和不可重试异常&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;网络超时 → 可重试&lt;/li&gt;
&lt;li&gt;参数非法 / 依赖返回 4xx / 业务规则冲突 → 不可重试，直接失败或进死信&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;consume&lt;/span&gt;(msg):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        process(msg)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ConsumeStatus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;CONSUME_SUCCESS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; RetryableException &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 可重试异常：网络抖动、依赖短暂不可用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;warn(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;retryable: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;e&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ConsumeStatus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;RECONSUME_LATER
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; NonRetryableException &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 不可重试异常：直接进死信，避免浪费重试次数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;error(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;non-retryable: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;e&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 某些客户端可通过返回特定状态或手动移入死信&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ConsumeStatus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;CONSUME_SUCCESS  &lt;span style=&#34;color:#75715e&#34;&gt;# 业务侧兜底，记录失败原因&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;44-消息卡住消费超时与心跳检测&#34;&gt;4.4 消息卡住：消费超时与心跳检测&lt;/h3&gt;
&lt;p&gt;Consumer 处理到一半进程挂了，消息状态可能卡在「处理中」。《RocketMQ 技术内幕》里强调：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;消息队列只保证投递，不保证业务逻辑一定完成。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以业务层需要做：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;消费超时控制&lt;/strong&gt;：给单条消息设置最大处理时间，超时强制释放或重试。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;心跳与任务认领&lt;/strong&gt;：Consumer 处理任务时定时更新心跳，超时时由兜底任务重置状态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;进度监控&lt;/strong&gt;：关注消费进度（ConsumeProgress），发现停滞及时告警。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 伪代码：心跳续命 + 超时释放&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;process_task&lt;/span&gt;(task_id):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    claim_task(task_id, worker_id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;WORKER_ID, ttl&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; heartbeat_renewal(task_id, interval&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            do_heavy_work(task_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        mark_done(task_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;except&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Exception&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        release_task(task_id)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;raise&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;五如何支撑高并发&#34;&gt;五、如何支撑高并发？&lt;/h2&gt;
&lt;p&gt;RocketMQ 本身的吞吐很高（单机万级 TPS 没问题），但业务侧能不能撑住高并发，取决于怎么用它。&lt;/p&gt;
&lt;h3 id=&#34;51-生产者侧优化&#34;&gt;5.1 生产者侧优化&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;手段&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;批量发送&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;把小消息攒成一批发送，减少 RTT&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;异步发送&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;关键路径用 &lt;code&gt;send_async&lt;/code&gt;，失败回调补偿&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;多 Producer 实例&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;生产端水平扩展，分摊发送压力&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;合理选择 Topic/Queue 数量&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Queue 数影响并行度，太多会增加元数据开销&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;关闭不必要的消息轨迹&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;非核心场景关闭 msg_trace 减少开销&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;52-broker-侧优化&#34;&gt;5.2 Broker 侧优化&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;手段&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;集群部署&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;多 Master 多 Slave，避免单点&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;读写分离（Slave 读）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;消费压力大时，从 Slave 拉取减轻 Master 压力&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;异步刷盘&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ASYNC_FLUSH&lt;/code&gt; 性能更高，但可能丢少量消息&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;分片存储（CommitLog）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;利用顺序写磁盘，提升吞吐&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;JVM/网卡/磁盘调优&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;消息队列是 IO 密集型，磁盘 SSD、网卡万兆是基础&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;53-消费者侧优化&#34;&gt;5.3 消费者侧优化&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;手段&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;增加 Consumer 实例&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;消费组内实例数 ≤ Queue 数时，扩容能线性提升吞吐&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;提高单实例并发&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;PushConsumer 可配置 consumeThreadMin/Max&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;批量消费&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;一次拉取多条，合并数据库/Redis 操作&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;消费逻辑异步化&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;IO 密集型任务不要阻塞消费线程&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;本地缓存热点数据&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;减少重复 RPC/DB 查询&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键公式&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;总消费吞吐 = Consumer 实例数 × 每个实例的并发线程数 × 单线程处理 TPS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;当 Consumer 实例数达到 Topic 的 Queue 数后，再增加实例也无法提升并行度，这时需要增加 Queue 数或优化单线程处理速度。&lt;/p&gt;
&lt;h3 id=&#34;54-削峰填谷的核心思想&#34;&gt;5.4 削峰填谷的核心思想&lt;/h3&gt;
&lt;p&gt;高并发不是无限扩容，而是&lt;strong&gt;用队列把流量削平&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[&amp;#34;突发流量&amp;#34;] --&amp;gt; B[&amp;#34;Broker 队列堆积&amp;lt;br/&amp;gt;（容忍峰值）&amp;#34;] --&amp;gt; C[&amp;#34;Consumer 按稳定速率消费&amp;lt;br/&amp;gt;（保护下游）&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;所以设计高并发系统时，Queue 的堆积能力本身就是「容量缓冲」。只要 Consumer 能最终追上来，系统就是健康的。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六避坑指南&#34;&gt;六、避坑指南&lt;/h2&gt;
&lt;h3 id=&#34;61-消费组订阅不一致&#34;&gt;6.1 消费组订阅不一致&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;坑&lt;/strong&gt;：同一个 ConsumerGroup 下的不同实例订阅了不同的 Topic 或 Tag，导致重平衡混乱。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：一个 ConsumerGroup 只订阅一个 Topic + 一套 Tag 表达式，不要随意变更。&lt;/p&gt;
&lt;h3 id=&#34;62-tag-用得太细&#34;&gt;6.2 Tag 用得太细&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;坑&lt;/strong&gt;：每个业务场景都建一个 Tag，结果消费者端过滤复杂，Topic 管理混乱。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：Topic 按业务域划分，Tag 做粗粒度过滤。不要用一个 Topic 承载完全无关的业务。&lt;/p&gt;
&lt;h3 id=&#34;63-消息体过大&#34;&gt;6.3 消息体过大&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;坑&lt;/strong&gt;：把完整对象、图片二进制、大 JSON 塞进消息体，超过 4MB 默认限制，发送失败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：消息体只传 ID 和必要字段，完整数据由 Consumer 从存储（DB/Redis/OSS）拉取。&lt;/p&gt;
&lt;h3 id=&#34;64-顺序消息误用&#34;&gt;6.4 顺序消息误用&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;坑&lt;/strong&gt;：为了「简单」把所有消息都当顺序消息发，结果全局顺序严重拖垮吞吐。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：RocketMQ 的顺序消息是「分片内有序」，不是全局有序。只在真正需要局部顺序的场景用（比如同一订单的操作按顺序处理），并且用业务 Key 做 Sharding。&lt;/p&gt;
&lt;h3 id=&#34;65-忽视-nameserver-路由更新延迟&#34;&gt;6.5 忽视 NameServer 路由更新延迟&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;坑&lt;/strong&gt;：Broker 扩缩容后，Producer/Consumer 还没刷新路由，导致发送到已下线的 Broker。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：理解 NameServer 是最终一致的路由发现，扩缩容时留足等待时间或主动触发重连。&lt;/p&gt;
&lt;h3 id=&#34;66-producerconsumer-启动顺序问题&#34;&gt;6.6 Producer/Consumer 启动顺序问题&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;坑&lt;/strong&gt;：Consumer 先启动但 Topic 还没创建，订阅失败；或 Producer 先启动但 NameServer 还没 ready。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：生产环境用自动化方式提前创建 Topic 和 ConsumerGroup，不要依赖自动创建。&lt;/p&gt;
&lt;h3 id=&#34;67-忽视监控与告警&#34;&gt;6.7 忽视监控与告警&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;核心监控指标&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;指标&lt;/th&gt;
					&lt;th&gt;意义&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;消息堆积量（Consumer Lag）&lt;/td&gt;
					&lt;td&gt;是否需要扩容 Consumer&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;消费 TPS&lt;/td&gt;
					&lt;td&gt;消费能力是否匹配生产&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;消息生产/消费延迟&lt;/td&gt;
					&lt;td&gt;端到端延迟是否可接受&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;死信队列消息数&lt;/td&gt;
					&lt;td&gt;是否有系统性失败&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Broker CPU/内存/磁盘 IO&lt;/td&gt;
					&lt;td&gt;集群健康度&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;消费失败重试次数&lt;/td&gt;
					&lt;td&gt;是否有异常趋势&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;68-版本与客户端兼容性&#34;&gt;6.8 版本与客户端兼容性&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;坑&lt;/strong&gt;：服务端和客户端版本差距大，出现协议不兼容或特性缺失。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：尽量保持服务端与客户端版本一致，升级时先升级服务端再升级客户端，灰度验证。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七总结&#34;&gt;七、总结&lt;/h2&gt;
&lt;p&gt;RocketMQ 不是银弹，但在大多数分布式异步场景里是非常稳妥的选择。用好它，关键是理解几个核心原则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;推/拉/通知不是对立关系&lt;/strong&gt;：Push 适合大多数业务，Pull 适合重任务和批量，Notify 是业务层闭环。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异常处理要分三层&lt;/strong&gt;：发送层用同步/异步确认，Broker 层用刷盘和主从，消费层用幂等 + 重试 + 死信。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高并发 = 水平扩展 + 削峰填谷&lt;/strong&gt;：Queue 是缓冲，Consumer 是处理单元，单线程效率决定上限。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;避坑的核心是规范&lt;/strong&gt;：订阅一致、消息体小、顺序消息慎用、监控到位。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;选型不是单选题&lt;/strong&gt;：RocketMQ 适合在线业务，Kafka 适合日志流处理，RabbitMQ 适合轻量快速落地，大厂往往是组合使用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;底层差异决定选型&lt;/strong&gt;：CommitLog + ConsumeQueue、NameServer、长轮询 Push、原生事务/延迟消息，共同决定了 RocketMQ 在在线业务场景的优势。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;《RocketMQ 实战与核心原理》&lt;/li&gt;
&lt;li&gt;《RocketMQ 技术内幕》&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.tencent.com/developer/article/2615437&#34;&gt;RocketMQ 消息消费核心原理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/1978935567824736405&#34;&gt;RocketMQ 高并发与异常处理实践&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;如果你也在用 RocketMQ 做异步化改造，欢迎在评论区交流推拉选型、重试策略或高并发调优经验。&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
