
缓存是后端性能优化的第一利器用好了QPS翻十倍用不好系统雪崩、数据错乱、脏读横行。我梳理了8个最容易踩的坑每一个都曾让线上系统半夜报警。一、缓存穿透查一个不存在的数据用户恶意请求一个不存在的ID缓存不命中请求直接打到数据库。数据库也没有于是每次都要查库再返回空。高并发下数据库被打穿。解决方案有两种缓存空值并设置较短过期时间或者用布隆过滤器提前拦截。布隆过滤器的代价是有误判率但能过滤掉绝大多数无效请求。选择哪种取决于业务对一致性的容忍度。二、缓存击穿热点key突然过期某个爆款商品的缓存刚好过期瞬间大量请求同时打到数据库。和穿透的区别是击穿针对的是本来就存在的热点数据。解决方案是加互斥锁只让一个线程去加载数据其他线程等待。或者干脆不设过期时间用后台任务定时更新。逻辑过期是另一种思路缓存永不过期但值里带逻辑过期时间发现过期后异步刷新返回旧值兜底。三、缓存雪崩大量key同时失效凌晨批量预热缓存统一设置过期时间为24小时结果第二天凌晨全部同时失效。请求像雪崩一样涌向数据库。解决方案很简单过期时间加随机值。比如基础时间加0到300秒的随机偏移让key均匀分散失效。如果是集群宕机导致的雪崩还需要熔断降级和限流兜底。四、数据一致性缓存和数据库谁先更新这是最容易被低估的坑。先更新数据库再删缓存还是先删缓存再更新数据库两种都有问题。先删缓存再更新数据库在并发场景下可能导致旧数据被重新加载进缓存。先更新数据库再删缓存理论上更安全但删除失败就前功尽弃。主流方案是延迟双删更新数据库后删一次缓存延迟几百毫秒再删一次覆盖并发读导致的脏数据。但延迟双删也不是银弹极端情况下仍有一致性窗口。五、大key和热key一个Redis的String类型key存了10MB的JSON每次读取都阻塞其他请求。或者某个key的QPS是其他key的几百倍单个节点被打满。大key要拆分按字段拆、按时间拆、按业务维度拆。热key要做本地缓存在应用层扛住大部分请求或者用Redis Cluster的哈希标签把热key分散到不同节点。监控大key和热key需要工具支持Redis自带的--bigkeys只能离线扫线上要用redis-cli --hotkeys或自研采样方案。六、缓存与数据库双写不一致更新数据库成功但更新缓存失败。或者更新缓存成功但数据库回滚了。根本原因是缓存和数据库没有分布式事务。解决方案是最终一致性把缓存更新操作放进消息队列失败自动重试同时记录操作日志便于对账。如果业务能接受短暂不一致用过期时间兜底是最简单的方式。七、缓存预热与冷启动系统刚上线或重启缓存是空的所有请求都打到数据库。如果数据库扛不住直接雪崩。预热方案分两种全量预热启动时批量加载热点数据到缓存增量预热通过消息队列消费历史操作逐步构建缓存。预热脚本要控制速率避免把数据库打挂。八、序列化与反序列化性能用Java原生序列化存对象体积大、速度慢。换JSON好一些但字段多的时候仍有开销。Protobuf或Kryo是更好的选择体积小、速度快但需要定义schema。选型要看业务对可读性和兼容性的要求。跨语言场景用JSON或Protobuf纯Java内部服务用Kryo或FST。写在最后缓存架构没有银弹每个方案都是在一致性、可用性、性能之间做权衡。穿透、击穿、雪崩是可用性问题一致性是正确性问题大key热key是容量问题。搞清每个坑的本质才能设计出真正扛得住的后端缓存架构。下次加缓存之前先问问自己这8个坑我避开了几个