大数据

Redis - 缓存穿透、击穿、雪崩

2021-12-11  本文已影响0人  坨坨的大数据

温馨提示:面试常问,多需结合项目实战经验

一、缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起id为-1的数据或者特别大的不存在的数据。有可能是黑客利用漏洞攻击从而去压垮应用的数据库。

常见解决方案

对于缓存穿透问题,常见的解决方案有以下三种:

Copypublic Student getStudentsByID(Long id) {
    // 从Redis中获取学生信息
    Student student = redisTemplate.opsForValue()
        .get(String.valueOf(id));
    if (student != null) {
        return student;
    }
    // 从数据库查询学生信息,并存入Redis
    student = studentDao.selectByStudentId(id);
    if (student != null) {
        redisTemplate.opsForValue()
            .set(String.valueOf(id), student, 60, TimeUnit.MINUTES);
    } else {
        // 即使不存在,也将其存入缓存中
        redisTemplate.opsForValue()
            .set(String.valueOf(id), null, 60, TimeUnit.SECONDS);
    }
    return student;
}

2. 布隆过滤器

注意:BloomFilter并不支持删除操作,只支持添加操作。这一点很容易理解,因为你如果要删除数据,就得将对应的bit位置为0,但是你这个Key对应的bit位可能其他的Key也对应着。

缓存空数据与布隆过滤器的比较

上面对这两种方案都进行了简单的介绍,缓存空数据与布隆过滤器都能有效解决缓存穿透问题,但使用场景有着些许不同;

二、缓存击穿

缓存击穿是指当前热点数据存储到期时,多个线程同时并发访问热点数据。因为缓存刚过期,所有并发请求都会到数据库中查询数据。

解决方案

Copypublic String get(key) {
    String value = redis.get(key);
    if (value == null) { // 代表缓存值过期
        // 设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
        if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  // 代表设置成功
            value = db.get(key);
            redis.set(key, value, expire_secs);
            redis.del(key_mutex);
        } else {  // 这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
            sleep(50);
            get(key);  // 重试
        }
    } else {
        return value;
    }
}

三、缓存雪崩

缓存雪崩发生有几种情况,比如大量缓存集中在或者缓存同时在大范围中失效,出现了大量请求去访问数据库,从而导致CPU和内存过载,甚至停机。

一个简单的雪崩过程:

  1. Redis 集群产生了大面积故障;
  2. 缓存失败,此时仍有大量请求去访问 Redis 缓存服务器;
  3. 在大量 Redis 请求失败后,这些请求将会去访问数据库;
  4. 由于应用的设计依赖于数据库和 Redis 服务,很快就会造成服务器集群的雪崩,最终导致整个系统的瘫痪。

解决方案

上一篇 下一篇

猜你喜欢

热点阅读