很多人以为“加了缓存,性能就一定好”,结果上线之后,系统依然慢,数据库 QPS 居高不下,Redis 明明命中率 80%,数据库却一点没减压。
为什么用了缓存,数据库还是这么忙?问题根本不在“有没有缓存”,而在“你怎么用的缓存”。
一、缓存用了,为什么数据库还慢?
1. 热点数据命中高,长尾请求依然打库
缓存往往只能命中频率高的数据,比如用户信息、商品详情。但很多业务请求带有动态查询条件,比如搜索、筛选、分页——这些基本都要打数据库。
数据库压力其实主要来源于这类“非缓存型请求”。
2. 缓存粒度不对,重复命中价值不高
有的缓存把整个页面缓存,有的把字段拆得太细,导致缓存本身存在但复用效率低。真正能“扛住压力”的缓存,是要有高命中率 + 高请求价值的。
3. 缓存更新策略设计不合理
写入数据后不刷新缓存,导致“写库-读缓存”数据不一致,最终只能频繁回源查库。
最常见的错法:只做读缓存,不做写更新或延迟更新
正确姿势:更新数据库的同时也更新/删除缓存
4. 缓存穿透、雪崩、击穿没有防护
这些是缓存的三大“杀手”:
穿透:大量查询无效数据,缓存没存,数据库压力全背
击穿:某热点缓存突然过期,成千上万请求同时打数据库
雪崩:大量缓存同时失效,系统直接崩溃
二、如何正确使用缓存降低数据库压力?
1. 加布隆过滤器,拦住无效请求
比如用户 ID、商品 ID 可以先用布隆过滤器判断是否合法,不合法的直接拦截,别让它打到数据库。
2. 加互斥锁,防止击穿
热点数据失效时,用互斥锁保护回源操作,只让第一个请求去查库并刷新缓存。
if redis.get(key) is None: if acquire_lock(key): data = query_db() redis.set(key, data)
3. 设置不同过期时间,避免雪崩
批量缓存时,随机设置 TTL,比如设置为 300s ~ 600s 之间,错开失效时间。
4. 使用异步缓存更新机制
对数据变动频繁、读写比低的业务,可以考虑定时批量刷新缓存,而不是每次操作都实时更新。
三、总结
缓存不是“加了就快”的灵丹妙药,真正的优化效果来自:
命中率高
更新策略合理
防击穿防雪崩机制完备
不是数据库撑不住,而是你根本没把缓存用明白。




