From b3277daaae0f497bedb9423814865066025ffb02 Mon Sep 17 00:00:00 2001 From: CyC2018 Date: Mon, 26 Oct 2026 02:34:35 +0800 Subject: [PATCH] =?UTF-8?q?Update=20=E7=BC=93=E5=AD=98.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充大 Key 与热 Key 的问题、发现和处理方法。 --- notes/缓存.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/notes/缓存.md b/notes/缓存.md index 08831347..5e4f6aad 100644 --- a/notes/缓存.md +++ b/notes/缓存.md @@ -154,6 +154,30 @@ CDN 主要有以下优点: - 减少网络通信次数; - 降低接入成本,使用长连接 / 连接池,NIO 等。 +### 大 Key 与热 Key + +大 Key 指的是值很大的键,例如几 MB 的字符串,或者包含几十万个元素的集合;热 Key 指的是访问量远高于其它键的键,例如秒杀商品的库存。 + +大 Key 的问题: + +- 阻塞:Redis 用一个线程执行命令,对大 Key 执行 HGETALL、DEL 这类 O(N) 的命令时,其它命令都要等待。在本机删除一个有 100 万个字段、占用 64 MB 内存的 HASH,DEL 耗时 341 ms,而 UNLINK 只需 35 μs,它在后台线程中释放内存; +- 网络:一次读写的数据量大,占用带宽; +- 数据倾斜:在集群中,大 Key 所在节点的内存和流量都会高于其它节点。 + +大 Key 的发现与处理: + +- 用 redis-cli --bigkeys 或者 --memkeys 扫描,它们使用 SCAN 命令遍历,不会阻塞服务器;用 MEMORY USAGE 查看单个键占用的内存; +- 拆分:例如把一个大的 HASH 按字段的哈希值拆成 16 个小 HASH,user:1001:fav:0 到 user:1001:fav:15; +- 删除用 UNLINK;读取集合时用 HSCAN、SSCAN 分批读取,不要一次读出所有元素。 + +热 Key 的问题是请求集中到同一个节点,集群中其它节点再多也无法分担。处理方法: + +- 发现:redis-cli --hotkeys,它要求淘汰策略为 LFU;也可以在客户端或者代理中统计访问频率; +- 本地缓存:在应用中缓存热 Key 的值,大部分请求不再访问 Redis,代价是数据会有短暂的不一致,见上文的 [本地缓存](#本地缓存); +- 复制多份:把同一个值写到 stock#0 到 stock#9 这 10 个键中,读取时随机选一个。这些键分布在不同的槽上,请求就分散到了多个节点,代价是写入时要更新所有副本。 + +热 Key 过期时大量请求同时打到数据库的问题,见上文的缓存击穿。 + ## 五、数据分布 ### 哈希分布 @@ -342,3 +366,5 @@ public class LRU implements Iterable { - [一致性哈希算法](https://my.oschina.net/jayhu/blog/732849) - [内容分发网络](https://zh.wikipedia.org/wiki/%E5%85%A7%E5%AE%B9%E5%82%B3%E9%81%9E%E7%B6%B2%E8%B7%AF) - [How Aspiration CDN helps to improve your website loading speed?](https://www.aspirationhosting.com/aspiration-cdn/) +- [Redis: UNLINK](https://redis.io/docs/latest/commands/unlink/) +- [Redis CLI](https://redis.io/docs/latest/develop/tools/cli/)