<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>缓存策略 on 洛克里亚的五度 博客</title>
    <link>https://lv-blog.pages.dev/tags/%E7%BC%93%E5%AD%98%E7%AD%96%E7%95%A5/</link>
    <description>Recent content in 缓存策略 on 洛克里亚的五度 博客</description>
    <generator>Hugo</generator>
    <language>zh</language>
    <lastBuildDate>Tue, 05 May 2026 22:46:44 +0800</lastBuildDate>
    <atom:link href="https://lv-blog.pages.dev/tags/%E7%BC%93%E5%AD%98%E7%AD%96%E7%95%A5/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>常见缓存策略精析</title>
      <link>https://lv-blog.pages.dev/posts/programming/backend/redis/common-cache-strategies/</link>
      <pubDate>Tue, 05 May 2026 22:46:44 +0800</pubDate>
      <guid>https://lv-blog.pages.dev/posts/programming/backend/redis/common-cache-strategies/</guid>
      <description>&lt;h1 id=&#34;缓存三兄弟&#34;&gt;缓存三兄弟&lt;/h1&gt;
&lt;h2 id=&#34;缓存穿透&#34;&gt;缓存穿透&lt;/h2&gt;
&lt;p&gt;是什么：大量请求查询数据库不存在的数据。缓存没有，持续击打数据库
防范方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;缓存空值
&lt;ol&gt;
&lt;li&gt;数据库查不到也往缓存放一个空标记（TTL短，2分钟，该TTL过期了才能进行再次数据库查询）&lt;/li&gt;
&lt;li&gt;下一次同样的id来了直接被挡住&lt;/li&gt;
&lt;li&gt;优点：有效拦截大量穿透请求&lt;/li&gt;
&lt;li&gt;缺点：
&lt;ol&gt;
&lt;li&gt;恶意攻击造成大量不同的不存在的key，缓存堆满无效数据，浪费内存&lt;/li&gt;
&lt;li&gt;延迟了数据一致性，新数据必须等缓存过期&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;布隆过滤器&lt;/strong&gt;（推荐）
&lt;ol&gt;
&lt;li&gt;启动时把所有合法id放入布隆过滤器；&lt;/li&gt;
&lt;li&gt;布隆过滤器不给进就真的没有；&lt;/li&gt;
&lt;li&gt;优点：
&lt;ol&gt;
&lt;li&gt;没有高内存占用风险&lt;/li&gt;
&lt;li&gt;没有数据一致性风险&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;缺点：
&lt;ol&gt;
&lt;li&gt;有极小误判率&lt;/li&gt;
&lt;li&gt;增删要维护。数据更新时，要同步更新布隆过滤器&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;接口层限流和校验
&lt;ol&gt;
&lt;li&gt;API网关或Controller层做拦截&lt;/li&gt;
&lt;li&gt;参数校验、限流降级&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;互斥锁重建
&lt;ol&gt;
&lt;li&gt;互斥锁主要解决缓存击穿（热点key过期），但是在缓存空对象场景下，如果有大量并发请求一个不存在的key，可以使用锁&lt;/li&gt;
&lt;li&gt;每次访问让一个线程去查DB，其他线程等待&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;大厂的实践&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;网关层 校验参数格式，IP限流（挡掉脚本攻击）&lt;/li&gt;
&lt;li&gt;过滤器层 布隆过滤器&lt;/li&gt;
&lt;li&gt;缓存层&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;缓存击穿&#34;&gt;缓存击穿&lt;/h2&gt;
&lt;p&gt;是什么：某个被疯狂访问的热点key，因为TTL一到，失效的一瞬间海量并发请求同时miss，同时到DB重建同一个key&lt;/p&gt;
&lt;p&gt;防范方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;互斥锁
&lt;ol&gt;
&lt;li&gt;只让第1个miss的线程去查DB&lt;/li&gt;
&lt;li&gt;其他线程等一下再读缓存
&lt;ol&gt;
&lt;li&gt;高一致性：线程傻傻等待&lt;/li&gt;
&lt;li&gt;低一致性：先给旧数据，下一次来查就是新的&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;逻辑过期
&lt;ol&gt;
&lt;li&gt;key永不物理过期，把过期时间存在value里面&lt;/li&gt;
&lt;li&gt;如果发现逻辑上过期了，异步开个线程重建&lt;/li&gt;
&lt;li&gt;当前请求先返回旧值&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;互斥锁的实现&#34;&gt;互斥锁的实现&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;如何搭建出正确的锁？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;v1：SETNX key 1 抢锁，DEL key 释放&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SETNX=&amp;ldquo;不存在才设置成功&amp;rdquo;，天然互斥。但问题：抢到锁的线程崩了、DEL 没执行 → 锁永远不释放 → 死锁。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;v2：给锁加过期间&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;崩了也能自动过期。但关键：必须用一条原子命令 SET key value NX EX 30。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;陷阱：别写成 SETNX + 再 EXPIRE 两条——如果刚 SETNX 成功、还没 EXPIRE 就崩了，又变回 v1 的死锁。&amp;ldquo;抢锁&amp;quot;和&amp;quot;设过期&amp;quot;必须一步做完。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
