1.Redis-缓存击穿

缓存击穿是指在高并发场景下,当一个缓存对象失效的瞬间,有大量的请求同时到达,这些请求发现缓存中没有该数据,就会去数据库查询,这可能会导致数据库在瞬间承受巨大的压力,甚至导致数据库宕机。

缓存击穿通常发生在对某个热点数据进行高频率访问时,这个数据的缓存在某一时刻过期,而此时如果有大量的请求到来,它们都会去查询数据库,因为缓存中没有这个数据。

image-20240921002950971

这种情况在旁路缓存模式中容易触发,因为该模式更新数据时会删除缓存。特别是热点缓存数据一旦被删除,就需要考虑缓存被“击穿 ”的问题。

2.解决办法

2.1 互斥锁(Mutex Key):

在缓存失效时,先去获取一个互斥锁,只有获取到锁的请求才会去查询数据库并更新缓存,其他请求则等待或重试。这样可以保证在缓存失效时,只有一个请求去数据库查询数据并回写缓存。

public DataObject getData(Long id) {
    // 从缓存读取数据
    DataObject result = getDataFromCache(id);
    if (result != null) {
        return result;
    }

    // 缓存不存在,尝试获取互斥锁
    RLock lock = redissonClient.getLock(DATA_LOCK_NAME + id);
    lock.lock();
    try {
        // 双重检查,避免在等待锁的过程中,其他线程已经加载了数据
        result = getDataFromCache(id);
        if (result != null) {
            return result;
        }
        // 从数据库查询数据
        result = getDataFromDB(id);
        // 将查询到的数据写入缓存
        setDataToCache(id, result);
    } finally {
        lock.unlock();
    }
    return result;
}

2.2 逻辑过期:

在缓存数据时,同时存储数据的过期时间,当缓存数据被访问时,检查当前时间是否超过数据的逻辑过期时间,如果未过期,则直接返回数据;如果已过期,则从数据库加载新数据并更新缓存。

2.3 后台定时刷新:

通过后台任务定时刷新缓存数据,确保缓存数据不会同时过期,减少击穿的可能性。

2.4 热点数据不过期:

对于非常热点的数据,可以考虑设置为永不过期,或者过期时间非常长,由后台服务定期更新缓存数据。