缓存穿透和缓存击穿都是与缓存相关的问题,但它们发生的原因和解决方法略有不同。
-
缓存穿透(Cache Penetration):
-
缓存穿透指的是在缓存中查找一个不存在的数据,导致每次请求都直接查询数据库或其他数据源,绕过了缓存层。
-
典型的缓存穿透场景是请求的数据在数据源中不存在,而恶意请求或频繁的非法查询会导致大量的无效请求击穿到后端存储系统上,对系统造成压力。
-
解决方法:
- 布隆过滤器(Bloom Filter):在查询缓存之前,先使用布隆过滤器判断请求的数据是否存在于数据源中,不存在则直接返回,避免了无效的查询操作。
- 缓存空对象(Cache Null Object):如果查询的数据在数据源中确实不存在,可以将结果设置为空对象或空值,并将其缓存起来,这样下次相同的查询就可以直接返回空结果,避免对数据源的无效查询。
-
-
缓存击穿(Cache Breakdown):
-
缓存击穿指的是一个非常热门的数据在缓存中过期或被删除,同时有大量并发请求同时查询这个数据,导致所有请求都绕过了缓存,直接查询数据源,给数据源带来巨大压力。
-
典型的缓存击穿场景是某个热门商品或热门数据的缓存过期,此时大量并发请求同时查询该数据,导致数据库或其他数据源负载激增。
-
解决方法:
- 设置热门数据的永不过期:对于一些热门的数据,可以设置它们的缓存过期时间为永不过期,或者通过动态刷新缓存来保证数据的及时性。
- 加互斥锁(Mutex Lock):在查询缓存数据时,如果发现数据已经过期或不存在,可以使用互斥锁(Mutex Lock)来保证只有一个线程去查询数据源,其他线程等待查询结果。查询到数据后,更新缓存并释放锁,其他线程再从缓存中获取数据。
- 延时双删(Double-checked Locking):在获取缓存数据时,先从缓存中尝试获取,如果获取不到再加锁查询数据源。查询到数据后,更新缓存并释放锁。其他线程在等待期间会再次尝试从缓存中获取,避免了重复查询数据源。
-