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

官方参考#

客户端缓存模式介绍 · SET · DEL

学习导航#

上一课:Redis 入门 04:List、Set 与 Sorted Set · 学习目录 · 下一课:Redis 入门 06:排行榜与计数器综合练习

Redis 入门 05:缓存读写与失效处理
作者:LcooYa
CC BY-NC-SA 4.0
相关文章
随机文章