加了缓存接口还是慢,多半不是缓存没用,而是根本没命中:key 设计太细、TTL 太短,或者被一个大 key 拖住了。缓存怎么用才有效,先别急着换组件,按下面的顺序查一遍,多数问题在前两步就能定位。
缓存命中率先算清楚:低于90%别谈优化
排查从数字开始,不从代码开始。
- 连上 Redis 执行
redis-cli INFO stats,找到keyspace_hits和keyspace_misses。
- 命中率 = hits ÷(hits + misses)。低于 90% 说明大量请求还在打数据库。
- 算一下漏出去的请求量:商品详情接口 QPS 2000、命中率 60%,等于每秒 800 次查库,这时加机器只是把账单拉高。
- 打开
redis-cli --stat,一边压测一边看 hits/misses 每秒的变化,确认缓存到底有没有被读到。
三个常见误判
- 只在本地环境看日志:数据少,几乎全命中,上线就打回原形。
- 用
KEYS *数 key 总量当命中率,数量多不等于命中高,还会卡住实例。
- 缓存列表接口却每次都带不同的分页、排序参数,等于每个请求都是新 key。

key和TTL怎么设,直接决定缓存命中率
key 设计
- 一个 key 只对应一种查询条件,别把用户 token、时间戳、随机数拼进去。
- 参数顺序写死:
item:{id}:detail,不要一会儿item:detail:{id}。
- 单个 value 控制在 10KB 以内,超过就拆开,或者只缓存热点字段,别整行塞进去。
TTL 与更新顺序
- 热点数据设 5~30 分钟,配随机抖动(比如 300 秒 ±10%),避免同一秒集体过期。
- 冷数据不缓存,或者只给 60 秒,挡住瞬时并发就够了。
- 更新走 Cache Aside:先写数据库,再删缓存;删完隔 200~500 毫秒再删一次,覆盖并发读回填的旧值。
- 别用「更新数据库的同时更新缓存」,两个写操作一乱序,脏数据会一直留着。

缓存失效的三种坑,对应三种做法
- 穿透:查一个不存在的 ID,每次都穿到数据库。做法是空结果也缓存 60 秒,量大再加布隆过滤器。
- 击穿:单个热点 key 过期瞬间,几百个请求同时回源。做法是加互斥锁或单飞(singleflight),只放一个请求去查库。
- 雪崩:大批 key 同时过期,或者 Redis 挂了。做法是 TTL 加随机、进程内缓存兜一层、给数据库加限流。
验证有没有真修好,按这三步做:
- 压测前记录数据库 QPS,压测后再看一次,两个数字一对比就知道缓存挡了多少。
- 手动删掉一个热点 key,看接口耗时是否飙升,能复现说明回源逻辑正常,不能复现说明缓存根本没被读。
- 把 TTL 临时改成 5 秒,观察数据库 QPS 曲线是否同步抬升。
本地缓存和Redis怎么分工
- 单机、数据量小、能容忍几十秒不一致:用进程内缓存(如 Caffeine),省掉一次网络往返,单次读能从毫秒级降到微秒级。
- 多实例、要共享、跨服务读同一份数据:用 Redis。
- 两级组合:本地 30 秒 + Redis 10 分钟。更新时先删 Redis,再广播清本地,别反过来。
免费与付费边界:本地用 Docker 起一个 Redis 练手不花钱;线上托管版按内存规格计费,具体价格以官方页面为准。选规格前先估峰值内存 = key 数量 × 平均 value 大小 × 1.3,留三成冗余。
常见问题(FAQ)
缓存和数据库不一致怎么办?
先接受短暂不一致,多数业务能容忍几百毫秒。做法是先更新库再删缓存,配合延迟双删;要求强一致的场景别用缓存兜,直接读库更省心。
缓存一定要设过期时间吗?
要。没有 TTL 的 key 一旦写错就永久占内存,还会掩盖更新逻辑的 bug。至少给个兜底过期时间,比如 1 天。
命中率已经95%了还是慢怎么办?
看是不是大 key 或热 key 把单核打满:用 redis-cli --bigkeys 找大 key,看监控里 QPS 是否集中在一个分片。这种情况要拆分,不是继续加缓存。
小项目有必要上缓存吗?
用户量几千以内、单次查询在 10 毫秒内,先加索引比加缓存划算。缓存是并发上来之后的第二个手段,顺序反了只会多一层要维护的东西。
缓存怎么用才有效,说到底就三件事:命中率先达标、key 和 TTL 设计得当、失效场景有兜底。按上面的顺序查一遍,比盲目换组件快得多。
最后更新:2026-10-24(工具界面、价格与政策可能调整,请以官方页面为准)。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...