19年11月第4题

原方案采用“写缓存再写数据库”或“写数据库再写缓存”,看似能保证缓存与数据库的数据一致,但实际上存在双写不一致问题。#card

  • 例如,先写缓存后写数据库时,如果缓存写成功而数据库写失败,会导致数据不一致;反之,若先写数据库再写缓存,缓存更新失败时也会造成矛盾。

  • 此外,当多个请求同时发生时,可能出现读写冲突,即一个请求刚写数据库但缓存未更新,另一个请求却从缓存读到旧数据,造成脏读。这些问题说明,双写方案并不能彻底解决一致性。

[[缓存淘汰机制]](Cache-Aside Pattern) #Card

  • 读操作:优先从缓存读,若未命中,则从数据库读并更新缓存;

  • 写操作:先写数据库,再删除或使缓存失效。

  • 这种方式的优势在于避免了缓存与数据库的双写,只需保证数据库正确写入即可。缓存失效后,下一次读请求会触发数据库读取并刷新缓存,从而实现最终一致性。

  • 由于删除缓存的操作是轻量级内存操作,失败概率极低;即便出现偶发不一致,也会在下一次读取时自动修复。

  • 因此,该方案在保证高性能的同时,极大地降低了缓存与数据库不一致的风险,成为业界常见的实践。

问题一

  • a 去查数据库

  • b 将key value 写到缓存中

  • c 数据库

  • d 将 key value 写到缓存中

缓存key设置空值

  • 存在问题 #card

    • 不在系统中的key值是无限的,如果均设置key值为空,会造成内存资源的极大浪费,引起性能急剧下降。
  • 解决思路 #card

    • 查询缓存之前,对key值进行过滤,只允许系统中存在的key进行后续操作(例如采用布隆过滤器进行过滤)。

    • 常见方法是布隆过滤器:它基于位数组和多哈希函数,能够高效判断某个 key 是否可能存在于系统中,如果布隆过滤器判断 key 不存在,则无需访问数据库和缓存,从源头阻断恶意请求。

    • 此外,还可采用字典表或位图记录已存在 key 的范围和规则。

    • 这样,系统只对合理 key 发起查询,从而避免无效 key 导致缓存膨胀,保证整体稳定性和性能。

当大量缓存 key 设置了相同过期时间,或者缓存系统重启导致 key 大量失效,会出现 “缓存雪崩” 现象:瞬间有海量请求绕过缓存直击数据库,导致数据库 QPS 暴增,甚至直接宕机。
本题中的场景就是典型的缓存雪崩问题。其原因在于 :-> 缓存失效集中触发数据库访问,加上并发请求数大,数据库无法承受瞬时流量。
当大量缓存 key 设置了相同过期时间,或者缓存系统重启导致 key 大量失效,会出现 “缓存雪崩” 现象:瞬间有海量请求绕过缓存直击数据库,导致数据库 QPS 暴增,甚至直接宕机。
[[缓存雪崩]] 如何解决缓存失效带来的性能问题

  • 串行化更新,通过加锁或排队控制同一 key 的并发写请求,避免重复写数据库刷新缓存;

  • 过期时间随机化, :-> 为不同 key 设置不同或带随机偏移的 TTL,使缓存过期时间分布更均匀,减少同一时刻的大规模失效;

  • 多级缓存 :-> 在应用节点本地维护 L1 缓存,分布式缓存作为 L2,双层缓存共同抵御突发流量,即使部分失效,也能通过局部缓存抵消部分请求压力。
    结合实际业务特点,往往需要综合使用

  • 例如在 热点数据 上启用多级缓存与锁机制,在 长尾数据 上采用过期时间分散策略,从而整体上避免缓存雪崩,保障系统性能与可用性。

作者

Ryen Xiang

发布于

2026-01-31

更新于

2025-10-18

许可协议


网络回响

评论