Redis 入门 05:缓存读写与失效处理
实验基线:Redis 7.4.11,先完成环境准备。除标注为宿主机终端的代码外,Redis 命令在该课指定的 redis-cli 中执行;不复制输出结果作为命令。
学习目标#
手动模拟 Cache Aside 的命中、回源、写入和失效,明确缓存错误与业务不存在的区别。
原理:事实由数据库负责#
读取流程是“查缓存 → 命中则返回 → 未命中则查数据库 → 缓存结果 → 返回结果”。写入流程常用“更新数据库成功 → 删除旧缓存”。先删除缓存再更新数据库时,另一个读请求可能把旧数据重新写回,因此顺序非常重要。
这里的数据库用两个明确的 JSON 文本模拟,不需要安装额外软件。它帮助观察流程,不意味着 Redis 与数据库之间存在共同事务。删除失败、回源与写入竞争、数据库复制延迟需要额外策略,进阶课继续讨论。
实验:首次未命中与回源#
UNLINK learn:cache:product:42
GET learn:cache:product:42
预期 nil。现在假设数据库返回商品 42、价格 19900 分。不要把金额 199.00 元存成未经约束的浮点计算结果。
SET learn:cache:product:42 '{"id":42,"name":"Keyboard","priceCents":19900}' EX 60
GET learn:cache:product:42
TTL learn:cache:product:42
预期 OK、商品 JSON、剩余不大于 60 秒。再次 GET 模拟缓存命中,数据库读取次数不再增加。真实应用应设置连接与命令超时,记录命中率、回源量和错误率。
实验:数据库更新后失效#
假设数据库事务已经提交,把价格改为 17900 分。随后:
DEL learn:cache:product:42
GET learn:cache:product:42
SET learn:cache:product:42 '{"id":42,"name":"Keyboard","priceCents":17900}' EX 60
GET learn:cache:product:42
在干净实验环境中 DEL 返回 1,随后 GET 为 nil,重新回源后的 GET 返回新价格。若键已过期,DEL 返回 0 也表示目标键已经不存在,不能把它误当成系统错误。
原理:缓存空值与过期抖动#
对不存在的商品,可用明确的空值标记并设置较短 TTL,避免持续查数据库。但要区分“业务不存在”与“数据库查询失败”:故障时不能缓存一个不存在标记。
大量键统一 60 秒到期,会集中回源。应用可以在基础 TTL 上叠加少量随机秒数,例如 60~75;不在 Redis 中存储随机数公式字符串。
常见错误#
- 缓存读取报错时直接无限回源:数据库可能被压垮,要限流或降级。
- 写入缓存却没有 EX:旧值可能长期存在。
- 所有接口均缓存:权限敏感响应要把用户或租户标识纳入键设计,避免串数据。
- 认为 TTL 等于一致性保证:TTL 只给过期策略,不消除并发竞争。
练习与参考答案#
为不存在的商品 404 设计一个 10 秒空值缓存,然后创建商品时删除这个标记:
SET learn:cache:product:404 '{"found":false}' EX 10
GET learn:cache:product:404
DEL learn:cache:product:404
应用看到 found
清理#
UNLINK learn:cache:product:42 learn:cache:product:404
官方参考#
学习导航#
上一课:Redis 入门 04:List、Set 与 Sorted Set · 学习目录 · 下一课:Redis 入门 06:排行榜与计数器综合练习







