<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>后端架构 on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/%E5%90%8E%E7%AB%AF%E6%9E%B6%E6%9E%84/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Tue, 28 Sep 2021 10:00:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/%E5%90%8E%E7%AB%AF%E6%9E%B6%E6%9E%84/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>从Redis核心原理到 IPTV 视频项目落地</title>
      <link>https://ftmao.com/blog/posts/redis-in-action-iptv/</link>
      <pubDate>Tue, 28 Sep 2021 10:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/redis-in-action-iptv/</guid>
      <description>&lt;h1 id=&#34;从redis核心原理到-iptv-视频项目落地&#34;&gt;从Redis核心原理到 IPTV 视频项目落地&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;先系统梳理 Redis 的核心原理与面试高频知识点，再结合 IPTV（交互式网络电视）视频业务场景，给出可直接运行的 Demo。最后讨论 Redis 为什么不适合长期存储、常见踩坑点，以及 List / Pub/Sub / Stream 三种消息队列实现。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一redis-是什么一句话定位&#34;&gt;一、Redis 是什么？一句话定位&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Redis（Remote Dictionary Server）是一个开源的、基于内存的高性能键值对数据库&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;graph LR
    A[Redis] --&amp;gt; B[内存存储]
    A --&amp;gt; C[数据结构服务器]
    A --&amp;gt; D[单线程命令执行]
    A --&amp;gt; E[IO 多路复用]
    A --&amp;gt; F[持久化 + 高可用]
    B --&amp;gt; G[读写毫秒级]
    C --&amp;gt; H[String/Hash/List/Set/ZSET/Stream/Bitmap/Geo/HyperLogLog]
    F --&amp;gt; I[RDB/AOF/主从/哨兵/Cluster]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;与 Memcached 等纯缓存不同，Redis 的核心价值在于&lt;strong&gt;丰富的数据结构与原子操作&lt;/strong&gt;，可以直接在内存中完成排序、计数、限流、去重、队列等复杂逻辑。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二redis-为什么快&#34;&gt;二、Redis 为什么快？&lt;/h2&gt;
&lt;p&gt;面试常问「Redis 为什么快」，通常从四个层面回答：&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;数据存于内存，无需磁盘寻道，访问速度是 SSD 的千倍以上。&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 缓存命中率更高。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;IO 多路复用&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;基于 epoll/kqueue/select 用一个线程处理大量连接。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;高效数据结构&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;String 底层 SDS、ZSET 底层跳表+字典、List 底层 quicklist 等。&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;graph TB
    subgraph Redis 6/7 线程模型
        M[主线程&amp;lt;br/&amp;gt;命令执行 + IO 多路复用]
        IO[IO 线程池&amp;lt;br/&amp;gt;仅网络读写]
        BG[后台进程&amp;lt;br/&amp;gt;RDB fork / AOF rewrite]
    end
    C1[Client 1] --&amp;gt; M
    C2[Client 2] --&amp;gt; M
    C3[Client 3] --&amp;gt; M
    M &amp;lt;--&amp;gt; IO
    M -.-&amp;gt; BG&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;注意：Redis 6/7 引入的多线程&lt;strong&gt;只用于网络 IO 读写&lt;/strong&gt;，命令执行依旧是单线程。所以单条慢命令仍会阻塞整个实例。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三redis-数据类型与使用场景&#34;&gt;三、Redis 数据类型与使用场景&lt;/h2&gt;
&lt;h3 id=&#34;31-五种基本数据类型&#34;&gt;3.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;th&gt;典型场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;String&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;SDS（简单动态字符串）&lt;/td&gt;
					&lt;td&gt;缓存、计数器、分布式锁、Session&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Hash&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;ziplist / hashtable&lt;/td&gt;
					&lt;td&gt;对象缓存、用户信息、EPG 节目单&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;List&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;quicklist（ziplist + 双向链表）&lt;/td&gt;
					&lt;td&gt;消息队列、最新 N 条记录&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Set&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;intset / hashtable&lt;/td&gt;
					&lt;td&gt;去重、共同关注、抽奖&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ZSET&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;ziplist / skiplist + dict&lt;/td&gt;
					&lt;td&gt;排行榜、延时队列、范围查询&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;注：表中 ziplist 在 Redis 7 起已被 listpack 替代（动机见 §4.2），配置项改名 &lt;code&gt;*-max-listpack-*&lt;/code&gt;，旧名仍兼容。&lt;/p&gt;
&lt;/blockquote&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;Bitmap&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;位数组，按位操作&lt;/td&gt;
					&lt;td&gt;用户签到、在线状态、UV 统计&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;HyperLogLog&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;基数估计算法&lt;/td&gt;
					&lt;td&gt;海量 UV 去重计数，误差约 0.81%&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Geo&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;地理位置坐标&lt;/td&gt;
					&lt;td&gt;附近的人、POI 搜索&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;33-string最常用却被低估&#34;&gt;3.3 String：最常用却被低估&lt;/h3&gt;
&lt;p&gt;String 不仅能存字符串，还能存整数、浮点数、二进制数据。常用命令：&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET key value EX &lt;span style=&#34;color:#ae81ff&#34;&gt;3600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET key
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INCR view_count
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INCRBY view_count &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SETNX lock:order:123 true EX &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;  &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;p&gt;&lt;strong&gt;SDS 的优势&lt;/strong&gt;（相对 C 字符串）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;O(1) 获取长度。&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;h3 id=&#34;34-hash对象缓存首选&#34;&gt;3.4 Hash：对象缓存首选&lt;/h3&gt;
&lt;p&gt;Hash 适合存「一组字段」的对象，比 JSON String 更节省内存、更新更灵活。&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HSET user:1001 name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;张三&amp;#34;&lt;/span&gt; age &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt; city &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;北京&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HGET user:1001 name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HGETALL user:1001
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HINCRBY user:1001 age &lt;span style=&#34;color:#ae81ff&#34;&gt;1&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;35-zset排行榜的王牌&#34;&gt;3.5 ZSET：排行榜的王牌&lt;/h3&gt;
&lt;p&gt;ZSET 底层同时维护「跳表」和「字典」：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;跳表（skiplist）&lt;/strong&gt;：支持 O(log N) 的范围查询和排序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;字典（dict）&lt;/strong&gt;：支持 O(1) 按 member 查 score。&lt;/li&gt;
&lt;/ul&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ZADD hot:tv &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;庆余年&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ZADD hot:tv &lt;span style=&#34;color:#ae81ff&#34;&gt;800&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;狂飙&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ZINCRBY hot:tv &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;狂飙&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ZREVRANGE hot:tv &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt; WITHSCORES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ZREVRANK hot:tv &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;狂飙&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;36-list-与-stream队列双雄&#34;&gt;3.6 List 与 Stream：队列双雄&lt;/h3&gt;
&lt;p&gt;List 适合简单队列，Stream 适合生产级消息队列，后面第十四部分会详细对比。&lt;/p&gt;
&lt;h3 id=&#34;37-bitmap-与-hyperloglog海量-uv-统计的利器&#34;&gt;3.7 Bitmap 与 HyperLogLog：海量 UV 统计的利器&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Bitmap 为什么能天然去重？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Bitmap 本质是一个超长 bit 数组，每个 bit 只能是 0 或 1。把 user_id 作为偏移量（offset），用户访问一次就把对应位置 1：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;天然去重&lt;/strong&gt;：同一用户重复访问，置的都是同一个 bit，无需额外判断。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;极致省内存&lt;/strong&gt;：1 亿用户只需 1 亿 bit ≈ 12MB；而 Set 存 1 亿个 ID 要占用数 GB。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支持位运算&lt;/strong&gt;：&lt;code&gt;BITOP AND/OR&lt;/code&gt; 可以直接算多日留存（今天访问 AND 昨天也访问）。&lt;/li&gt;
&lt;/ul&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SETBIT uv:20210928 &lt;span style=&#34;color:#ae81ff&#34;&gt;10086&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;# 用户 10086 访问&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SETBIT uv:20210928 &lt;span style=&#34;color:#ae81ff&#34;&gt;10086&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&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;BITCOUNT uv:20210928         &lt;span style=&#34;color:#75715e&#34;&gt;# 直接得出 UV 数&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;局限：要求 user_id 是连续整数，ID 稀疏时浪费内存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HyperLogLog 为什么 12KB 能数一亿？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;HyperLogLog 基于概率估计算法：把每个元素 hash 成均匀分布的随机数，观察 hash 值二进制串中&lt;strong&gt;前导零的最大个数&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;类比抛硬币：想连续抛出 N 次正面，平均要抛 2^N 次。反过来，如果见过最长连续 N 次正面，就估计大约抛了 2^N 次——前导零越多，说明见过的不同元素越多。&lt;/li&gt;
&lt;li&gt;单次估计误差大，所以内部用 &lt;strong&gt;16384 个分桶（寄存器，每个 6 bit）&lt;/strong&gt; 分别记录，再取调和平均数消除偶然性，最终误差稳定在 &lt;strong&gt;0.81%&lt;/strong&gt; 左右。&lt;/li&gt;
&lt;li&gt;内存恒定 &lt;strong&gt;约 12KB&lt;/strong&gt;，与元素个数无关：统计 1 亿 UV 还是 10 亿 UV 都是 12KB。&lt;/li&gt;
&lt;/ul&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PFADD uv:20210928 &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user:10086&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PFADD uv:20210928 &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user:10086&amp;#34;&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;PFCOUNT uv:20210928             &lt;span style=&#34;color:#75715e&#34;&gt;# 估算 UV&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;/p&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;精确计数、算多日留存（交并集）、ID 是连续整数&lt;/td&gt;
					&lt;td&gt;Bitmap&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;只要近似 UV、数据量极大、ID 是任意字符串&lt;/td&gt;
					&lt;td&gt;HyperLogLog&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四redis-底层数据结构速览&#34;&gt;四、Redis 底层数据结构速览&lt;/h2&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;graph TD
    A[Redis 数据类型] --&amp;gt; B[String]
    A --&amp;gt; C[Hash]
    A --&amp;gt; D[List]
    A --&amp;gt; E[Set]
    A --&amp;gt; F[ZSET]
    B --&amp;gt; G[SDS]
    C --&amp;gt; H[ziplist]
    C --&amp;gt; I[hashtable]
    D --&amp;gt; J[quicklist]
    E --&amp;gt; K[intset]
    E --&amp;gt; L[hashtable]
    F --&amp;gt; M[ziplist]
    F --&amp;gt; N[skiplist + dict]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&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;SDS&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;带长度、预分配、二进制安全。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ziplist&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;紧凑列表，小数据量时省内存；大数据量时改为 hashtable/skiplist。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;listpack&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;ziplist 的修正版（Redis 7+）：entry 只记自身长度，消灭连锁更新。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;quicklist&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;List 的底层，由多个紧凑块（Redis 7 前是 ziplist，之后是 listpack）节点组成的双向链表。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;hashtable&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;标准哈希表，渐进式 rehash 避免一次性阻塞。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;intset&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Set 在元素全为整数且数量少时的紧凑实现。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;skiplist&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;多层索引链表，实现 ZSET 的有序范围查询。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;下面把 5 种核心结构「画」出来。&lt;/p&gt;
&lt;h3 id=&#34;41-sdssimple-dynamic-string&#34;&gt;4.1 SDS（Simple Dynamic String）&lt;/h3&gt;
&lt;p&gt;Redis 没有直接用 C 字符串，而是包了 SDS：&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
    L[&amp;#34;len&amp;lt;br/&amp;gt;已用长度（4B）&amp;lt;br/&amp;gt;= 5&amp;#34;] --- A[&amp;#34;alloc&amp;lt;br/&amp;gt;总容量&amp;lt;br/&amp;gt;= 8&amp;#34;] --- F[&amp;#34;flags&amp;lt;br/&amp;gt;编码位&amp;lt;br/&amp;gt;= 0&amp;#34;] --- B[&amp;#34;buf[]&amp;lt;br/&amp;gt;实际字符/二进制数据&amp;lt;br/&amp;gt;H e l l o \0 ...&amp;#34;]
    N1[&amp;#34;O(1) 取长度&amp;#34;] -.-&amp;gt; L
    N2[&amp;#34;末尾保留 \0&amp;lt;br/&amp;gt;兼容 C 字符串函数&amp;#34;] -.-&amp;gt; B&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;len&lt;/code&gt;：已用长度，取长度 &lt;code&gt;O(1)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;alloc&lt;/code&gt;：分配的总空间；&lt;code&gt;free = alloc - len&lt;/code&gt; 可减少内存重分配。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;二进制安全&lt;/strong&gt;：内容中间可以有 &lt;code&gt;\0&lt;/code&gt;，长度由 &lt;code&gt;len&lt;/code&gt; 决定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预分配&lt;/strong&gt;：修改时若 &lt;code&gt;free&lt;/code&gt; 足够就不 &lt;code&gt;realloc&lt;/code&gt;；不足时按 2 倍或 1MB 上限预分配。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;42-ziplist压缩列表&#34;&gt;4.2 ziplist（压缩列表）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ziplist&lt;/code&gt; 是一块连续内存，把所有 entry 紧凑排列：&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;zlbytes&amp;lt;br/&amp;gt;总字节数&amp;lt;br/&amp;gt;4B&amp;#34;] --- B[&amp;#34;zltail&amp;lt;br/&amp;gt;尾偏移量&amp;lt;br/&amp;gt;4B&amp;#34;] --- C[&amp;#34;zllen&amp;lt;br/&amp;gt;节点数&amp;lt;br/&amp;gt;2B&amp;#34;] --- D[&amp;#34;entry1&amp;lt;br/&amp;gt;变长字节&amp;#34;] --- E[&amp;#34;entry2&amp;lt;br/&amp;gt;变长字节&amp;#34;] --- F[&amp;#34;...&amp;#34;] --- G[&amp;#34;zlend&amp;lt;br/&amp;gt;0xFF&amp;lt;br/&amp;gt;1B&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;每个 entry 的内部结构：&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;prevlen&amp;lt;br/&amp;gt;前节点长度&amp;lt;br/&amp;gt;1B 或 5B&amp;#34;] --- B[&amp;#34;encoding&amp;lt;br/&amp;gt;编码/长度类型&amp;lt;br/&amp;gt;1B 或更多&amp;#34;] --- C[&amp;#34;content&amp;lt;br/&amp;gt;实际数据&amp;lt;br/&amp;gt;变长&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;连续内存、无额外指针，所以&lt;strong&gt;省内存&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;插入/删除需要整体 &lt;code&gt;memmove&lt;/code&gt;，因此只用于&lt;strong&gt;小数据量&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Hash/List/ZSET&lt;/code&gt; 元素少且单元素短时先用 ziplist，超过阈值升级为 hashtable/skiplist。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;listpack（Redis 7 的替代者）&lt;/strong&gt;：ziplist 的致命伤就藏在 &lt;code&gt;prevlen&lt;/code&gt; 里——每个 entry 要记录&lt;strong&gt;前一个&lt;/strong&gt; entry 的长度：前 entry 小于 254 字节时 prevlen 占 1B，达到 254 字节时占 5B。于是一个 entry 从 253 涨到 254 字节，会让后面每个 entry 的 prevlen 从 1B 膨胀到 5B，膨胀又可能触发下一个 entry 继续膨胀——&lt;strong&gt;连锁更新&lt;/strong&gt;，最坏 O(N²)。&lt;/p&gt;
&lt;p&gt;listpack 的修法：&lt;strong&gt;每个 entry 只记录自己的总长度，且存在 entry 末尾&lt;/strong&gt;，entry 之间互不引用——改任何一个 entry 都不会波及邻居，连锁更新从根上消失。Redis 7 起 Hash/List/ZSET 的小对象编码全部换成 listpack，配置项同步改名（&lt;code&gt;hash-max-listpack-entries&lt;/code&gt; 等，旧的 &lt;code&gt;*-ziplist-*&lt;/code&gt; 名仍兼容）。面试回答「ziplist 和 listpack 的区别」，核心就是这一句：&lt;strong&gt;ziplist 记前驱长度所以连锁更新，listpack 记自身长度所以免疫&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;43-quicklist快速列表&#34;&gt;4.3 quicklist（快速列表）&lt;/h3&gt;
&lt;p&gt;Redis 3.2 后，&lt;code&gt;List&lt;/code&gt; 的底层是 &lt;strong&gt;quicklist = 双向链表 + ziplist&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
    H[&amp;#34;head&amp;#34;] --&amp;gt; A[&amp;#34;ziplist A&amp;lt;br/&amp;gt;[a|b|c]&amp;lt;br/&amp;gt;count=3&amp;lt;br/&amp;gt;sz=...&amp;#34;] &amp;lt;--&amp;gt; B[&amp;#34;ziplist B&amp;lt;br/&amp;gt;[d|e|f|g]&amp;lt;br/&amp;gt;count=4&amp;lt;br/&amp;gt;sz=...&amp;#34;] &amp;lt;--&amp;gt; C[&amp;#34;...&amp;#34;]
    N[&amp;#34;每个节点是一个 ziplist&amp;lt;br/&amp;gt;节点之间用 prev/next 指针连接&amp;#34;] -.-&amp;gt; A&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;quicklistNode 结构：&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;prev&amp;lt;br/&amp;gt;指针&amp;#34;] --- B[&amp;#34;next&amp;lt;br/&amp;gt;指针&amp;#34;] --- C[&amp;#34;zl&amp;lt;br/&amp;gt;ziplist&amp;#34;] --- D[&amp;#34;sz&amp;lt;br/&amp;gt;字节数&amp;#34;] --- E[&amp;#34;count&amp;lt;br/&amp;gt;元素个数&amp;#34;] --- F[&amp;#34;encoding&amp;lt;br/&amp;gt;是否压缩&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;结合了双向链表「插入删除快」和 ziplist「省内存」的优点。&lt;/li&gt;
&lt;li&gt;每个节点只存少量元素，避免单个 ziplist 太大导致 &lt;code&gt;memmove&lt;/code&gt; 开销。&lt;/li&gt;
&lt;li&gt;Redis 7 起节点从 ziplist 换成 listpack（动机见 §4.2），但 quicklist 的「链表 + 紧凑块」思想不变。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;44-intset整数集合&#34;&gt;4.4 intset（整数集合）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Set&lt;/code&gt; 在元素&lt;strong&gt;全为整数且数量少&lt;/strong&gt;时使用 intset，否则升级为 &lt;code&gt;hashtable&lt;/code&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;encoding&amp;lt;br/&amp;gt;编码类型&amp;lt;br/&amp;gt;2B/4B/8B&amp;#34;] --- B[&amp;#34;length&amp;lt;br/&amp;gt;元素个数&amp;lt;br/&amp;gt;4B&amp;#34;] --- C[&amp;#34;contents[]&amp;lt;br/&amp;gt;有序整数数组&amp;lt;br/&amp;gt;[1] [3] [5] [7] [9] ...&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;有序数组，支持二分查找 &lt;code&gt;O(log N)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;所有元素用同一 encoding；加入更大范围整数时可能整体升级（如 int16 → int32），升级是 &lt;code&gt;O(N)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;无重复元素（Set 语义）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;45-skiplist跳表&#34;&gt;4.5 skiplist（跳表）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ZSET&lt;/code&gt; 同时维护 &lt;strong&gt;skiplist + dict&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;skiplist&lt;/code&gt;：按 score 排序，支持范围查询 / 排名 &lt;code&gt;O(log N)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dict&lt;/code&gt;：按 member 查 score，&lt;code&gt;O(1)&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&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
    subgraph L3[&amp;#34;level 3&amp;#34;]
        A3[&amp;#34;1&amp;#34;] --&amp;gt; B3[&amp;#34;9&amp;#34;] --&amp;gt; C3[&amp;#34;15&amp;#34;]
    end
    subgraph L2[&amp;#34;level 2&amp;#34;]
        A2[&amp;#34;1&amp;#34;] --&amp;gt; B2[&amp;#34;5&amp;#34;] --&amp;gt; C2[&amp;#34;9&amp;#34;] --&amp;gt; D2[&amp;#34;13&amp;#34;] --&amp;gt; E2[&amp;#34;15&amp;#34;]
    end
    subgraph L1[&amp;#34;level 1&amp;#34;]
        A1[&amp;#34;1&amp;#34;] --&amp;gt; B1[&amp;#34;3&amp;#34;] --&amp;gt; C1[&amp;#34;5&amp;#34;] --&amp;gt; D1[&amp;#34;7&amp;#34;] --&amp;gt; E1[&amp;#34;9&amp;#34;] --&amp;gt; F1[&amp;#34;11&amp;#34;] --&amp;gt; G1[&amp;#34;13&amp;#34;] --&amp;gt; H1[&amp;#34;15&amp;#34;]
    end
    A3 --- A2 --- A1
    B3 --- C2 --- E1
    C3 --- E2 --- H1
    HEAD[&amp;#34;头节点&amp;#34;] -.-&amp;gt; A1
    H1 -.-&amp;gt; TAIL[&amp;#34;尾节点&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&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
    A[&amp;#34;member&amp;lt;br/&amp;gt;成员字符串&amp;lt;br/&amp;gt;（sds）&amp;#34;] --- B[&amp;#34;score&amp;lt;br/&amp;gt;分数&amp;lt;br/&amp;gt;（double）&amp;#34;] --- C[&amp;#34;forward[] 数组&amp;lt;br/&amp;gt;[L1指针， L2指针， L3指针， ...]&amp;lt;br/&amp;gt;最高层数 = 随机 1~32&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;概率平衡&lt;/strong&gt;：不用像红黑树那样做复杂旋转。&lt;/li&gt;
&lt;li&gt;查找 &lt;code&gt;score=11&lt;/code&gt; 时，先在高层大步跳跃，再逐层下降，平均 &lt;code&gt;O(log N)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;配合 dict 实现 &lt;code&gt;ZSCORE&lt;/code&gt; 的 &lt;code&gt;O(1)&lt;/code&gt; 查询。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五redis-持久化rdb-与-aof&#34;&gt;五、Redis 持久化：RDB 与 AOF&lt;/h2&gt;
&lt;p&gt;Redis 提供两种持久化方式，各有优劣。&lt;/p&gt;
&lt;h3 id=&#34;51-rdbredis-database&#34;&gt;5.1 RDB（Redis Database）&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;save &lt;span style=&#34;color:#ae81ff&#34;&gt;900&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# 900 秒内至少 1 次修改则触发&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;save &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;     &lt;span style=&#34;color:#75715e&#34;&gt;# 300 秒内至少 10 次修改则触发&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;save &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10000&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;# 60 秒内至少 10000 次修改则触发&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;strong&gt;优点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&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;两次快照之间数据可能丢失。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bgsave&lt;/code&gt; 通过 &lt;code&gt;fork()&lt;/code&gt; 子进程生成，大数据集时可能阻塞主线程。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;52-aofappend-only-file&#34;&gt;5.2 AOF（Append Only File）&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;appendonly yes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;appendfsync everysec  &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:#75715e&#34;&gt;# appendfsync always  # 每次写都刷盘，最安全但最慢&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;# appendfsync no      # 由操作系统决定，最快但不安全&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;strong&gt;优点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据安全性更高，默认最多丢失 1 秒数据。&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;AOF 重写（rewrite）时会占用额外资源。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;53-混合持久化redis-40&#34;&gt;5.3 混合持久化（Redis 4.0+）&lt;/h3&gt;
&lt;p&gt;AOF 重写时先写入 RDB 全量数据，再追加增量 AOF，兼顾恢复速度和数据安全。&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;aof-use-rdb-preamble yes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&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;graph LR
    A[持久化选择] --&amp;gt; B[RDB]
    A --&amp;gt; C[AOF]
    A --&amp;gt; D[混合持久化]
    B --&amp;gt; E[适合备份/快速恢复]
    C --&amp;gt; F[适合低丢失容忍]
    D --&amp;gt; G[生产推荐]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;八股重点&lt;/strong&gt;：Redis 的持久化是「灾难恢复手段」，不是「主存储方案」。&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;Redis 对过期 Key 采用两种策略结合：&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;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;访问 Key 时检查是否过期，过期则删除。&lt;/td&gt;
					&lt;td&gt;CPU 开销小&lt;/td&gt;
					&lt;td&gt;过期 Key 可能长期占用内存&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;定期删除&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;每隔一段时间随机抽查部分 Key 删除。&lt;/td&gt;
					&lt;td&gt;平衡内存与 CPU&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;p&gt;当内存达到 &lt;code&gt;maxmemory&lt;/code&gt; 时，根据 &lt;code&gt;maxmemory-policy&lt;/code&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;code&gt;noeviction&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;不淘汰，写操作直接报错。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;allkeys-lru&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;所有 Key 中淘汰最近最少使用。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;volatile-lru&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;只在设置了 TTL 的 Key 中淘汰最近最少使用。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;allkeys-random&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;所有 Key 中随机淘汰。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;volatile-random&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;只在设置了 TTL 的 Key 中随机淘汰。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;volatile-ttl&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;淘汰即将过期的 Key。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;allkeys-lfu&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;所有 Key 中淘汰使用频率最低的。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;volatile-lfu&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;只在设置了 TTL 的 Key 中淘汰使用频率最低的。&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;code&gt;maxmemory&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;缓存场景推荐 &lt;code&gt;allkeys-lru&lt;/code&gt; 或 &lt;code&gt;allkeys-lfu&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;有冷热区分时可用 &lt;code&gt;volatile-lru&lt;/code&gt;，但必须给 Key 设置 TTL。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七redis-高可用架构&#34;&gt;七、Redis 高可用架构&lt;/h2&gt;
&lt;h3 id=&#34;71-主从复制replication&#34;&gt;7.1 主从复制（Replication）&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;graph LR
    M[Master&amp;lt;br/&amp;gt;写 + 读] --&amp;gt;|全量/增量同步| S1[Slave 1&amp;lt;br/&amp;gt;读]
    M --&amp;gt; S2[Slave 2&amp;lt;br/&amp;gt;读]
    M --&amp;gt; S3[Slave 3&amp;lt;br/&amp;gt;读]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;复制过程&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Slave 发送 &lt;code&gt;PSYNC runId offset&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;如果 runId 一致且 offset 在复制积压缓冲区中，则&lt;strong&gt;增量同步&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;否则&lt;strong&gt;全量同步&lt;/strong&gt;：Master 执行 &lt;code&gt;bgsave&lt;/code&gt; 生成 RDB，发送给 Slave。&lt;/li&gt;
&lt;/ol&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;/ul&gt;
&lt;h3 id=&#34;72-哨兵sentinel&#34;&gt;7.2 哨兵（Sentinel）&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;graph TB
    subgraph Sentinel 集群
        Se1[Sentinel 1]
        Se2[Sentinel 2]
        Se3[Sentinel 3]
    end
    M[Master] --&amp;gt; S1[Slave 1]
    M --&amp;gt; S2[Slave 2]
    Se1 --&amp;gt;|监控| M
    Se2 --&amp;gt;|监控| M
    Se3 --&amp;gt;|监控| M
    Se1 -.-&amp;gt; Se2
    Se2 -.-&amp;gt; Se3&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;strong&gt;主观下线（SDOWN）&lt;/strong&gt;：单个 Sentinel 认为 Master 不可用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;客观下线（ODOWN）&lt;/strong&gt;：多数 Sentinel 达成一致。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leader 选举&lt;/strong&gt;：Sentinel 之间通过 Raft 算法选举出执行故障转移的 Leader。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;故障转移&lt;/strong&gt;：选一个 Slave 提升为 Master，通知其他 Slave 和客户端。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;73-cluster-集群&#34;&gt;7.3 Cluster 集群&lt;/h3&gt;
&lt;p&gt;Redis Cluster 采用&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;graph TB
    subgraph Redis Cluster
        N1[Node 1&amp;lt;br/&amp;gt;0-5460]
        N2[Node 2&amp;lt;br/&amp;gt;5461-10922]
        N3[Node 3&amp;lt;br/&amp;gt;10923-16383]
    end
    N1 &amp;lt;--&amp;gt; N2
    N2 &amp;lt;--&amp;gt; N3
    N1 &amp;lt;--&amp;gt; N3&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;strong&gt;16384 个槽（slot）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;每个 Key 通过 &lt;code&gt;CRC16(key) % 16384&lt;/code&gt; 计算所属槽。&lt;/li&gt;
&lt;li&gt;每个 Master 负责一部分槽，可配置 Slave 做高可用。&lt;/li&gt;
&lt;li&gt;客户端访问错误节点时，会收到 &lt;code&gt;MOVED&lt;/code&gt; 或 &lt;code&gt;ASK&lt;/code&gt; 重定向。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;MOVED vs ASK&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MOVED&lt;/strong&gt;：槽已经永久迁移到目标节点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ASK&lt;/strong&gt;：槽正在迁移中，先访问目标节点一次。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八事务与-lua-脚本&#34;&gt;八、事务与 Lua 脚本&lt;/h2&gt;
&lt;h3 id=&#34;81-事务multiexecdiscardwatch&#34;&gt;8.1 事务（MULTI/EXEC/DISCARD/WATCH）&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MULTI
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SET a &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INCR b
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EXEC&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;命令按顺序入队，EXEC 时一次性执行。&lt;/li&gt;
&lt;li&gt;执行期间不会被其他客户端打断。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;但没有回滚机制&lt;/strong&gt;：如果某条命令语法错误，整个事务不执行；如果运行时错误（如 INCR 字符串），后续命令仍会执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;82-lua-脚本&#34;&gt;8.2 Lua 脚本&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-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EVAL &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;return redis.call(&amp;#39;incr&amp;#39;, KEYS[1])&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; counter&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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;strong&gt;集群模式下所有 Key 必须落在同一 slot&lt;/strong&gt;，否则需要加 hash tag，如 &lt;code&gt;{user}:1001:profile&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九缓存经典问题&#34;&gt;九、缓存经典问题&lt;/h2&gt;
&lt;h3 id=&#34;91-缓存穿透&#34;&gt;9.1 缓存穿透&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;ul&gt;
&lt;li&gt;缓存空值（设置短 TTL）。&lt;/li&gt;
&lt;li&gt;使用布隆过滤器预先判断 Key 是否存在。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;92-缓存击穿&#34;&gt;9.2 缓存击穿&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;问题&lt;/strong&gt;：热点 Key 突然过期，大量请求同时打到数据库。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;热点 Key 设置永不过期，异步更新。&lt;/li&gt;
&lt;li&gt;加互斥锁（SETNX），只允许一个线程重建缓存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;93-缓存雪崩&#34;&gt;9.3 缓存雪崩&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;问题&lt;/strong&gt;：大量 Key 同时过期，或 Redis 宕机，数据库压力陡增。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;给 TTL 加随机值，避免同时失效。&lt;/li&gt;
&lt;li&gt;多级缓存（本地 + Redis）。&lt;/li&gt;
&lt;li&gt;熔断降级。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;94-缓存与数据库一致性&#34;&gt;9.4 缓存与数据库一致性&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;Cache Aside&lt;/td&gt;
					&lt;td&gt;读：先读缓存，未命中读 DB 并写回缓存；写：先更新 DB，再删缓存。&lt;/td&gt;
					&lt;td&gt;短暂不一致&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Read/Write Through&lt;/td&gt;
					&lt;td&gt;由缓存层统一维护 DB 和缓存。&lt;/td&gt;
					&lt;td&gt;实现复杂&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Write Behind&lt;/td&gt;
					&lt;td&gt;先写缓存，异步写 DB。&lt;/td&gt;
					&lt;td&gt;可能丢数据&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;最常用的是 Cache Aside&lt;/strong&gt;，配合「先更新数据库，再删除缓存」+ 延时双删 + 消息队列补偿，能在大多数场景下保证最终一致。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十redis-在-iptv-系统中的角色&#34;&gt;十、Redis 在 IPTV 系统中的角色&lt;/h2&gt;
&lt;p&gt;IPTV 系统的特点是：&lt;strong&gt;高并发读、强实时性、热点集中、写流量脉冲式&lt;/strong&gt;。用户在换台、看 EPG、播放点播、抢购付费节目时，系统需要在毫秒级返回结果。&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 TB
    subgraph 用户层
        A[机顶盒 / 手机 / Web]
    end

    subgraph 接入层
        B[CDN / 边缘节点]
        C[API Gateway]
    end

    subgraph 应用层
        D[鉴权服务]
        E[EPG 服务]
        F[播放调度服务]
        G[订单 / 秒杀服务]
    end

    subgraph 数据层
        H[(MySQL / 长视频元信息)]
        I[(对象存储 OSS)]
        J[(Redis 缓存 + 实时计算)]
    end

    A --&amp;gt; B --&amp;gt; C
    C --&amp;gt; D &amp;amp; E &amp;amp; F &amp;amp; G
    D --&amp;gt; J
    E --&amp;gt; J
    F --&amp;gt; J
    G --&amp;gt; J
    E --&amp;gt; H
    F --&amp;gt; I
    G --&amp;gt; H
    J -.-&amp;gt; H&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;Redis 数据结构&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;用户会话 / Token&lt;/td&gt;
					&lt;td&gt;String + EXPIRE&lt;/td&gt;
					&lt;td&gt;毫秒级鉴权&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;EPG 节目单缓存&lt;/td&gt;
					&lt;td&gt;Hash / JSON String&lt;/td&gt;
					&lt;td&gt;减少数据库查询&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;热播榜单 / 推荐位&lt;/td&gt;
					&lt;td&gt;Sorted Set (ZSET)&lt;/td&gt;
					&lt;td&gt;实时排序&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;播放限速 / 防刷&lt;/td&gt;
					&lt;td&gt;Lua + INCR + EXPIRE&lt;/td&gt;
					&lt;td&gt;滑动窗口限流&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;秒杀 / 付费解锁&lt;/td&gt;
					&lt;td&gt;SETNX + DECR + Lua&lt;/td&gt;
					&lt;td&gt;库存扣减&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;消息通知 / 任务队列&lt;/td&gt;
					&lt;td&gt;List / Stream&lt;/td&gt;
					&lt;td&gt;异步解耦&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十一iptv-项目-demo&#34;&gt;十一、IPTV 项目 Demo&lt;/h2&gt;
&lt;h3 id=&#34;111-用户会话缓存&#34;&gt;11.1 用户会话缓存&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; redis
&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; uuid
&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;r &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; redis&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Redis(host&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;, port&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;6379&lt;/span&gt;, db&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, decode_responses&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&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;login&lt;/span&gt;(user_id: str, device_id: str, ttl: int &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3600&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; str:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    token &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; str(uuid&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;uuid4())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;session:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;token&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;    r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;hset(key, mapping&lt;span style=&#34;color:#f92672&#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;user_id&amp;#34;&lt;/span&gt;: user_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;device_id&amp;#34;&lt;/span&gt;: device_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;login_at&amp;#34;&lt;/span&gt;: str(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;    r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;expire(key, ttl)
&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; token
&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;auth&lt;/span&gt;(token: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; dict &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;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;hgetall(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;session:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;token&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;112-epg-节目单缓存&#34;&gt;11.2 EPG 节目单缓存&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; json
&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;from&lt;/span&gt; datetime &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; datetime
&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;cache_epg&lt;/span&gt;(channel_id: str, programs: list[dict]):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;epg:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;channel_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;datetime&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;today()&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;strftime(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%Y%m&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%d&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;)&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;    pipe &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pipeline()
&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; p &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; programs:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        pipe&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;hset(key, p[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;start_time&amp;#39;&lt;/span&gt;], json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;dumps(p))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pipe&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;expire(key, &lt;span style=&#34;color:#ae81ff&#34;&gt;86400&lt;/span&gt; &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;    pipe&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;execute()
&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;get_program&lt;/span&gt;(channel_id: str, start_time: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; dict &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;    data &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;hget(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;epg:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;channel_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;datetime&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;today()&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;strftime(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%Y%m&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%d&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;)&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, start_time)
&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; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;loads(data) &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; data &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;None&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;113-热播排行榜&#34;&gt;11.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:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;record_view&lt;/span&gt;(program_id: str, score: float &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;zincrby(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hot:tv:daily&amp;#34;&lt;/span&gt;, score, program_id)
&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;top_n&lt;/span&gt;(n: int &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; list[tuple[str, float]]:
&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; r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;zrevrange(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hot:tv:daily&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, n &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, withscores&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&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;114-滑动窗口限流&#34;&gt;11.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;LIMIT_SCRIPT &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &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;local key = KEYS[1]
&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;local window = tonumber(ARGV[1])
&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;local limit = tonumber(ARGV[2])
&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;local now = tonumber(ARGV[3])
&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;local min = now - window
&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;
&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;redis.call(&amp;#39;zremrangebyscore&amp;#39;, key, &amp;#39;-inf&amp;#39;, min)
&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;local count = redis.call(&amp;#39;zcard&amp;#39;, 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:#e6db74&#34;&gt;if count &amp;lt; limit then
&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;    redis.call(&amp;#39;zadd&amp;#39;, key, now, 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;    redis.call(&amp;#39;expire&amp;#39;, key, math.ceil(window / 1000))
&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;    return 1
&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;else
&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;    return 0
&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;end
&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;
&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;limiter &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;register_script(LIMIT_SCRIPT)
&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;allow&lt;/span&gt;(user_id: str, max_qps: int &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, window_ms: int &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;) &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;    key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rate_limit:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;user_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&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    now &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; int(time&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;time() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&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; bool(limiter(keys&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[key], args&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[window_ms, max_qps, now]))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;115-秒杀--限时解锁&#34;&gt;11.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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SECKILL_SCRIPT &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &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;local key = KEYS[1]
&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;local user_id = ARGV[1]
&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;local stock = tonumber(redis.call(&amp;#39;get&amp;#39;, key) or &amp;#39;0&amp;#39;)
&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;if stock &amp;lt;= 0 then
&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;    return -1
&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;end
&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;if redis.call(&amp;#39;sismember&amp;#39;, key .. &amp;#39;:users&amp;#39;, user_id) == 1 then
&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;    return 0
&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;end
&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;redis.call(&amp;#39;decr&amp;#39;, 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:#e6db74&#34;&gt;redis.call(&amp;#39;sadd&amp;#39;, key .. &amp;#39;:users&amp;#39;, user_id)
&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;return 1
&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;
&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;seckill &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;register_script(SECKILL_SCRIPT)
&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;try_buy&lt;/span&gt;(activity_id: str, user_id: str, total_stock: int) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; int:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;seckill:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;activity_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:stock&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;setnx(key, total_stock)
&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; int(seckill(keys&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[key], args&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[user_id]))&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;十二为什么-redis-不适合做长期存储&#34;&gt;十二、为什么 Redis 不适合做长期存储？&lt;/h2&gt;
&lt;h3 id=&#34;121-持久化不是主存储&#34;&gt;12.1 持久化不是主存储&lt;/h3&gt;
&lt;p&gt;RDB 会丢数据，AOF 文件大且恢复慢。Redis 的持久化定位是「灾难恢复」，不是「可靠主存」。&lt;/p&gt;
&lt;h3 id=&#34;122-内存成本过高&#34;&gt;12.2 内存成本过高&lt;/h3&gt;
&lt;p&gt;内存价格是 SSD 的 10-50 倍。IPTV 的媒资、播放记录、订单流水动辄几十 TB，全放 Redis 不现实。&lt;/p&gt;
&lt;h3 id=&#34;123-单线程执行风险&#34;&gt;12.3 单线程执行风险&lt;/h3&gt;
&lt;p&gt;大数据集下，一个 &lt;code&gt;KEYS *&lt;/code&gt;、&lt;code&gt;HGETALL&lt;/code&gt; 或慢查询可能阻塞整个实例。&lt;/p&gt;
&lt;h3 id=&#34;124-缺乏复杂查询能力&#34;&gt;12.4 缺乏复杂查询能力&lt;/h3&gt;
&lt;p&gt;Redis 不支持 SQL、JOIN、二级索引。长期业务数据需要分析统计时，应使用 MySQL / PostgreSQL / ClickHouse。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Redis 适合「热数据 + 临时状态 + 实时计算」，价值在于速度；长期存储应交给磁盘数据库 + 对象存储。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十三redis-容易踩坑的地方&#34;&gt;十三、Redis 容易踩坑的地方&lt;/h2&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;大 Key&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;String &amp;gt; 10MB，集合元素百万级&lt;/td&gt;
					&lt;td&gt;拆分、分片、UNLINK 异步删除&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;热 Key&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;单个 Key 被高频访问&lt;/td&gt;
					&lt;td&gt;本地缓存、Key 分片、Cluster&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;缓存穿透/击穿/雪崩&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;缓存失效导致 DB 被打挂&lt;/td&gt;
					&lt;td&gt;布隆过滤器、互斥锁、随机 TTL&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;未设置 maxmemory&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;内存打满后写操作报错&lt;/td&gt;
					&lt;td&gt;设置 maxmemory 和淘汰策略&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;误用 KEYS&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;KEYS *&lt;/code&gt; 扫描全库阻塞主线程&lt;/td&gt;
					&lt;td&gt;生产禁用，改用 SCAN&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Lua 跨 slot&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Cluster 下脚本 Key 不在同一 slot&lt;/td&gt;
					&lt;td&gt;使用 hash tag &lt;code&gt;{user}:1001:xxx&lt;/code&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;EXEC 后某命令失败不会撤销前面命令&lt;/td&gt;
					&lt;td&gt;业务层保证幂等，或用 Lua&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;hr&gt;
&lt;h2 id=&#34;十四redis-做消息队列的方法&#34;&gt;十四、Redis 做消息队列的方法&lt;/h2&gt;
&lt;h3 id=&#34;141-list轻量队列&#34;&gt;14.1 List：轻量队列&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
    P[Producer] --&amp;gt;|LPUSH queue:transcode task| R[(Redis List)]
    C[Consumer] --&amp;gt;|BRPOP queue:transcode 5| R
    C --&amp;gt; S[执行转码]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&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;r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;lpush(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;queue:transcode&amp;#34;&lt;/span&gt;, json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;dumps({&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;video_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;v123&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; r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;brpop(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;queue:transcode&amp;#34;&lt;/span&gt;, 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;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;优点&lt;/strong&gt;：简单、阻塞读。
&lt;strong&gt;缺点&lt;/strong&gt;：无 ACK、无多消费者组、无消息回溯。&lt;/p&gt;
&lt;h3 id=&#34;142-pubsub实时广播&#34;&gt;14.2 Pub/Sub：实时广播&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;r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;publish(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;live:start&amp;#34;&lt;/span&gt;, json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;dumps({&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;channel_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cctv1&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;strong&gt;优点&lt;/strong&gt;：实时、多订阅者。
&lt;strong&gt;缺点&lt;/strong&gt;：不持久化，消费者断线期间消息丢失。&lt;/p&gt;
&lt;h3 id=&#34;143-stream生产级队列&#34;&gt;14.3 Stream：生产级队列&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;r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;xadd(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mq:events&amp;#34;&lt;/span&gt;, {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;event&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;video:play&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;u10086&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;r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;xgroup_create(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mq:events&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;group_log&amp;#34;&lt;/span&gt;, id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;, mkstream&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&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;messages &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;xreadgroup(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    groupname&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;group_log&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    consumername&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;worker_1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    streams&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mq:events&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;gt;&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    count&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    block&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5000&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;for&lt;/span&gt; stream, entries &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; messages:
&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; msg_id, fields &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; entries:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        process(fields)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        r&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;xack(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mq:events&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;group_log&amp;#34;&lt;/span&gt;, msg_id)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;优点&lt;/strong&gt;：支持消费者组、ACK、消息回溯。&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;List&lt;/td&gt;
					&lt;td&gt;简单任务队列&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Pub/Sub&lt;/td&gt;
					&lt;td&gt;实时广播&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Stream&lt;/td&gt;
					&lt;td&gt;生产级消息队列&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;p&gt;《Redis in Action》的核心思想可以概括为一句话：&lt;strong&gt;把 Redis 当成内存里的数据结构工具箱，而不是数据库&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Redis 适合&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓存加速（会话、配置、热点数据）。&lt;/li&gt;
&lt;li&gt;实时计算（排行榜、计数器、限流、秒杀）。&lt;/li&gt;
&lt;li&gt;异步解耦（List / Pub/Sub / Stream）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Redis 不适合&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;控制 Key 大小、设置合理 TTL、配置淘汰策略、慎用阻塞命令、理解持久化边界&lt;/strong&gt;。Redis 用好了是神兵利器，用错了就是生产事故的导火索。&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>
