MST

星途 面试题库

面试题:缓存设计之专家难度:复杂业务场景下缓存与微服务架构的深度集成策略

在一个具有复杂业务逻辑和数据依赖关系的微服务系统中,例如涉及多阶段数据处理、分布式事务以及数据的实时更新与同步。请详细阐述你会如何设计缓存策略,确保缓存既能有效提升系统性能,又能保证数据的完整性和一致性,同时还要考虑缓存失效、穿透、雪崩等问题的应对方案。
11.7万 热度难度
后端开发缓存设计

知识考点

AI 面试

面试题答案

一键面试

缓存策略设计

  1. 读写策略
    • 读策略
      • 采用Cache - Aside模式,即应用程序先从缓存中读取数据。如果缓存命中,直接返回数据;如果缓存未命中,再从数据库中读取,然后将数据写入缓存,并返回给应用。这样可以最大程度利用缓存,减少数据库压力。
      • 对于读多写少的场景,可以考虑Write - Through策略的变种,即异步Write - Through。先更新缓存,然后异步更新数据库,这样可以减少写操作的响应时间,但需要处理异步更新失败的重试机制。
    • 写策略
      • 对于写操作,采用Write - Invalidate策略。当数据更新时,先更新数据库,然后使相关缓存失效。这样能保证数据库和缓存最终一致性。为了防止并发写操作导致缓存不一致,可以在缓存失效时使用分布式锁(如Redis的SETNX命令实现简单分布式锁),确保同一时间只有一个写操作能使缓存失效。
  2. 缓存数据结构选择
    • 根据业务数据的特点选择合适的缓存数据结构。例如,如果数据具有层级关系,可以使用Redis的Hash结构,将父级数据作为Hash的key,子级数据作为field - value对存储。如果是简单的键值对数据,直接使用普通的key - value结构即可。对于需要排序的数据,可以考虑使用Redis的Sorted Set结构。
  3. 缓存粒度控制
    • 细粒度缓存:将数据按照最小可复用单元进行缓存,例如对于一个复杂订单系统,可以将订单的每个子项分别缓存。这样在部分数据更新时,只需要使对应的子项缓存失效,而不是整个订单缓存失效,减少缓存更新带来的性能开销。
    • 粗粒度缓存:对于一些关联性强、更新频率低的数据,可以采用粗粒度缓存。例如,系统中的配置信息,将所有配置信息作为一个整体进行缓存,减少缓存管理的复杂度。

保证数据完整性和一致性

  1. 分布式事务与缓存一致性
    • 使用两阶段提交(2PC)或三阶段提交(3PC)协议时,在准备阶段,先使相关缓存进入“预失效”状态(例如在缓存中设置一个特殊标识),如果提交阶段成功,再正式使缓存失效;如果回滚,取消“预失效”标识。
    • 基于消息队列实现最终一致性。在分布式事务成功提交后,发送消息到消息队列,由消息队列消费者负责更新或失效相关缓存。通过消息的可靠投递和重试机制保证缓存操作的最终成功。
  2. 实时更新与同步和缓存一致性
    • 对于实时数据更新,采用发布 - 订阅模式。当数据更新时,发布者向消息队列发布更新消息,多个订阅者(包括缓存更新服务)接收到消息后进行相应的缓存更新操作。
    • 对于数据同步场景,例如主从数据库同步过程中,在主库更新成功后,通过消息通知从库以及缓存更新服务,确保缓存和从库数据的一致性。

缓存失效、穿透、雪崩问题应对方案

  1. 缓存失效
    • 设置合理的过期时间:根据数据的更新频率和重要性设置不同的过期时间。对于更新频繁的数据,设置较短的过期时间;对于相对稳定的数据,设置较长的过期时间。可以采用随机过期时间(例如在固定过期时间基础上,上下浮动一定比例),避免大量缓存同时过期。
    • 缓存过期后的处理:当缓存过期时,采用“兜底”策略,例如返回默认值或者从数据库读取旧数据(如果允许短暂的数据不一致),同时异步更新缓存,减少用户感知到的延迟。
  2. 缓存穿透
    • 布隆过滤器:在查询数据前,先通过布隆过滤器判断数据是否存在。如果布隆过滤器判断不存在,则直接返回,避免查询数据库。布隆过滤器存在一定的误判率,但可以通过合理设置参数(如哈希函数个数、位数组大小)来降低误判率。
    • 缓存空值:当查询数据库发现数据不存在时,将空值也缓存起来,并设置较短的过期时间,这样下次相同查询直接从缓存返回空值,而不会穿透到数据库。
  3. 缓存雪崩
    • 构建多级缓存:例如采用本地缓存(如Guava Cache)和分布式缓存(如Redis)结合的方式。当分布式缓存出现雪崩时,本地缓存可以作为兜底,继续提供部分数据服务,减少对数据库的冲击。
    • 限流与降级:对访问系统的流量进行限制,例如使用令牌桶算法或漏桶算法。当流量过大,接近系统承载能力时,进行降级处理,如返回默认数据、提示系统繁忙等,避免大量请求直接压垮数据库。
    • 服务熔断:设置缓存服务的熔断机制,当缓存服务出现大面积故障时,熔断缓存服务,直接访问数据库,并启动降级策略,防止故障扩散到整个系统。