公司动态
缓存穿透、击穿和雪崩:别把三种问题混成一件事
缓存穿透、击穿和雪崩别把三种问题混成一件事缓存能够减少数据库读取也能让高频页面更快返回。但缓存不是简单加在数据库前面就结束了。请求查不到数据、热点刚好失效、大量键同时过期、缓存服务本身异常都会让流量重新落到后端。若团队把这些情况统称为“缓存崩了”往往会套错方案给不存在的数据加锁给热点一味延长过期时间或者只靠增加 Redis 容量来解决批量失效。更稳妥的做法是先区分现象再根据数据是否存在、热点程度、过期分布和后端承受能力设计防护。缓存策略应服务于业务正确性和可用性不能为了提高命中率而返回不该返回的数据或把过期数据无限期留在系统里。穿透先判断请求是否有意义缓存穿透通常指请求查询的对象在缓存和数据源中都不存在。可能是用户输入错误、爬虫探测、接口被滥用也可能是数据刚删除后仍有旧链接被访问。每次都直接查数据库即使单次查询很轻也会在高并发下形成持续压力。处理前应确认“不存在”在业务上是什么意思。有些资源确实永远不可能存在可以较早拒绝有些对象则可能刚创建、尚未同步过早判断不存在会影响正常用户。输入参数校验、权限校验和业务状态检查应放在合适位置不能把所有未知标识一律当作攻击。对可确认的无效请求可以使用短期的空结果缓存减少重复访问下沉。过期时间需要根据数据创建和删除的时效设计不能无限保存。布隆过滤器等概率结构也可以用于较大规模的已知集合它能可靠地排除某些不在集合中的键但“可能存在”并不代表数据库一定有记录后续仍要正常查询和处理。击穿关注的是单个热点重建缓存击穿与穿透不同它针对的是本来存在且访问量很高的对象。当一个热点键过期或失效时很多请求同时发现未命中并发回源加载同一份数据。后端压力集中在一个对象的重建上常在活动页、热门内容或高频配置读取时出现。第一步是识别真正热点而不是给所有键加复杂锁。可以通过访问量、重建成本和业务重要性判断哪些对象需要特殊处理。普通键偶尔并发回源可能并不值得引入额外协调高热点且重建昂贵的键才需要明确谁负责刷新、其他请求如何等待或降级。一种策略是在缓存失效后只允许有限请求触发重建其他请求短暂等待、返回受控的旧值或给出可理解的稍后重试。锁或单飞机制只能协调重建过程仍需要设置超时、失败处理和持有者身份避免重建任务本身卡住时把所有请求长期阻塞。逻辑过期是另一种思路物理缓存保留数据业务根据记录的更新时间决定它是否需要刷新。一个后台任务更新数据其余请求在有限窗口内可以读取旧值。这适合能够接受短暂陈旧结果的场景例如内容展示或非实时配置对余额、库存和强实时状态则不应为了平滑而返回过期结果。雪崩看的是一批缓存同时失去作用缓存雪崩涉及的不是单个热点而是一大批键在相近时间失效或缓存服务整体不可用。批量初始化时统一设置过期时间、定时任务集中刷新、发布时误删大范围键都可能造成前者单点部署、网络故障和容量耗尽则可能触发后者。过期时间适度分散能够降低同时回源的概率但它只是风险缓解不是绝对保证。随机范围要结合业务过期要求设计不能让需要准时更新的内容被随意拖延。更重要的是避免把大量关键键绑定到同一个刷新时刻并对批量操作设置范围检查和回滚路径。缓存服务故障时后端需要有明确的保护策略。数据库连接池、并发预算、限流和降级可以防止所有请求一起冲向数据源有些非关键功能可以暂时关闭或使用有限的本地结果。策略应区分接口优先级不能让一项低价值查询挤占核心交易所需资源。多副本、合理的客户端超时和故障切换有助于提高缓存服务可用性但也要测试切换期间的行为。客户端无限重试或同步等待可能在服务恢复前先把应用线程耗尽。缓存数据的正确性要有边界缓存中保存什么、何时更新、删除后怎样失效都必须与数据写入路径协调。仅在读取端添加缓存不处理写入后的更新或失效会让用户长期看到旧数据。写后删除、更新缓存、事件驱动刷新等方式各有适用条件需要结合并发写入和失败恢复设计。不要把缓存当作权限判断的最终来源。个性化数据、账户状态和敏感信息需要按用户与权限隔离缓存键或内容范围不清楚时可能把一个用户的结果返回给另一个用户。命中率再高也无法弥补这种错误。观测指标也应关注正确性命中与未命中、回源时间、重建失败、空结果比例、过期数据读取和缓存服务错误都能帮助判断策略是否在按预期工作。只有 QPS 和内存使用量不足以说明缓存真的保护了后端。用真实失败场景验证策略上线前可以在受控环境模拟几种关键情况持续请求不存在对象、热点键同时过期、刷新任务失败、大批键需要重新加载、缓存节点短暂不可用。观察数据库是否仍在可承受范围内用户是否得到适当反馈数据是否会错误地长期陈旧。发生异常后团队应知道先保护什么、谁有权关闭某项缓存策略、如何恢复和核对数据。运行手册不必写得很长但应避免现场临时执行大范围删除或无界重试。缓存穿透、击穿和雪崩的共同点是都会增加回源压力原因和处理方式却不同。先识别对象是否存在、是否是热点、是否会批量失效再选择短期空值、受控重建、过期分散和后端保护缓存才能在压力到来时真正发挥作用。