做后端开发这些年,缓存是我踩坑最多的领域之一。没有缓存,系统被数据库拖死;有了缓存,各种诡异的问题又接踵而至——数据不一致、缓存击穿、热 key 打死全站……这篇文章整理了我在生产环境中亲身踩过的 10 个坑,以及对应的解法。

坑一:缓存穿透——请求绕了一圈还是打爆了数据库
想象一下:有人用一个不存在的用户 ID 频繁请求接口,每次都查不到缓存,然后直接打到 MySQL。这种”穿透了缓存”的请求,叫缓存穿透。
我曾经遇到过一次,接口被恶意爬虫高频访问,全是无效查询,CPU 直接飙到 100%。
解法:对查询结果为空的情况,也缓存一个短 TTL 的空值(比如 null,TTL 设为 60 秒)。或者使用 布隆过滤器(Bloom Filter),在缓存层直接拦截不存在的 key。

坑二:缓存击穿——一个热 key 搞垮了整个服务
某个”爆款”商品的数据被千万人同时访问,但恰好这个 key 到期了——所有请求同时涌入数据库。这就是缓存击穿。
解法:使用 互斥锁 或 逻辑过期。互斥锁方案用 Redis 的 SETNX 实现只有一个请求去查库;逻辑过期方案则是给数据加一个”逻辑过期时间”,缓存过期后用后台线程异步重建缓存,用户无感知。
坑三:缓存雪崩——批量过期引发的血案
一批 key 设置了相同的过期时间,结果在同一秒全部失效——所有请求瞬间倾泻到数据库。缓存雪崩比击穿更恐怖,因为它是一大批 key 同时出问题。
解法:过期时间加随机偏移量,不要让大量 key 集中在同一时刻过期:
expireTime = baseTime + random(0, 1800)

坑四:热 key 问题——一个 key 吃掉 50% 的 QPS
某个明星发了一条微博,所有粉丝同时访问他的个人主页——这个用户 ID 就是个热 key。Redis 单节点处理热 key 有瓶颈,单线程的 Redis 会卡死。
解法:对热 key 加后缀分散到不同节点(key 打散),或者用本地缓存(Caffeine/Guava Cache)作为 Redis 前的缓冲层。
坑五:Key 设计混乱——维护者自己都看不懂
项目中见过这样的 key 设计:user:20231011、token_abc123、ProductDetail-9527——命名风格完全不统一。
推荐格式:业务:实体:id:属性,例如:crm:order:10086:detail、hr:employee:888:salary。统一规范,后期维护成本降低 80%。
坑六:把 Redis 当数据库用——丢了数据才后悔
有些团队把 Redis 作为主要存储,MySQL 成了备份。一旦 Redis 故障或数据丢失,业务直接崩溃。
原则:Redis 永远只是缓存,数据源必须是持久化存储(MySQL/PostgreSQL)。重要数据写入时遵循 Cache Aside 模式:读时先缓存再DB,写时先DB再删缓存。

坑七:没有监控——出了故障完全不知道
缓存慢查询、内存持续增长、连接数耗尽……这些问题如果没有监控,根本无法提前感知。
必做监控项:
- 内存使用率(used_memory / maxmemory)
- 缓存命中率(keyspace_hits / (keyspace_hits + keyspace_misses))
- 慢查询日志(slowlog get 10)
- 连接数(connected_clients)
推荐使用 Prometheus + Grafana 配合 Redis Exporter,搭一个基础监控面板,也就半小时的事。
坑八:Big Key——一次查询拖垮整个 Redis
用 Redis 的 --bigkeys 跑一下,可能会发现有些 value 达到了几十 MB。Big Key 在序列化/反序列化和网络传输时,都会造成严重延迟甚至 Redis 阻塞。
解法:拆分大 key,或者用 List/Hash 替代大 String,按需分页读取。
坑九:忽略 TTL——数据越来越”肥”
缓存没有过期时间,数据只进不出,最终 Redis 内存爆满。
解法:所有 key 必须带 TTL,建议按数据变更频率设置不同过期时间:配置类数据 1 小时,用户 Session 30 分钟,临时数据 5 分钟。
坑十:没有做缓存预热——上线即故障
大促前,系统刚重启,所有缓存都是空的,第一波流量直接打在数据库上,数据库表示:我太难了。
解法:系统启动时用脚本把热数据批量写入 Redis,或者系统启动后用少量请求逐步预热缓存,而不是等流量来了才想起来。
总结
缓存是性能优化的利器,但它也是一把双刃剑。用好缓存的关键,不在于你会用几个命令,而在于你能否预见到可能出现的问题,并在系统设计阶段就做好防范。
记住这三条黄金原则:
- 数据最终以持久化存储为准
- 所有 key 必须有 TTL
- 没有监控的缓存系统是裸奔
踩坑不可避免,但愿你踩过的坑,都能变成团队的经验值。
—— 来自一个被 Redis 坑过很多次的全栈开发者