MST

星途 面试题库

面试题:缓存设计下复杂业务场景缓存命中率优化

假设你正在开发一个电商系统,其中商品详情页的数据变化频率较低,但商品库存实时变动。为了提高商品详情页缓存命中率,同时确保库存数据的实时性,你会如何设计缓存策略?详细阐述缓存架构、更新机制以及可能遇到的问题及解决方案。
41.1万 热度难度
后端开发缓存设计

知识考点

AI 面试

面试题答案

一键面试

缓存架构设计

  1. 分层缓存
    • 浏览器缓存:对于商品详情页的静态资源,如图片、CSS 和 JavaScript 文件等,利用浏览器的缓存机制,设置合适的缓存头(如 Cache - ControlExpires 等),减少对服务器的请求,提高用户访问速度。
    • CDN 缓存:将商品详情页中的静态内容(如商品图片、描述中的富媒体等)分发到 CDN 节点进行缓存。CDN 能够根据用户的地理位置,快速地将缓存内容返回给用户,减轻源站的压力。
    • 应用层缓存:在应用服务器内部设置缓存,例如使用 Redis 作为缓存存储。对于商品详情页数据,由于变化频率低,可以设置较长的缓存过期时间。而对于库存数据,单独进行处理,不与商品详情页数据混合缓存。
  2. 数据分类缓存
    • 商品详情缓存:以商品 ID 作为缓存键,将商品的基本信息(如名称、描述、规格等)以及相对稳定的图片 URL 等缓存起来。因为这些数据变化不频繁,可以设置较长的过期时间,如 1 天甚至更长,具体根据业务需求确定。
    • 库存缓存:同样以商品 ID 作为缓存键,但设置较短的过期时间,例如 1 - 5 分钟(根据业务对库存实时性的要求调整),确保库存数据相对实时。或者采用不设置过期时间,而是在库存发生变化时主动更新缓存的方式。

更新机制

  1. 商品详情更新
    • 手动更新:当商品信息发生修改时,如商品描述更新、规格调整等,通过管理后台操作,在更新数据库的同时,主动删除对应的商品详情缓存。下次用户请求该商品详情页时,缓存未命中,从数据库中读取最新数据并重新缓存。
    • 定时更新:可以设置一个定时任务,定期全量或增量更新商品详情缓存,确保即使在没有手动修改的情况下,缓存数据也能保持相对的新鲜度。例如每天凌晨对所有商品详情缓存进行更新。
  2. 库存更新
    • 实时更新:当库存发生变动(如商品下单、库存补充等)时,在更新数据库库存记录的同时,立即更新库存缓存。确保库存缓存数据与数据库保持一致。可以通过数据库的事务机制,保证库存更新和缓存更新操作的原子性。
    • 消息队列(MQ)辅助更新:对于高并发场景下的库存更新,可以引入消息队列。当库存变动时,先将库存更新消息发送到消息队列,由消息队列的消费者负责更新库存缓存和数据库。这样可以避免高并发情况下对数据库和缓存的直接频繁操作,提高系统的稳定性和性能。

可能遇到的问题及解决方案

  1. 缓存穿透
    • 问题:查询一个不存在的商品 ID,每次请求都绕过缓存直接查询数据库,给数据库带来压力。
    • 解决方案
      • 布隆过滤器:在缓存之前设置布隆过滤器,将所有存在的商品 ID 构建成布隆过滤器。当查询商品时,先通过布隆过滤器判断商品 ID 是否存在。如果不存在,直接返回,不再查询数据库,避免无效请求穿透到数据库。
      • 空值缓存:当查询一个不存在的商品 ID 时,在缓存中设置一个空值(如 null),并设置较短的过期时间。下次请求同样的商品 ID 时,直接从缓存中获取空值,减少对数据库的查询。
  2. 缓存雪崩
    • 问题:大量商品详情缓存同时过期,导致大量请求直接查询数据库,可能使数据库压力过大甚至崩溃。
    • 解决方案
      • 随机过期时间:在设置商品详情缓存过期时间时,不要设置固定的过期时间,而是在一个合理的时间区间内设置随机过期时间。例如设置过期时间在 1 - 2 天之间随机,避免大量缓存同时过期。
      • 缓存预热:系统启动时,提前加载部分热点商品的缓存数据,避免系统刚上线时由于缓存为空导致大量请求直接查询数据库。
  3. 缓存击穿
    • 问题:热点商品的缓存过期瞬间,大量请求同时查询该商品,直接穿透到数据库,可能使数据库压力过大。
    • 解决方案
      • 互斥锁:在缓存过期时,使用互斥锁(如 Redis 的 SETNX 命令实现)来保证只有一个请求能够查询数据库并更新缓存,其他请求等待。当更新完缓存后,释放互斥锁,其他请求可以从缓存中获取数据。
      • 永不过期:对于热点商品,可以设置缓存永不过期,同时在数据更新时主动更新缓存,确保数据的实时性。这样可以避免缓存过期瞬间的高并发问题。