MST

星途 面试题库

面试题:缓存设计:本地缓存与分布式缓存的一致性问题

在使用本地缓存和分布式缓存时,分别可能会遇到哪些数据一致性问题?请描述如何在高并发环境下解决这些问题。
12.7万 热度难度
后端开发缓存设计

知识考点

AI 面试

面试题答案

一键面试

本地缓存数据一致性问题及解决

  1. 问题
    • 缓存与数据库不一致:当数据在数据库中更新后,本地缓存中的数据可能未及时更新,导致应用读取到旧数据。在高并发场景下,多个线程同时读取和更新数据,这种不一致情况更容易出现。
  2. 解决方法
    • 读写锁:使用读写锁来控制对缓存和数据库的访问。读操作可以并发执行,但写操作需要获取独占锁。当数据更新时,先获取写锁,更新数据库后立即更新本地缓存,然后释放锁。这样可以保证在数据更新期间,其他线程不会读取到旧数据。例如在Java中可以使用ReentrantReadWriteLock
    • 失效策略:设置合理的缓存失效时间。当数据更新时,直接使缓存失效,下次读取时从数据库重新加载数据到缓存。在高并发场景下,虽然可能出现短时间内缓存未命中的情况,但能保证数据的最终一致性。比如在Spring Cache中,可以设置@Cacheable注解的cacheManager的失效时间属性。

分布式缓存数据一致性问题及解决

  1. 问题
    • 缓存穿透:大量请求查询不存在的数据,这些请求绕过缓存直接访问数据库,可能导致数据库压力过大甚至崩溃。在高并发环境下,这种情况会迅速耗尽数据库资源。
    • 缓存雪崩:缓存中大量数据同时过期,导致大量请求瞬间直接访问数据库,造成数据库负载过高甚至宕机。
    • 缓存击穿:热点数据的缓存过期瞬间,大量并发请求同时访问该数据,这些请求直接打到数据库,可能使数据库压力骤增。
  2. 解决方法
    • 缓存穿透解决
      • 布隆过滤器:在缓存之前添加布隆过滤器,将所有可能存在的数据哈希到一个足够大的位数组中。当请求过来时,先通过布隆过滤器判断数据是否存在,如果不存在则直接返回,不会访问数据库。例如在Guava库中就提供了布隆过滤器的实现。
      • 空值缓存:当查询数据库发现数据不存在时,也将空值缓存起来,并设置较短的过期时间,这样后续相同请求就不会再次访问数据库。
    • 缓存雪崩解决
      • 随机过期时间:为缓存数据设置随机的过期时间,避免大量数据同时过期。例如原本设置过期时间为1小时,可以在50分钟到70分钟之间随机取值。
      • 加锁排队:在缓存失效后,通过加分布式锁(如Redis的SETNX命令实现分布式锁),保证只有一个请求去数据库加载数据并更新缓存,其他请求等待,从而避免大量请求同时访问数据库。
    • 缓存击穿解决
      • 互斥锁:和缓存雪崩中加锁排队类似,在热点数据缓存过期时,使用分布式锁,只有一个线程能去数据库加载数据并更新缓存,其他线程等待。
      • 永不过期:对热点数据设置永不过期,在数据更新时同时更新缓存。可以通过后台线程定时去更新缓存数据,保证数据的实时性。