<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Redis on 追风笔记</title><link>https://4f0a9a3b.wangpeng.pages.dev/tags/redis/</link><description>Recent content in Redis on 追风笔记</description><generator>Hugo</generator><language>zh</language><lastBuildDate>Tue, 25 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://4f0a9a3b.wangpeng.pages.dev/tags/redis/index.xml" rel="self" type="application/rss+xml"/><item><title>Redis 数据结构与底层实现</title><link>https://4f0a9a3b.wangpeng.pages.dev/tech/redis/data-structures/</link><pubDate>Tue, 25 Aug 2026 00:00:00 +0000</pubDate><guid>https://4f0a9a3b.wangpeng.pages.dev/tech/redis/data-structures/</guid><description>&lt;p&gt;Redis 对外暴露五种常用类型，但底层有多种编码（encoding）。根据数据规模自动在不同编码间转换，是它兼顾内存与性能的关键。&lt;/p&gt;&#10;&lt;h2 id="核心底层结构"&gt;核心底层结构&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;SDS（简单动态字符串）&lt;/strong&gt;：相比 C 字符串记录长度、预分配空间，避免缓冲区溢出并支持二进制安全。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ziplist / listpack&lt;/strong&gt;：连续内存的紧凑列表，节省空间，适合小数据量。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;linkedlist&lt;/strong&gt;：双向链表，元素多时替代 ziplist。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;dict（字典）&lt;/strong&gt;：哈希表，使用链地址法解决冲突，渐进式 rehash 避免阻塞。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;skiplist（跳表）&lt;/strong&gt;：多层有序链表，结合 dict 实现 zset，范围查询高效。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="各类型的编码与转换"&gt;各类型的编码与转换&#10;&lt;/h2&gt;&#10;&lt;div class="td-table-scroll td-table-scroll--static"&gt;&#10;&lt;table&gt;&#10; &lt;thead&gt;&#10; &lt;tr&gt;&#10; &lt;th scope="col"&gt;类型&lt;/th&gt;&#10; &lt;th scope="col"&gt;小数据编码&lt;/th&gt;&#10; &lt;th scope="col"&gt;大数据编码&lt;/th&gt;&#10; &lt;th scope="col"&gt;转换阈值（示意）&lt;/th&gt;&#10; &lt;/tr&gt;&#10; &lt;/thead&gt;&#10; &lt;tbody&gt;&#10; &lt;tr&gt;&#10; &lt;td&gt;string&lt;/td&gt;&#10; &lt;td&gt;int / embstr&lt;/td&gt;&#10; &lt;td&gt;raw&lt;/td&gt;&#10; &lt;td&gt;长度 &amp;gt; 44 字节转 raw&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td&gt;hash&lt;/td&gt;&#10; &lt;td&gt;ziplist/listpack&lt;/td&gt;&#10; &lt;td&gt;hashtable&lt;/td&gt;&#10; &lt;td&gt;元素数或单个值超阈值&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td&gt;list&lt;/td&gt;&#10; &lt;td&gt;quicklist（ziplist 片段）&lt;/td&gt;&#10; &lt;td&gt;quicklist&lt;/td&gt;&#10; &lt;td&gt;—&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td&gt;set&lt;/td&gt;&#10; &lt;td&gt;intset&lt;/td&gt;&#10; &lt;td&gt;hashtable&lt;/td&gt;&#10; &lt;td&gt;含非整数或元素过多&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td&gt;zset&lt;/td&gt;&#10; &lt;td&gt;ziplist&lt;/td&gt;&#10; &lt;td&gt;skiplist+dict&lt;/td&gt;&#10; &lt;td&gt;元素数或值长度超阈值&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;p&gt;以 &lt;code&gt;zset&lt;/code&gt; 为例，小数据使用 ziplist 紧凑存储（member 与 score 相邻），当元素数量或单个 member 长度超过阈值时转为 &lt;code&gt;skiplist + dict&lt;/code&gt;，保证有序遍历与按 member 查找都为 O(1)/O(log n)。&lt;/p&gt;&#10;&lt;div class="td-code td-code--untitled" id="td-code-d3cd55a5-fence-0" data-td-code data-td-code-auto-id&#10; data-td-language="text" data-td-line-count="2"&gt;&#10; &lt;div class="td-code__viewport" id="td-code-d3cd55a5-fence-0-viewport" data-td-code-viewport&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;zset 小: [member1, score1, member2, score2, ...] (ziplist)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zset 大: dict(member-&amp;gt;score) + skiplist(score-&amp;gt;member)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;理解这些阈值有助于解释「为什么小哈希比单独 key 省内存」，也提醒我们避免让单个 key 堆积过多元素，否则编码升级或操作耗时都会陡增。&lt;/p&gt;</description></item><item><title>Redis 缓存设计</title><link>https://4f0a9a3b.wangpeng.pages.dev/tech/redis/cache-design/</link><pubDate>Tue, 25 Aug 2026 00:00:00 +0000</pubDate><guid>https://4f0a9a3b.wangpeng.pages.dev/tech/redis/cache-design/</guid><description>&lt;p&gt;引入缓存能显著降低数据库压力，但设计不当会引入穿透、击穿、雪崩等经典问题。下面逐一拆解成因与对策。&lt;/p&gt;&#10;&lt;h2 id="三大经典问题"&gt;三大经典问题&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;缓存穿透&lt;/strong&gt;：查询不存在的数据，缓存与数据库都查不到，请求每次都打到 DB。应对：缓存空值（短过期）、布隆过滤器拦截非法 key。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;缓存击穿&lt;/strong&gt;：某个热点 key 过期瞬间，大量并发同时回源 DB。应对：互斥锁（只放一个线程重建）、逻辑过期（异步刷新）、热点 key 不过期。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;缓存雪崩&lt;/strong&gt;：大量 key 同一时刻集中失效，或 Redis 整体不可用，DB 被冲垮。应对：过期时间加随机抖动、多级缓存、Redis 高可用（哨兵/集群）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="cache-aside-与一致性"&gt;Cache-Aside 与一致性&#10;&lt;/h2&gt;&#10;&lt;p&gt;最常用的是 &lt;strong&gt;Cache-Aside（旁路缓存）&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;div class="td-code td-code--untitled" id="td-code-9a055417-fence-0" data-td-code data-td-code-auto-id&#10; data-td-language="text" data-td-line-count="2"&gt;&#10; &lt;div class="td-code__viewport" id="td-code-9a055417-fence-0-viewport" data-td-code-viewport&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;读: 先读缓存 -&amp;gt; 命中返回; 未命中读 DB -&amp;gt; 写入缓存&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;写: 先更新 DB -&amp;gt; 再删除缓存 (而非更新缓存)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;「先更新 DB 再删缓存」可降低并发下读到旧值的概率；极端不一致可通过延迟双删或订阅 binlog（如 Canal）补偿。注意：不要盲目「更新缓存」，否则并发写可能产生脏数据。&lt;/p&gt;&#10;&lt;h2 id="大-key-与热-key"&gt;大 key 与热 key&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;大 key&lt;/strong&gt;：如包含百万元素的 hash/list，删除或序列化会阻塞主线程。应对：拆分、分批删除（&lt;code&gt;unlink&lt;/code&gt;）、定期清理。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;热 key&lt;/strong&gt;：单个 key 访问极高，单节点成为瓶颈。应对：本地缓存副本、key 打散到多个副本、Redis 集群分片。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="过期与淘汰策略"&gt;过期与淘汰策略&#10;&lt;/h2&gt;&#10;&lt;p&gt;Redis 提供主动 + 惰性两种过期删除，内存不足时按 &lt;code&gt;maxmemory-policy&lt;/code&gt; 淘汰：&lt;/p&gt;</description></item></channel></rss>