Theory · Redis · Cache Patterns
穿透 / 击穿 / 雪崩 + Cache Aside 双写推演 —— 缓存面试的主战场,每道题都有"问题机制 → 方案 → 边界"三层
穿透(查不存在)、击穿(热点过期)、雪崩(批量过期/宕机)——共同本质:请求越过缓存直打 DB
先更新库再删缓存的主流地位、两个并发时序的反例推演、延迟双删与 binlog 异步删除兜底
判定标准(String>10KB、集合>5000)、UNLINK 惰性删除、热 key 本地缓存与打散
Why Cache Problems Matter
// 一个商品详情接口,大促当天的真实压力分布 读 QPS 30000/s // 峰值,全部要读商品详情 缓存命中率 99.2% // 只有约 240/s 真正落到 MySQL MySQL 承载上限 2000/s // 单实例极限,再多就排队 // 凌晨 03:00,预热脚本把 10 万个商品灌进缓存 SET item:1 {...} EX 1800 // TTL 都是 1800 秒 SET item:2 {...} EX 1800 // ……一模一样 // 03:30:00 —— 10 万个 key 在同一秒集体过期 → 30000/s 全部打到 MySQL(是它上限的 15 倍) → 连接池占满,查询开始排队,响应从 5ms 变 3s → 上游超时后重试,请求量再翻倍 → 03:30:12 全站 502。此时 Redis 完全健康。
30000/s 全程打 MySQL:要么堆到十几台只读从库(成本与运维复杂度都上一个量级),要么接受几百毫秒的响应。缓存用"一份放在内存里的副本 + 允许短暂读到旧值",换掉了"为峰值堆数据库"这件事——这是它存在的唯一理由。
本来只有 MySQL 一个真相来源,现在多了一份可能过期、可能缺失、可能被挤出去的副本。本 deck 讲的四类故障,全都是"两层"这个结构自带的,单层系统里它们根本不存在。
① 穿透:要查的数据本来就不存在,缓存永远填不上,每次都打库;
② 击穿:一个热点 key 恰好过期的那一瞬间,成千请求同时去重建;
③ 雪崩:一大批 key 同时过期(就是上面这场事故),或 Redis 整体挂掉;
④ 双写不一致:库改了、缓存还是旧值——两层存储各说各话。
另外还有两个"单 key 病":大 key(一次操作太重)与热 key(访问太集中)。
先给四种缓存模式的坐标系 → 三大问题各按"机制 → 方案 → 边界"讲透 → 双写一致性的两个并发时序推演(要能手画)→ 大 key / 热 key 的工程治理 → 速查页 + 16 道 QA。读完你应该能回答:"线上打挂了先查什么"和"为什么必须先更库再删缓存"。
Prerequisites & Glossary
| 术语 | 一句话理解(细节后面展开) |
|---|---|
| 命中 / 未命中 (cache hit / miss) | 要读的 key 在缓存里找到了 = 命中;没找到 = 未命中(miss),miss 就得去数据库查 |
| 回填(backfill) | miss 之后从库里查到值,再写回缓存,让下次能命中——三大问题几乎都出在这一步 |
| TTL(Time To Live) | 给 key 设的存活时间,到点自动删除;缓存靠它自动淘汰旧数据 |
| Cache Aside (旁路缓存) | 最主流的用法:应用自己读写缓存和数据库两边,缓存只是"旁边放的一份副本" |
| 双写(dual write) | 一次业务修改要同时改数据库和缓存两个地方——它们无法一起原子成功,这就是不一致的根源 |
| 最终一致 (eventual consistency) | 允许短暂不一致,但保证过一段时间(如 TTL 到期)一定收敛到相同值 |
| QPS | 每秒请求数(Queries Per Second),衡量流量大小的基本单位 |
| 大 key / 热 key | 大 key = 单个 key 体积大或元素多(一次操作很重);热 key = 单个 key 被访问得特别频繁 |
| 单飞 (single-flight) | 同一时刻只让一个请求去重建缓存,其余请求等它的结果——击穿的两个方案都是它的变体 |
| 假阳性 (false positive) | 判断"存在"但其实不存在(误报);布隆过滤器只会误报存在,绝不会漏掉真实存在的 |
过期删除与内存淘汰 → TTL 到期后 Redis 究竟什么时候真删、内存不够时谁被踢掉
单线程模型 → 为什么一条慢命令能卡住所有人(大 key 危害的根源)
分布式锁 → 击穿方案里 SET NX 抢锁的完整细节与坑
主从 / 哨兵 / Cluster → 雪崩第二种成因(实例宕机)的高可用防线
为了不在名词上打转,后面统一说"读 miss 后回填"这一个动作;只有讲具体命令时才出现 SET NX、UNLINK 这类原文。数据库一律以 MySQL 为例,但结论对任何持久化存储都成立。
整份 deck 只围绕一个动作:"读不到就去库里查,查到再放回缓存"。
· 三大问题 = 这句话的前半句失灵(该拦的没拦、同时去查、集体去查);
· 双写一致性 = 这句话的后半句放错了值(放回去的是旧值);
· 大 key / 热 key = 这个动作本身太重或太密。
看到任何新方案,先问它在改哪一段——就不会记成一堆彼此无关的招式。
Caching Patterns Overview
开场那场事故里的写法——应用自己读缓存、miss 后查库回填、写时删缓存——只是四种模式中的一种(Cache Aside)。先把坐标系立起来,才知道后面讨论的一致性问题属于哪一种模式。
| 模式 | 读写路径 | 一致性能力 | 适用与代价 |
|---|---|---|---|
| Cache Aside(旁路缓存,主流) | 应用自己同时读写缓存与 DB:读 miss 回填、写"更新库 + 删缓存" | 最终一致(有并发窗口,见第 8-10 页) | 应用层完全掌控、实现简单;一致性推演是面试核心 |
| Read-Through | 应用只访问缓存层,缓存层负责 miss 时从 DB 加载 | 同 Cache Aside,但逻辑下沉 | 需要缓存组件支持(如代理层);应用更薄 |
| Write-Through | 写请求经缓存层同步写库后写缓存 | 强(写路径双写原子性由缓存层保证) | 写延迟 = 库延迟 + 缓存延迟;冷数据也被写入 |
| Write-Behind(Write-Back) | 先写缓存立即返回,异步批量刷库 | 弱(缓存宕机丢未刷数据) | 写性能极高;需 crash 恢复设计——适合点赞/计数类 |
Read/Write-Through 需要"缓存中间层"承担 DB 访问逻辑,自研组件成本高;Cache Aside 只需应用代码配合(先库后缓存),Redis 官方文档的 caching 场景也按"lazy loading"语义描述——控制权在应用、故障面最小。
"四种模式的差别是'谁来维护缓存与谁对一致性负责':Cache Aside 由应用维护,Through 系列由缓存层维护,Write-Behind 用丢一致性换写性能。业务系统默认 Cache Aside,极少数写密集计数场景考虑 Write-Behind。"
Cache Aside · Read / Write Flow
① 读缓存命中 → 直接返回;② miss → 读 DB → 回填缓存并设置过期时间 → 返回。要点:回填的值来自 DB 读取那一刻,并发下可能回填旧值(第 9 页推演)。
① 更新 DB;② 删除(而非更新)缓存。下次读 miss 自动从 DB 加载最新值。删除失败是唯一残留风险 → 消息队列重试 / binlog 异步删除(第 10 页)。
| 追问:为什么不更新缓存? | 答案 |
|---|---|
| ① 并发写覆盖 | 两个写并发"写 A 值→写缓存"与"写 B 值→写缓存"可能交叉执行,缓存最终落的是先发的旧值;删除是幂等的,不存在覆盖序问题 |
| ② 写多读少浪费 | 每次写都更新缓存,若该 key 读频率低,大量更新白写(还占内存);删除后按需懒加载,只缓存真正被读的值 |
| ③ 更新≠写整对象 | 缓存常是 DB 多表聚合结果(如商品详情),写库只动一列——更新缓存得重算整个聚合;删除让下次读自然重建 |
| ④ 那为什么不"先删缓存再更新库"? | 读并发会把旧值回填进缓存并长期驻留——比"更新缓存"更糟,完整推演见第 9 页 |
Cache Penetration
请求的 key 在缓存和 DB 都不存在(恶意伪造 ID、爬虫扫库):每次都 miss → 打 DB → 查不到 → 无值可回填 → 下次继续 miss。DB 被恒定流量穿透,而不是瞬时脉冲——这是它和击穿的最大区别。
DB 查不到也回填一个占位值(如 "" / 约定 JSON),配短 TTL(秒级~分钟级)。代价:可能内存占用大(大量不同假 key)、且 DB 新插入该 key 后有短暂不一致窗口——TTL 即上限。适合 key 集合有限的场景。
| 方案 | 做法 | 边界与代价 |
|---|---|---|
| 缓存空值 | miss 且 DB 无 → set 占位值 + 短 TTL | 简单有效;防不住海量随机 key(占内存);有插入后的短暂不一致 |
| 布隆过滤器(下页详解) | 全量合法 key 预热进 BF,读前先过 BF,"不存在"直接拒 | 挡在缓存之前,DB 零压力;有假阳性;删除困难 |
| 参数校验 / 风控 | 格式校验(ID 必须 >0、长度/枚举检查)、用户级限流、黑名单 | 治理恶意流量的第一道闸,工程上必做——但防不住"合法格式"的伪造 key |
| 组合拳(推荐答法) | 参数校验 → 布隆过滤器 → 空值缓存兜底 → DB 限流熔断 | 层层递进:每层把更少的流量放进下一层 |
Bloom Filter
Cache Breakdown / Hotspot Invalid
某个高并发热点 key 到期失效的一瞬间,成百上千请求同时 miss → 同时读 DB → 同时回填。DB 承受的是瞬时脉冲(QPS 尖刺),可能直接打挂;常出现于秒杀商品、爆款详情。
穿透:key 根本不存在(恒定流量);击穿:key 存在但恰好过期(单点脉冲);雪崩:大量 key 同时失效或缓存实例整体宕机(全局故障)。流量形态决定方案选型。
| 方案 | 机制 | 优点 | 代价与边界 |
|---|---|---|---|
| 互斥锁重建 | miss 后先 SET lock:hot NX PX 10000 抢锁;抢到的查 DB 回填缓存再释放;没抢到的自旋/睡眠重试读缓存 | 保证 DB 只被一个请求打到;强一致性好 | 其他请求等待有延迟;锁本身可能死(持锁节点挂)→ 必须带 TTL;实现相对复杂 |
| 逻辑过期 | 不设 Redis TTL;value 里内嵌过期时间戳。读到"已逻辑过期"→ 抢互斥锁,抢到的异步线程重建缓存,所有人立即返回旧值 | 零阻塞、体验最好;不真过期就没有击穿窗口 | 短暂返回旧数据(最终一致);内存常驻热点数据;实现要改 value 结构 |
| 热点永不过期 | 热点 key 直接不设 TTL,靠后台定时任务主动刷新 | 最简单 | 内存占用;更新有延迟;不适合大规模使用 |
Cache Avalanche
批量预热的 key 设了相同 TTL(如凌晨统一导入),同一秒集体失效 → 请求洪峰全部压向 DB。本质是"击穿"的规模化。
Redis 宕机 / 网络故障 / 主从切换中,全部请求落到 DB——DB 瞬时过载 → 变慢 → 更多超时 → 雪球滚大。这是故障放大链,也是雪崩最危险的形态。
| 防御层 | 手段 | 要点 |
|---|---|---|
| ① 过期打散 | TTL 加随机抖动:ttl = base + rand(0, 600s);预热任务错峰导入 | 治"同时过期",一行代码消除大头;必答 |
| ② 高可用架构 | 主从 + 哨兵 / Cluster(replication-cluster deck),避免单点;多机房容灾 | 治"实例宕机";与成因二对应 |
| ③ 多级缓存 | 本地缓存(Caffeine / Go: ristretto, bigcache)+ Redis 组成 L1/L2;热点前置到应用内存 | Redis 不可用时 L1 兜住热点读;注意各层一致性窗口与容量控制 |
| ④ 限流熔断降级 | DB 前加限流(令牌桶/信号量)、熔断器、降级返回默认值/静态页;队列削峰异步重建 | 最后的保命层:宁可部分不可用,不让 DB 被"打死"——保护核心链路 |
Cache-DB Consistency · 1/3
Cache-DB Consistency · 2/3
Cache-DB Consistency · 3/3
针对"先删后更"或担心删后回填的业务:删缓存 → 更新库 → 延迟 N(500ms~1s)→ 再删一次。第二次删除清掉并发读回填的旧值,N 要 ≥ 一次"读库+回填"耗时。代价:N 是经验值、延迟删除需异步执行。
业务只管写库;Canal 伪装成 MySQL 从库订阅 binlog → 解析变更行 → 投 MQ → 消费端删对应缓存。把"删缓存"从业务里剥离:重试、幂等、顺序都交给中间件,删失败可无限重试直到成功。
所有 key 必须设 TTL:即使删除链路彻底失败(进程挂、MQ 丢),不一致也最多持续到 TTL 到期。TTL 长度 = 业务能容忍的最大不一致窗口——用"最终一致"给整个方案封顶。
| 方案 | 解决什么 | 成本 | 适用 |
|---|---|---|---|
| 先更新库 + 删缓存(基础) | 绝大多数场景,窗口毫秒级 | 最低(两行代码) | 默认起点;配合 TTL 已满足多数业务 |
| 延迟双删 | 极端读写交错下的旧值回填 | 低(+一次延迟删除) | 没上 MQ 的中小系统快速加固 |
| binlog 订阅删除 | 删除失败重试、解耦业务、多缓存统一失效 | 中(Canal+MQ 基建) | 一致性要求高、写路径复杂的核心系统 |
| TTL 兜底 | 一切兜不住的尾部风险 | 零 | 无条件必配 |
Big Keys
String 的 value > 10KB;集合类型(List/Hash/Set/ZSet)元素个数 > 5000。危害与元素总量相关而不仅是单元素大小——百万成员的 ZSet 即使每条很小也是大 key。
① 慢:读写单 key 耗时长,阻塞主线程(单线程模型,thread-model deck);② 阻塞:DEL 一个百万元素集合是 O(N) 同步释放;③ 网络:一次取整 key 打满带宽;④ 复制倾斜:主从同步/迁移时单 key 巨包;⑤ 内存倾斜(Cluster 单槽热点)。
| 环节 | 工具 / 做法 | 要点 |
|---|---|---|
| 线上发现 | redis-cli --bigkeys(SCAN 采样,返回各类型最大 key)· --memkeys(按内存)· -i 0.1 每 100 次 SCAN 休眠 0.1s 限速 | 采样统计非精确;MEMORY USAGE key 精查单个 |
| 离线分析 | 对 RDB 文件离线全量分析(rdb-tools / redis-rdb-cli / 云厂商离线 key 分析) | 不影响线上;可输出 top N 与分布报表 |
| 删除治理 | 用 UNLINK 替代 DEL(4.0+):先从键空间摘除,内存释放在后台线程执行,命令本身不阻塞 | UNLINK 官方原文:"performs the actual memory reclaiming in a different thread";配套 lazyfree-lazy-* 配置 |
| 结构治理 | 拆分(Hash 分桶 hash:{id%100})、压缩(value 序列化压缩/只存 ID 查详情)、ZSet 限制长度+定期 ZREMRANGEBYRANK、大 String 转独立小 key 或压缩 | 目标:单 key 元素数千以内、value KB 级 |
Hot Keys
单个 key(或单个槽)承载不成比例的 QPS:Redis 单线程处理命令,热 key 让单节点 CPU 打满,其余节点闲置——Cluster 里热点槽成为整体瓶颈。参考阈值:阿里云 DAS 以 QPS > 5000 记为热 key(可自定义)。典型场景:秒杀商品、爆款直播、明星微博。
① redis-cli --hotkeys(依赖 LFU 淘汰策略 maxmemory-policy 为 lfu 系);② MONITOR 短时观察(有开销,慎用);③ 客户端埋点统计;④ 云厂商热 key 实时统计(DAS/控制台 Top Key)。业务大促前应做热 key 预演。
| 方案 | 做法 | 要点与代价 |
|---|---|---|
| 本地缓存(L1) | 应用进程内缓存热 key(Go: ristretto/bigcache),Redis 退为 L2;本地 TTL 设秒级容忍旧值 | 最有效——热 key 流量根本不出口;代价是各实例一致性窗口与缓存击穿需在本地重做(单飞/逻辑过期) |
| 读写分离/副本分摊 | 读请求分摊到多个副本(主从 + 读写分离,Cluster 用 READONLY 读副本) | 扩展读能力;写热点(如计数)不适用 |
| key 打散(分片) | 写时复制 N 份 key:1..N(N = 预估 QPS/单节点承受力),读随机命中一份 | 把单点 QPS 摊到 N 个 key/节点;写放大 N 倍,一致性维护变复杂 |
| 业务削峰 | 计数类改本地累加 + 定期回写;秒杀类前置队列/令牌桶 | 从业务形态上消灭"必须高频读同一 key" |
Cheat Sheet
| 现象 | 定性与首选动作 |
|---|---|
| DB QPS 恒定偏高,查的 ID 大多查不到数据 | 穿透 → 参数校验 + 布隆过滤器 + 空值缓存(短 TTL) |
| DB QPS 瞬时尖刺,集中在同一个 key | 击穿 → 互斥锁单飞重建,或逻辑过期异步重建 |
| DB QPS 整体飙升,缓存命中率断崖 | 雪崩 → 查 TTL 是否同批设置 / Redis 是否宕机;限流降级先保 DB |
| 读到的值和库里不一样,过一会儿又对了 | 双写不一致 → 检查是否"先删缓存再更库"、删缓存是否失败 |
| 单节点 CPU 打满、其余节点空闲 | 热 key → --hotkeys 定位,本地缓存 / 打散 |
| 偶发毫秒级卡顿、主从同步变慢 | 大 key → --bigkeys 定位,UNLINK 删、拆分治理 |
| 穿透 | 主:布隆过滤器(判"不存在"直接拒);备:空值缓存 + 短 TTL;必做:参数校验 |
| 击穿 | 主:互斥锁重建(保 DB、牺牲等待);备:逻辑过期(保延迟、接受秒级旧值) |
| 雪崩 | 主:TTL 随机抖动 base + rand();备:高可用 + 多级缓存;兜底:限流熔断降级 |
| 先更库 + 删缓存 | 默认解。窗口 ≈ 一次 DEL 耗时(毫秒级),删成功即收敛 |
| 先删缓存 + 再更库 | 反例。旧值被回填并驻留到 TTL(分钟级),业务可见脏读 |
| 为什么删不更 | 并发写会交叉覆盖;写多读少白写;缓存常是聚合结果没法定点改 |
| 删失败怎么办 | MQ 重试 → Canal 订阅 binlog 异步删 → TTL 兜底封上界 |
| 能不能强一致 | 不能。跨异构系统要分布式事务,代价不成比例 → 只做最终一致 |
| 大 key 判定 | String value > 10KB;集合元素 > 5000(阿里云 Tair 口径) |
| 热 key 判定 | 单 key QPS > 5000(阿里云 DAS 默认口径,可自定义) |
| 删大 key | 用 UNLINK(后台线程释放内存)而不是 DEL(同步 O(N) 阻塞) |
| 危害机制 | 大 key = 单次操作重(阻塞主线程);热 key = 访问密(单节点 CPU 满) |
--bigkeys(带 -i 0.1 限速),确认没有巨型 key。
Interview QA · 1/2
先盖住答案自己答一遍,再展开对照——想不起来比看得顺眼记得牢;答不出的直接翻回上一页速查表。
穿透:查不存在的数据,恒定流量打库;击穿:单个热点 key 过期,瞬时脉冲打库;雪崩:大量 key 同时失效或缓存宕机,全局流量打库。一个是"数据缺席"、一个是"时间差"、一个是"规模失效"。
插入时 k 个哈希置位;真实存在的 key 其 k 位必然全为 1(都是自己置的)→ 绝不漏判。但别的 key 可能恰好把这些位全占了 → 假阳性"可能存在"。结论:BF 说"不存在"可放心拦截,说"存在"还得走正常链路。
不能直接删:一个位可能被多个 key 共享,清零会误伤。解法:Counting Bloom Filter(每位用计数器,删除减一);Cuckoo 滤波(RedisBloom CF.*,原生支持删除);或定期全量重建(离线重放合法 key 集)。
miss 后 SET lock:key uuid NX PX 10000 抢锁,抢到者查库回填再释放(释放校验 uuid + Lua);未抢到者 sleep 后重试读缓存。坑:锁必须带 TTL(持锁节点崩溃导致死锁)、等待超时要有上限、重试读不到要降级。
Redis 层不设 TTL,value 内嵌过期时间戳:逻辑过期后仍能命中缓存(值还在),先返回旧值,异步线程抢锁重建。击穿的根源是"miss 瞬间",逻辑过期让 miss 永不发生——代价是秒级旧数据。
过期时间 = 基础时长 + rand(0, 抖动窗口)(如 30min + rand(0,10min)),同一批导入的 key 失效点被摊开。配合预热脚本分批错峰、多级缓存把热点前置。抖动窗口过小无效,过大伤命中率——按业务过期模式调。
全量流量压向 DB → DB 响应变慢 → 应用连接池/线程池堆积 → 超时重试更多 → 雪球滚大。防线:DB 前限流(宁可拒绝部分请求)、熔断降级返回默认值、缓存侧做高可用(哨兵/Cluster)缩短不可用窗口。
强一致要求的数据(余额扣减等直接走 DB 事务)、命中率极低的冷数据(浪费内存还污染缓存)、超大 value(大 key 危害);频繁全量变更但从不读热的数据也不适合。缓存适合"读多写少 + 可容忍短暂旧值"的数据。
Interview QA · 2/2
同样先自答。这一组每题都要"结论 + 一句代价或边界"才算完整——只给结论一定会被追问。
先删后更:读写并发时读线程 miss 读到旧库值回填,旧值驻留到 TTL(分钟级、业务可见)。先更后删:窗口只有"删除前读命中旧缓存"的毫秒级,删除成功即收敛。后者不一致窗口小两个数量级。
三层:同步重试(有限次);把删除动作投 MQ,消费失败重试直至成功(不能阻塞主流程);Canal 订阅 binlog 异步删除,彻底与业务解耦。最坏情况 TTL 兜底——不一致有上界。
用于"先删缓存再更新库"或担心回填的业务:删 → 更新库 → 延迟 N → 再删。N 要覆盖"并发读从 miss 到回填完成"的耗时(几百毫秒~1s 经验值),延迟删除最好异步执行;N 估不准是固有缺陷。
缓存与 DB 是异构独立系统,跨系统原子提交要分布式事务(2PC/Seata),延迟与复杂度不可接受。工程答案是最终一致:删缓存压窗口、异步重试保成功、TTL 封上界。
阿里云口径:String >10KB、集合元素 >5000。DEL 同步 O(N) 释放,百万元素集合能阻塞主线程数百 ms;UNLINK(4.0+)先摘除键、内存释放交后台线程,命令本身 O(1) 返回。
游标 SCAN 遍历键空间,按类型用 TYPE/STRLEN/LLEN/HLEN 取大小,输出各类型最大 key。注意:采样统计、执行有 CPU 占用(-i 0.1 限速);只报"最大"不报"总量",精确内存查 MEMORY USAGE 或离线分析 RDB。
读热点:本地缓存(L1)最有效,其次副本分摊读。写热点(计数/秒杀库存):副本都有全量数据,写仍集中主库——只能 key 打散(复制 N 份随机写再聚合)、本地累加定期回写、或业务削峰。
大而热兼有最危险:先拆小(分桶/压缩/UNLINK),再打散与本地缓存。工具成对记:--bigkeys 对 --hotkeys。大 key 害在单次操作阻塞、热 key 害在单节点 CPU,方案不能混用。
Related & References
主从 / 哨兵 / Cluster → 雪崩的高可用防线、热 key 副本分摊
过期删除与内存淘汰 → TTL 语义是全部方案的底层约束
Redis 分布式锁 → 击穿互斥锁的 SET NX 与看门狗
单线程模型 → 大 key / 热 key 危害的执行模型根源
布隆过滤器 → 穿透防御第一道闸:负判断零误差
LRU 缓存(手撕)→ 同为"缓存 + 惰性加载",但一致性责任在应用层
通用线索:穿透 / 击穿 = 缓存 miss 的并发放大;最终一致 + TTL 兜底是跨系统缓存的通用范式
参考来源(★ = 最值得原文精读的一篇)
| ★ 美团技术团队《缓存那些事》 | 双写一致性两个时序推演(先删后更 vs 先更后删)与"更新缓存 vs 删除缓存"的取舍——本 deck 核心两页的原文出处(tech.meituan.com/2017/03/17/cache-about.html) |
| redis.io/docs · caching 开发指南 + AWS《Database Caching Strategies using Redis》 | Cache Aside / lazy loading 语义与四种缓存模式定义 |
| redis.io/commands/unlink · /del | UNLINK 在后台线程回收内存;DEL 同步阻塞 |
| redis.io/docs · redis-cli(--bigkeys / --memkeys / --hotkeys / -i) | SCAN 采样统计各类型最大 key 与限速参数;--hotkeys 依赖 LFU 策略 |
| 阿里云 Tair · 大 key 与热 key 识别与处理 | String >10KB、集合 >5000 元素;DAS 以 QPS >5000 记为热 key |
| github.com/alibaba/canal | 伪装 MySQL slave 订阅 binlog 的异步缓存失效链路 |