缓存穿透、缓存击穿、缓存雪崩及解决方案

系统中常常用Redis来做缓存,极大的提升了系统性能和效率,但同时也存在一些问题。其一是数据一致性问题,严格意义上来讲,只要用到缓存,那就会有一致性问题,这是无解的。另一个问题就是本文要讲的缓存穿透、缓存击穿、缓存雪崩,不仅仅局限于Redis,其他方式实现的缓存,也存在着三个问题。

一、缓存穿透

缓存穿透是指,用户在查询一个数据库肯定不存在的数据时,这时的返回结果的null,结果不会存入缓存。假设用户不断的发起这种请求,始终不会命中缓存,从而导致所有查询都落到数据库上,造成数据库压力过大。

问题代码:

public Object getOrder(Long orderId) {

    Object orderInfo = redisTemplate.opsForValue().get(String.valueOf(orderId));
    if (orderInfo != null) { // 命中缓存,则直接返回redis中的值
        return orderInfo;
    }

    // 未命中缓存,则查询数据库
    orderInfo = orderDao.selectByOrderId(orderId);
    if (orderInfo != null) { // 查到了结果,则放入缓存
        redisTemplate.opsForValue().set(String.valueOf(orderId), orderInfo);
    }
    return orderInfo;
}

试想一下,如果黑客发起请求,参数orderId = -1,这种数据肯定是不会存在的,每次都会走到查询数据库,并且数据的查询结果也是null,也不会去缓存这个结果。

解决方案:

1、用户鉴权、参数校验等,将明显不合理的请求,拦截在上层

2、数据库查询结果为null时,也进行缓存,只不过缓存有效期设短一点,以免影响正常数据的缓存

解决代码:

public Object getOrder(Long orderId) {

    Object orderInfo = redisTemplate.opsForValue().get(String.valueOf(orderId));
    if (orderInfo != null) { // 命中缓存,则直接返回redis中的值
        return orderInfo;
    }

    // 未命中缓存,则查询数据库
    orderInfo = orderDao.selectByOrderId(orderId);
    if (orderInfo != null) { // 查到了结果,则放入缓存,60分钟有效期
        redisTemplate.opsForValue()
            .set(String.valueOf(orderId), orderInfo, 60, TimeUnit.MINUTES);
    } else { // 否则,也放入缓存,60秒有效期
        redisTemplate.opsForValue().set(String.valueOf(orderId), null, 60, TimeUnit.SECONDS);
    }
    return orderInfo;
}

二、缓存击穿

缓存击穿是指,某一个热点key数据过期时,多个线程高并发的去请求这个key,这是缓存刚好过期,到时所有的并发请求全部去数据库查询数据。

解决方案:

其实大多数实际业务场景中,即时发生缓存击穿,也不会对数据库造成太大的压力,因为一般的公司业务,并发量不会那么高,即时很不幸,你们发生了这种情况,可以通过将这些热点key,设置成永不过期即可。另外一种方式是,通过加锁来控制查询数据库的线程访问

三、缓存雪崩

缓存雪崩是指某一个时间,缓存中大量的key到了过期时间,这时候如果发生大量查询的话,将全部落到数据库上。与缓存击穿不同,前者是因为某一个key过期,并发查询这个key,后者是一个大量key同时过期,然后很多查询都查不到缓存。

解决方案:

1、缓存数据的过期时间,设置成一个随机值,防止同一时间大量key过期,热点数据有效期长一些,冷门数据有效期短一些

2、某些热点的key,设置成永不过期

3、如果是因为缓存服务器宕机造成的雪崩,可以采用分布式缓存服务器,提高其可用性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值