高并发项目中的缓存的常见问题及其解决方案
1.缓存穿透
- 现象:大量请求查询数据库中不存在的数据(如恶意攻击),缓存未命中导致直接穿透到数据库。
- 原因:非法请求利用系统漏洞频繁访问不存在的数据。
- 解决方案:
- 布隆过滤器(Bloom Filter):在缓存层前增加布隆过滤器,预先存储所有合法 Key 的哈希值,快速拦截非法请求。
- 缓存空值(Null Caching):对查询结果为空的 Key 缓存短期空值(如 5 分钟),避免重复穿透。
- 请求校验:对参数合法性进行严格校验(如 ID 格式),拦截无效请求。
关于布隆过滤器的解释
是一种高效的概率型数据结构,用于快速判断一个元素是否属于某个集合。它的核心特点是空间效率极高(节省内存),但存在一定的误判率(False Positive,即可能误判不存在的元素为存在,但不会漏判存在的元素)。
核心原理
- 位数组(Bit Array)
布隆过滤器底层是一个长度为m的二进制位数组(初始全为0)。- 多个哈希函数(Hash Functions)
使用k个不同的哈希函数,每个函数将元素映射到位数组的某个位置。- 添加元素
将元素依次通过k个哈希函数,得到k个位置,将这些位置的值设为1。- 查询元素
将元素依次通过同样的k个哈希函数,得到k个位置:
- 如果所有位置的值为1,则认为元素可能存在(可能存在误判)。
- 如果任一位置的值为0,则元素一定不存在(100%准确)。
2.缓存击穿
- 现象:热点 Key 突然过期,大量并发请求直接冲击数据库。
- 原因:高并发场景下热点数据失效导致瞬时数据库压力。
- 解决方案:
- 互斥锁(Mutex Lock):使用分布式锁(如 Redis 的
SETNX)控制单线程重建缓存,其他线程等待后重试。 - 逻辑过期:缓存不设置物理过期时间,数据中存储逻辑过期时间,异步更新缓存。
- 永不过期策略:对极热点数据不设置过期时间,通过定时任务或消息队列异步更新。
- 互斥锁(Mutex Lock):使用分布式锁(如 Redis 的
2.1. 缓存击穿的核心原因
缓存击穿是指 某个热点 Key 在缓存中过期时,大量并发请求瞬间穿透缓存,直接访问数据库的现象。其本质原因是:
- 热点 Key 同时失效:例如某个高频访问的 Key 设置了相同的过期时间,导致大量请求在缓存失效的瞬间涌入数据库。
- 缺乏并发控制:没有在缓存失效时对数据库访问进行限流或互斥锁保护。
- 缓存未预热:缓存失效后,未及时重建新缓存,导致后续请求继续穿透。
2.2 Redis 的存储结构与 Key 过期
-
Redis 的存储形式:
Redis 支持多种数据结构(如 String、Hash、List 等),但无论使用何种结构,Key 的过期机制是独立于数据结构的。当 Key 过期时,Redis 会自动删除它(无论其底层是 HashMap 还是其他结构)。 -
Key 过期的触发方式:
Redis 采用 惰性删除 + 定期删除 策略:- 惰性删除:当客户端尝试访问某个 Key 时,Redis 会检查其是否过期,若过期则删除。
- 定期删除:Redis 周期性随机检查一批 Key,删除其中已过期的。
因此,Key 过期本身并不会直接导致缓存击穿,真正的问题在于:
大量并发请求在 Key 过期后同时触发缓存重建,且未有效控制对数据库的访问。
3.缓存雪崩
- 现象:大量缓存 Key 同时失效或缓存集群宕机,导致数据库压力暴增。
- 原因:缓存集中过期或缓存服务不可用。
- 解决方案:
- 随机过期时间:为 Key 的过期时间添加随机值(如基础 1 小时 + 随机 0-10 分钟),分散失效时间。
- 多级缓存架构:采用本地缓存(Caffeine) + 分布式缓存(Redis)的多级结构,降低单点风险。
- 高可用设计:使用 Redis Cluster 或 Sentinel 实现集群高可用,避免单节点故障。
4. 缓存与数据库一致性
-
现象:缓存数据与数据库数据不一致,导致业务逻辑错误。
-
原因:异步更新延迟或并发写操作引发数据冲突。
-
解决方案:
双写策略:更新数据库后同步更新缓存(需处理失败重试)。
延迟双删:先删缓存 → 更新数据库 → 延迟再次删缓存(应对并发读脏数据)。
订阅数据库日志:通过 Canal 监听 MySQL Binlog,异步更新缓存,保证最终一致性。
5. 热点数据倾斜(Hotspot Skew)
- 现象:某些 Key 访问量极高(如明星微博),导致单节点负载过大。
- 解决方案:
- 本地缓存:在应用层使用本地缓存(如 Guava Cache)分流热点请求。
- Key 分片:对热点 Key 添加随机后缀(如
key_1,key_2),分散到多个节点。 - 限流降级:对热点接口实施限流(如 Sentinel),防止系统过载。
浙公网安备 33010602011771号