Redis缓存机制

89 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第18天,点击查看活动详情

一. 缓存雪崩

缓存雪崩是指在短时间内,有大量缓存同时过期,导致大量的请求直接查询数据库,从而对数据库造成了巨大的压力,严重情况下可能会导致数据库宕机的情况叫做缓存雪崩。

\

我们可以看出:可以看到,当缓存失效时,大量请求直接绕过 Redis 去请求数据库,导致会对数据库造成很大压力。

解决方法:

1.加锁排队

思路:相当于单例模式的双重加锁机制

// 缓存 key
String cacheKey = "userlist";
// 查询缓存
String data = jedis.get(cacheKey);
if (StringUtils.isNotBlank(data)) {
    // 查询到数据,直接返回结果
    return data;
} else {
    // 先排队查询数据库,再放入缓存
    synchronized (cacheKey) {
        data = jedis.get(cacheKey);
        if (!StringUtils.isNotBlank(data)) { // 双重判断
            // 查询数据库
            data = findUserInfo();
            // 放入缓存
            jedis.set(cacheKey, data);
        }
        return data;
    }
}

注意:如果是分布式架构,不能采用本地锁,要采用redis分布式锁。

2.随机化过期时间

为了避免缓存同时过期,可在设置缓存时添加随机时间,这样就可以极大的避免大量的缓存同时失效。

// 缓存原本的失效时间
int exTime = 10 * 60;
// 随机数生成类
Random random = new Random();
// 缓存设置
jedis.setex(cacheKey, exTime + random.nextInt(1000) , value);

\

二.缓存穿透

缓存穿透说白了就是查询一个一定不存在的数据,由于缓存是未命中从数据库去查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。

\

解决方法:

1.布隆过滤器:

我们可以使用布隆过滤器来解决,可以将布隆过滤器想象成一个map,请求一个不存在的数据,我们就把它放到这个map中,每次请求前先通过map过滤一遍,如果map中存在这个值就直接将请求拦截掉。

2.缓存空结果:

我们可以把每次从数据库查询的数据都保存到缓存中,我们可以将空结果的缓存时间设置得短一些,例如 1-3 分钟。

\

三、缓存击穿

缓存击穿指的是某个热点缓存,在某一时刻恰好失效了,然后客户端访问数据的时候,redis中没有数据,mysql中有数据,相当于直接跳过了redis。

解决方法:

1.加锁排队

在查数据库时进行加锁,缓冲大量请求, 以减少数据库压力

2.设置永不过期

对于某些热点缓存,我们可以设置永不过期,这样就能保证缓存的稳定性,但需要注意在数据更改之后,要及时更新此热点缓存,不然就会造成查询结果的误差。

\

四、缓存预热

缓存预热并不是一个问题,而是使用缓存时的一个优化方案,它可以提高前台用户的使用体验。

缓存预热指的是在系统启动的时候,先把查询结果预存到缓存中,以便用户后面查询时可以直接从缓存中读取,以节约用户的等待时间。