<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>高并发 on 吾爱主机</title><link>https://blog.waihost.com/tags/%E9%AB%98%E5%B9%B6%E5%8F%91/</link><description>Recent content in 高并发 on 吾爱主机</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Mon, 13 Jul 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://blog.waihost.com/tags/%E9%AB%98%E5%B9%B6%E5%8F%91/index.xml" rel="self" type="application/rss+xml"/><item><title>Redis 缓存穿透、击穿与雪崩：原理、场景与工程解法</title><link>https://blog.waihost.com/posts/redis-cache-penetration-breakdown-avalanche/</link><pubDate>Mon, 13 Jul 2026 00:00:00 +0800</pubDate><guid>https://blog.waihost.com/posts/redis-cache-penetration-breakdown-avalanche/</guid><description>&lt;img src="https://blog.waihost.com/images/covers/redis-cache-penetration-breakdown-avalanche.svg" alt="Featured image of post Redis 缓存穿透、击穿与雪崩：原理、场景与工程解法" /&gt;&lt;p&gt;在高并发系统里，Redis 常常被放在数据库前面做读加速。一旦缓存设计不当，问题往往不是“Redis 慢一点”，而是数据库被瞬间打穿。工程上最常见、也最容易被混为一谈的三类故障是：&lt;strong&gt;缓存穿透&lt;/strong&gt;、&lt;strong&gt;缓存击穿&lt;/strong&gt;和&lt;strong&gt;缓存雪崩&lt;/strong&gt;。&lt;/p&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;缓存穿透&lt;/td&gt;
					&lt;td&gt;查的是不存在的数据，缓存和 DB 都没有&lt;/td&gt;
					&lt;td&gt;恶意或异常请求反复打到 DB&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;缓存击穿&lt;/td&gt;
					&lt;td&gt;某个热点 key 刚好过期&lt;/td&gt;
					&lt;td&gt;同一时刻大量请求打到 DB&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;缓存雪崩&lt;/td&gt;
					&lt;td&gt;大量 key 同时失效，或缓存层整体不可用&lt;/td&gt;
					&lt;td&gt;系统级读流量直接压垮 DB&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;本文从现象、根因、可落地方案三层拆开，并结合 Redis 官方能力（&lt;code&gt;SET&lt;/code&gt; 的 &lt;code&gt;NX/EX&lt;/code&gt;、&lt;code&gt;EXPIRE&lt;/code&gt;、淘汰策略、分布式锁模式）给出可复用实践。&lt;/p&gt;
&lt;h2 id="一先把请求路径画清楚"&gt;&lt;a href="#%e4%b8%80%e5%85%88%e6%8a%8a%e8%af%b7%e6%b1%82%e8%b7%af%e5%be%84%e7%94%bb%e6%b8%85%e6%a5%9a" class="header-anchor"&gt;&lt;/a&gt;一、先把请求路径画清楚
&lt;/h2&gt;&lt;p&gt;一个典型读路径是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Client -&amp;gt; App -&amp;gt; Redis -&amp;gt; (miss) -&amp;gt; Database -&amp;gt; write back Redis -&amp;gt; response
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;缓存层的价值在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;把高频读从数据库剥离出来；&lt;/li&gt;
&lt;li&gt;用更低延迟响应热点数据；&lt;/li&gt;
&lt;li&gt;给数据库争取容量和稳定性。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，任何“绕过缓存直接打 DB”的路径，都要被当成故障设计点来处理。&lt;/p&gt;
&lt;h2 id="二缓存穿透查不存在的数据"&gt;&lt;a href="#%e4%ba%8c%e7%bc%93%e5%ad%98%e7%a9%bf%e9%80%8f%e6%9f%a5%e4%b8%8d%e5%ad%98%e5%9c%a8%e7%9a%84%e6%95%b0%e6%8d%ae" class="header-anchor"&gt;&lt;/a&gt;二、缓存穿透：查不存在的数据
&lt;/h2&gt;&lt;h3 id="1-现象"&gt;&lt;a href="#1-%e7%8e%b0%e8%b1%a1" class="header-anchor"&gt;&lt;/a&gt;1. 现象
&lt;/h3&gt;&lt;p&gt;请求的 key 在业务上不存在，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户 ID &lt;code&gt;-1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;商品 ID &lt;code&gt;999999999&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;被爬虫扫出来的非法参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此时 Redis 没有缓存，数据库也查不到记录。如果应用只在“查到结果时才写缓存”，那么每次请求都会落到数据库。&lt;/p&gt;
&lt;h3 id="2-根因"&gt;&lt;a href="#2-%e6%a0%b9%e5%9b%a0" class="header-anchor"&gt;&lt;/a&gt;2. 根因
&lt;/h3&gt;&lt;p&gt;穿透的本质不是“缓存过期”，而是：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;空结果没有被负缓存（negative caching）保护。&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="3-解法"&gt;&lt;a href="#3-%e8%a7%a3%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;3. 解法
&lt;/h3&gt;&lt;h4 id="方案-a缓存空对象最常用"&gt;&lt;a href="#%e6%96%b9%e6%a1%88-a%e7%bc%93%e5%ad%98%e7%a9%ba%e5%af%b9%e8%b1%a1%e6%9c%80%e5%b8%b8%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;方案 A：缓存空对象（最常用）
&lt;/h4&gt;&lt;p&gt;查库为空时，也写入一个短 TTL 的空值标记：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 伪命令：空结果缓存 60 秒&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SET product:999999999 __NULL__ EX &lt;span class="m"&gt;60&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应用读到 &lt;code&gt;__NULL__&lt;/code&gt; 时直接返回“不存在”，不再访问数据库。&lt;/p&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TTL 不要太长，避免真实数据刚创建后长时间读不到；&lt;/li&gt;
&lt;li&gt;空值要有统一约定，避免和正常业务值冲突；&lt;/li&gt;
&lt;li&gt;对写路径做缓存失效/更新，保证最终一致。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="方案-b布隆过滤器bloom-filter前置拦截"&gt;&lt;a href="#%e6%96%b9%e6%a1%88-b%e5%b8%83%e9%9a%86%e8%bf%87%e6%bb%a4%e5%99%a8bloom-filter%e5%89%8d%e7%bd%ae%e6%8b%a6%e6%88%aa" class="header-anchor"&gt;&lt;/a&gt;方案 B：布隆过滤器（Bloom Filter）前置拦截
&lt;/h4&gt;&lt;p&gt;对“可能存在”的 ID 集合做布隆过滤器：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数据写入时同步/异步加入过滤器；&lt;/li&gt;
&lt;li&gt;查询前先判断“一定不存在还是可能存在”；&lt;/li&gt;
&lt;li&gt;一定不存在则直接拒绝，不打 Redis/DB。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;适合海量 ID、爬虫扫描、开放查询接口。代价是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有极低误判率（把不存在判断成可能存在）；&lt;/li&gt;
&lt;li&gt;需要维护过滤器更新与扩容。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="方案-c参数与权限校验前置"&gt;&lt;a href="#%e6%96%b9%e6%a1%88-c%e5%8f%82%e6%95%b0%e4%b8%8e%e6%9d%83%e9%99%90%e6%a0%a1%e9%aa%8c%e5%89%8d%e7%bd%ae" class="header-anchor"&gt;&lt;/a&gt;方案 C：参数与权限校验前置
&lt;/h4&gt;&lt;p&gt;很多穿透其实是脏流量：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;非数字 ID&lt;/li&gt;
&lt;li&gt;超范围分页&lt;/li&gt;
&lt;li&gt;未登录却访问私有资源&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在网关/应用入口直接拦截，比把压力交给缓存更划算。&lt;/p&gt;
&lt;h2 id="三缓存击穿热点-key-刚好失效"&gt;&lt;a href="#%e4%b8%89%e7%bc%93%e5%ad%98%e5%87%bb%e7%a9%bf%e7%83%ad%e7%82%b9-key-%e5%88%9a%e5%a5%bd%e5%a4%b1%e6%95%88" class="header-anchor"&gt;&lt;/a&gt;三、缓存击穿：热点 key 刚好失效
&lt;/h2&gt;&lt;h3 id="1-现象-1"&gt;&lt;a href="#1-%e7%8e%b0%e8%b1%a1-1" class="header-anchor"&gt;&lt;/a&gt;1. 现象
&lt;/h3&gt;&lt;p&gt;某个非常热的 key（首页配置、秒杀库存视图、热门商品详情）在某一瞬间过期。&lt;br&gt;
下一毫秒，成千上万请求同时看到 miss，一起去查数据库，形成“单点热点打穿”。&lt;/p&gt;
&lt;h3 id="2-根因-1"&gt;&lt;a href="#2-%e6%a0%b9%e5%9b%a0-1" class="header-anchor"&gt;&lt;/a&gt;2. 根因
&lt;/h3&gt;&lt;p&gt;击穿关注的是：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;单个热点 key 过期窗口内的并发回源。&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;它和穿透不同：数据本来存在，只是缓存刚好空了。&lt;/p&gt;
&lt;h3 id="3-解法-1"&gt;&lt;a href="#3-%e8%a7%a3%e6%b3%95-1" class="header-anchor"&gt;&lt;/a&gt;3. 解法
&lt;/h3&gt;&lt;h4 id="方案-a互斥重建singleflight--分布式锁"&gt;&lt;a href="#%e6%96%b9%e6%a1%88-a%e4%ba%92%e6%96%a5%e9%87%8d%e5%bb%basingleflight--%e5%88%86%e5%b8%83%e5%bc%8f%e9%94%81" class="header-anchor"&gt;&lt;/a&gt;方案 A：互斥重建（singleflight / 分布式锁）
&lt;/h4&gt;&lt;p&gt;只有一个请求负责回源重建，其他请求等待或短暂失败重试。&lt;/p&gt;
&lt;p&gt;Redis 官方 &lt;code&gt;SET&lt;/code&gt; 支持原子条件写入，可用 &lt;code&gt;NX + EX&lt;/code&gt; 做互斥：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 抢重建锁，5 秒自动过期，防止进程崩溃后死锁&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SET rebuild:lock:product:1001 &lt;span class="m"&gt;1&lt;/span&gt; NX EX &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;读缓存 miss；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SET lock NX EX&lt;/code&gt; 抢锁；&lt;/li&gt;
&lt;li&gt;抢到锁的请求查 DB，写回缓存，释放锁；&lt;/li&gt;
&lt;li&gt;没抢到锁的请求短暂 sleep/重试读缓存，或返回旧兜底。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;官方文档明确：&lt;code&gt;SET key value NX EX seconds&lt;/code&gt; 是设置值并带过期时间的常用原子写法；&lt;code&gt;SETNX&lt;/code&gt; 在新代码中更推荐用 &lt;code&gt;SET ... NX&lt;/code&gt; 替代。&lt;/p&gt;
&lt;h4 id="方案-b逻辑过期logical-expire"&gt;&lt;a href="#%e6%96%b9%e6%a1%88-b%e9%80%bb%e8%be%91%e8%bf%87%e6%9c%9flogical-expire" class="header-anchor"&gt;&lt;/a&gt;方案 B：逻辑过期（logical expire）
&lt;/h4&gt;&lt;p&gt;缓存 value 内嵌业务过期时间，物理 key 不过期或过期很久：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;price&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;expireAt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1720857600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;读取时：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;未逻辑过期：直接返回；&lt;/li&gt;
&lt;li&gt;已逻辑过期：返回旧数据，同时异步触发重建。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;优点是用户几乎无感 miss；代价是要接受短暂脏读，并做好异步重建失败补偿。&lt;/p&gt;
&lt;h4 id="方案-c热点-key-永不过期--主动更新"&gt;&lt;a href="#%e6%96%b9%e6%a1%88-c%e7%83%ad%e7%82%b9-key-%e6%b0%b8%e4%b8%8d%e8%bf%87%e6%9c%9f--%e4%b8%bb%e5%8a%a8%e6%9b%b4%e6%96%b0" class="header-anchor"&gt;&lt;/a&gt;方案 C：热点 key 永不过期 + 主动更新
&lt;/h4&gt;&lt;p&gt;对真正的超级热点，不依赖 TTL 被动失效，而由写路径/定时任务主动更新。&lt;br&gt;
TTL 更适合普通数据；热点数据更适合“写时更新 + 监控”。&lt;/p&gt;
&lt;h2 id="四缓存雪崩大面积失效或缓存层故障"&gt;&lt;a href="#%e5%9b%9b%e7%bc%93%e5%ad%98%e9%9b%aa%e5%b4%a9%e5%a4%a7%e9%9d%a2%e7%a7%af%e5%a4%b1%e6%95%88%e6%88%96%e7%bc%93%e5%ad%98%e5%b1%82%e6%95%85%e9%9a%9c" class="header-anchor"&gt;&lt;/a&gt;四、缓存雪崩：大面积失效或缓存层故障
&lt;/h2&gt;&lt;h3 id="1-现象-2"&gt;&lt;a href="#1-%e7%8e%b0%e8%b1%a1-2" class="header-anchor"&gt;&lt;/a&gt;1. 现象
&lt;/h3&gt;&lt;p&gt;两类雪崩最常见：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;过期雪崩&lt;/strong&gt;：大量 key 在同一时间点过期；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可用性雪崩&lt;/strong&gt;：Redis 集群故障、网络分区、连接打满，导致缓存层整体不可用。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;结果都是数据库在短时间内接到远超容量的读请求。&lt;/p&gt;
&lt;h3 id="2-根因-2"&gt;&lt;a href="#2-%e6%a0%b9%e5%9b%a0-2" class="header-anchor"&gt;&lt;/a&gt;2. 根因
&lt;/h3&gt;&lt;p&gt;雪崩的核心不是某一个 key，而是：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;缓存保护面在同一时间失效，流量失去缓冲层。&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="3-解法-2"&gt;&lt;a href="#3-%e8%a7%a3%e6%b3%95-2" class="header-anchor"&gt;&lt;/a&gt;3. 解法
&lt;/h3&gt;&lt;h4 id="方案-attl-加随机抖动"&gt;&lt;a href="#%e6%96%b9%e6%a1%88-attl-%e5%8a%a0%e9%9a%8f%e6%9c%ba%e6%8a%96%e5%8a%a8" class="header-anchor"&gt;&lt;/a&gt;方案 A：TTL 加随机抖动
&lt;/h4&gt;&lt;p&gt;不要让同类数据使用完全相同的过期时间：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ttl = base_ttl + random(0, jitter)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 例如 3600 + random(0, 300)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样可以把过期曲线打散，避免整点集体回源。&lt;/p&gt;
&lt;h4 id="方案-b多级缓存与本地缓存"&gt;&lt;a href="#%e6%96%b9%e6%a1%88-b%e5%a4%9a%e7%ba%a7%e7%bc%93%e5%ad%98%e4%b8%8e%e6%9c%ac%e5%9c%b0%e7%bc%93%e5%ad%98" class="header-anchor"&gt;&lt;/a&gt;方案 B：多级缓存与本地缓存
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;本地 Caffeine/Guava Cache 挡住进程内重复读；&lt;/li&gt;
&lt;li&gt;Redis 作为分布式缓存；&lt;/li&gt;
&lt;li&gt;DB 作为最终数据源。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本地缓存 TTL 更短，可显著降低 Redis 抖动对 DB 的传导。&lt;/p&gt;
&lt;h4 id="方案-c限流熔断降级"&gt;&lt;a href="#%e6%96%b9%e6%a1%88-c%e9%99%90%e6%b5%81%e7%86%94%e6%96%ad%e9%99%8d%e7%ba%a7" class="header-anchor"&gt;&lt;/a&gt;方案 C：限流、熔断、降级
&lt;/h4&gt;&lt;p&gt;缓存层异常时，应用不能无脑回源：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对回源 QPS 做令牌桶/漏桶限流；&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;h4 id="方案-d正确使用-redis-内存淘汰策略"&gt;&lt;a href="#%e6%96%b9%e6%a1%88-d%e6%ad%a3%e7%a1%ae%e4%bd%bf%e7%94%a8-redis-%e5%86%85%e5%ad%98%e6%b7%98%e6%b1%b0%e7%ad%96%e7%95%a5" class="header-anchor"&gt;&lt;/a&gt;方案 D：正确使用 Redis 内存淘汰策略
&lt;/h4&gt;&lt;p&gt;当 Redis 用作缓存时，官方建议配置最大内存和淘汰策略，以便内存触顶时按策略驱逐 key，而不是写失败或无规划崩溃。常见策略包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;allkeys-lru&lt;/code&gt; / &lt;code&gt;allkeys-lfu&lt;/code&gt;：在全部 key 中淘汰；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;volatile-lru&lt;/code&gt; / &lt;code&gt;volatile-lfu&lt;/code&gt; / &lt;code&gt;volatile-ttl&lt;/code&gt;：只在设置了过期时间的 key 中淘汰。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;缓存场景应显式设置 &lt;code&gt;maxmemory&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;按业务选择 LRU/LFU；&lt;/li&gt;
&lt;li&gt;监控 &lt;code&gt;evicted_keys&lt;/code&gt;、命中率、内存使用，避免“默默淘汰关键数据”却无人知晓。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;淘汰策略解决的是&lt;strong&gt;内存压力下的可持续性&lt;/strong&gt;，不能替代业务层的穿透/击穿防护，但能降低缓存层自身失控概率。&lt;/p&gt;
&lt;h2 id="五一套可落地的组合策略"&gt;&lt;a href="#%e4%ba%94%e4%b8%80%e5%a5%97%e5%8f%af%e8%90%bd%e5%9c%b0%e7%9a%84%e7%bb%84%e5%90%88%e7%ad%96%e7%95%a5" class="header-anchor"&gt;&lt;/a&gt;五、一套可落地的组合策略
&lt;/h2&gt;&lt;p&gt;真实系统很少只选一种方案，更常见的是分层组合：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1. 入口校验：挡住非法参数
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. 布隆过滤器/存在性索引：挡住明显不存在的 key
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. Redis 读：命中则返回
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4. miss 时：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 热点 key：互斥重建或逻辑过期
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 普通 key：允许有限并发回源
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5. DB 空结果：写短 TTL 空缓存
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6. DB 有结果：写缓存，TTL 加抖动
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;7. 全链路：限流 + 熔断 + 监控告警
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="伪代码示例"&gt;&lt;a href="#%e4%bc%aa%e4%bb%a3%e7%a0%81%e7%a4%ba%e4%be%8b" class="header-anchor"&gt;&lt;/a&gt;伪代码示例
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;valid_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;bloom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;might_contain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;product:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;__NULL__&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 热点互斥重建&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;locked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rebuild:lock:product:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;locked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;get_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 简化：重试读缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;product:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;__NULL__&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;product:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rebuild:lock:product:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SET ... NX EX&lt;/code&gt; 用于短锁，避免击穿时并发回源；&lt;/li&gt;
&lt;li&gt;空值缓存用于防穿透；&lt;/li&gt;
&lt;li&gt;TTL 抖动用于打散过期，降低雪崩概率。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="六排查清单线上怎么快速判断是哪一种"&gt;&lt;a href="#%e5%85%ad%e6%8e%92%e6%9f%a5%e6%b8%85%e5%8d%95%e7%ba%bf%e4%b8%8a%e6%80%8e%e4%b9%88%e5%bf%ab%e9%80%9f%e5%88%a4%e6%96%ad%e6%98%af%e5%93%aa%e4%b8%80%e7%a7%8d" class="header-anchor"&gt;&lt;/a&gt;六、排查清单：线上怎么快速判断是哪一种
&lt;/h2&gt;&lt;h3 id="1-先看指标"&gt;&lt;a href="#1-%e5%85%88%e7%9c%8b%e6%8c%87%e6%a0%87" class="header-anchor"&gt;&lt;/a&gt;1. 先看指标
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Redis 命中率是否骤降&lt;/li&gt;
&lt;li&gt;Redis 连接数/超时是否升高&lt;/li&gt;
&lt;li&gt;数据库 QPS、慢查询、连接池是否打满&lt;/li&gt;
&lt;li&gt;是否集中在某几个 key，还是大面积 key&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-判断路径"&gt;&lt;a href="#2-%e5%88%a4%e6%96%ad%e8%b7%af%e5%be%84" class="header-anchor"&gt;&lt;/a&gt;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;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;大量非法/不存在 ID，DB 查空很多&lt;/td&gt;
					&lt;td&gt;穿透&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;单个热 key 流量尖峰，过期瞬间 DB 飙升&lt;/td&gt;
					&lt;td&gt;击穿&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;整点或批次任务后大面积 miss&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;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="3-临时止血"&gt;&lt;a href="#3-%e4%b8%b4%e6%97%b6%e6%ad%a2%e8%a1%80" class="header-anchor"&gt;&lt;/a&gt;3. 临时止血
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;对异常查询参数限流；&lt;/li&gt;
&lt;li&gt;对热点 key 预热并临时延长 TTL；&lt;/li&gt;
&lt;li&gt;打开空值缓存；&lt;/li&gt;
&lt;li&gt;给 DB 回源加总开关/配额；&lt;/li&gt;
&lt;li&gt;非核心读降级。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="七设计原则总结"&gt;&lt;a href="#%e4%b8%83%e8%ae%be%e8%ae%a1%e5%8e%9f%e5%88%99%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;七、设计原则总结
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;缓存不是数据库的影子，是保护层。&lt;/strong&gt; 任何 miss 路径都要有预算。&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; 相同 TTL 是雪崩温床，抖动是基本操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓存故障要有降级。&lt;/strong&gt; 没有限流和熔断的缓存架构，只是把风险延后到数据库。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可观测性比“感觉很快”更重要。&lt;/strong&gt; 命中率、回源 QPS、淘汰数、锁竞争都要可监控。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="八什么时候不该过度设计"&gt;&lt;a href="#%e5%85%ab%e4%bb%80%e4%b9%88%e6%97%b6%e5%80%99%e4%b8%8d%e8%af%a5%e8%bf%87%e5%ba%a6%e8%ae%be%e8%ae%a1" class="header-anchor"&gt;&lt;/a&gt;八、什么时候不该过度设计
&lt;/h2&gt;&lt;p&gt;不是所有系统都要上布隆过滤器 + 逻辑过期 + 多级缓存：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;读 QPS 不高、数据几乎都存在：做好空值缓存和基础 TTL 即可；&lt;/li&gt;
&lt;li&gt;写极少、读极多的配置类数据：适合主动更新 + 较长 TTL；&lt;/li&gt;
&lt;li&gt;强一致要求极高的余额/库存：缓存只能做辅助，核心以数据库/专用组件为准，并明确一致性模型。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;架构选择应匹配流量模型和一致性要求，而不是堆名词。&lt;/p&gt;
&lt;h2 id="总结"&gt;&lt;a href="#%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h2&gt;&lt;p&gt;缓存穿透、击穿、雪崩并不是三个神秘黑话，而是三条清晰的失败路径：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;穿透&lt;/strong&gt;：不存在的数据反复打穿 DB；&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;/ul&gt;
&lt;p&gt;把问题定义清楚后，解法会自然收敛到：入口校验、空值缓存、互斥重建、TTL 抖动、淘汰策略、限流熔断与监控。&lt;br&gt;
Redis 提供了 &lt;code&gt;SET NX/EX&lt;/code&gt;、&lt;code&gt;EXPIRE&lt;/code&gt;、内存淘汰和分布式锁模式等基础能力，但真正决定系统稳不稳的，是你有没有把这些能力嵌进完整的读路径设计里。&lt;/p&gt;
&lt;h2 id="参考资料"&gt;&lt;a href="#%e5%8f%82%e8%80%83%e8%b5%84%e6%96%99" class="header-anchor"&gt;&lt;/a&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Redis 官方文档：&lt;a class="link" href="https://redis.io/docs/latest/commands/set/" target="_blank" rel="noopener"
 &gt;&lt;code&gt;SET&lt;/code&gt; 命令&lt;/a&gt;（含 &lt;code&gt;NX&lt;/code&gt; / &lt;code&gt;EX&lt;/code&gt; 等选项）&lt;/li&gt;
&lt;li&gt;Redis 官方文档：&lt;a class="link" href="https://redis.io/docs/latest/commands/expire/" target="_blank" rel="noopener"
 &gt;&lt;code&gt;EXPIRE&lt;/code&gt; 命令&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redis 官方文档：&lt;a class="link" href="https://redis.io/docs/latest/commands/setnx/" target="_blank" rel="noopener"
 &gt;&lt;code&gt;SETNX&lt;/code&gt; 命令&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redis 官方文档：&lt;a class="link" href="https://redis.io/docs/latest/develop/reference/eviction/" target="_blank" rel="noopener"
 &gt;Key eviction 内存淘汰策略&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redis 官方文档：&lt;a class="link" href="https://redis.io/docs/latest/develop/use/patterns/distributed-locks/" target="_blank" rel="noopener"
 &gt;Distributed locks 分布式锁模式&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>