MST

星途 面试题库

面试题:缓存设计 - 高并发下的缓存策略优化

假设你的系统面临每秒上万次的高并发读写请求,且数据访问模式复杂。请详细说明你会如何设计缓存策略,包括缓存过期策略、缓存更新策略以及如何防止缓存雪崩、缓存穿透和缓存击穿等问题,以确保系统在高并发场景下的稳定性和高性能。
43.7万 热度难度
后端开发缓存设计

知识考点

AI 面试

面试题答案

一键面试

缓存策略设计

  1. 缓存过期策略
    • 定期过期:为每个缓存设置一个固定的过期时间,比如热门数据设置较短过期时间(如5 - 10分钟),非热门数据设置较长过期时间(如1 - 2小时)。这样可以确保缓存中的数据不会长期占用内存,同时在一定程度上保证数据的时效性。
    • 惰性过期:在每次访问缓存时,检查数据是否过期。如果过期则从数据源中重新获取并更新缓存。此方法能减少过期任务调度压力,但可能导致过期数据在一段时间内仍被访问。可结合定期过期一起使用,定期清理一部分过期数据。
  2. 缓存更新策略
    • 读写后更新:在数据发生变化(写入或修改)后,立即更新缓存中的数据。这种方法能保证缓存数据的一致性,但在高并发场景下,如果频繁写入,可能会导致缓存更新压力过大。为了缓解压力,可以使用批量更新的方式,即将多个更新操作合并为一次批量更新。
    • 失效模式:在数据发生变化时,不立即更新缓存,而是将缓存标记为失效。下次读取缓存时发现数据失效,再从数据源获取最新数据并更新缓存。此方法适合对数据一致性要求不是特别高的场景,可减少缓存更新的频率。
    • 异步更新:使用消息队列(如 Kafka 等),当数据发生变化时,将更新缓存的任务发送到消息队列中,由专门的消费者异步处理缓存更新操作。这样可以避免在高并发写入时直接更新缓存带来的性能问题。
  3. 防止缓存雪崩
    • 分散过期时间:避免大量缓存同时过期。对于需要设置相同过期时间的缓存,可以在基础过期时间上增加一个随机的时间偏移量,例如基础过期时间为1小时,随机偏移量为0 - 30分钟,这样可以将缓存过期时间分散开,降低同时过期的风险。
    • 二级缓存:设置主缓存和备用缓存。主缓存失效后,先从备用缓存获取数据,如果备用缓存也失效,再从数据源获取并同时更新主缓存和备用缓存。备用缓存可以设置较长的过期时间,以应对主缓存大量失效的情况。
    • 缓存降级:当发现缓存大面积失效,系统负载过高时,启动缓存降级策略。比如直接返回默认值或者从数据库中按照一定的限流策略读取数据,避免因大量请求直接穿透到数据库导致数据库崩溃。
  4. 防止缓存穿透
    • 布隆过滤器:在查询数据前,先通过布隆过滤器判断数据是否存在。布隆过滤器是一种概率型数据结构,它可以快速判断一个元素是否在集合中。如果布隆过滤器判断数据不存在,则直接返回,不再查询数据库,从而避免大量不存在的数据穿透到数据库。布隆过滤器有一定的误判率,但误判率可以通过调整参数(如哈希函数个数、位数组大小等)来控制。
    • 空值缓存:当查询的数据在数据库中不存在时,也将这个空值结果缓存起来,并设置较短的过期时间。这样下次查询同样不存在的数据时,直接从缓存中获取空值,避免穿透到数据库。
  5. 防止缓存击穿
    • 互斥锁:在查询缓存失效时,使用互斥锁(如 Redis 的 SETNX 命令实现分布式锁)来保证只有一个线程去查询数据库并更新缓存,其他线程等待。当获取锁的线程更新完缓存后,释放锁,其他线程再从缓存中获取数据。这种方法能有效防止缓存击穿,但可能会导致性能问题,因为其他线程需要等待,可结合合理的超时设置来避免死锁。
    • 热点数据永不过期:对于一些热点数据,不设置过期时间。同时使用异步线程定期更新这些数据,保证数据的时效性。在更新数据时,先更新缓存副本,再将副本替换为正式缓存,以避免更新过程中出现数据不一致的问题。