【Java面试】redis雪崩、穿透和击穿详解

这篇具有很好参考价值的文章主要介绍了【Java面试】redis雪崩、穿透和击穿详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一 Redis雪崩、穿透和击穿

1. Redis雪崩
 Redis雪崩是指在某一时刻,缓存中大量的缓存数据同时失效或过期,导致大量的请求直接打到后端数据库,导致数据库负载剧增,引发性能问题甚至崩溃。这通常是因为缓存数据的过期时间设置过于集中,或者在同一时间段内大量缓存同时失效造成的。

2. Redis穿透
 Redis穿透是指恶意或者异常请求查询一个不存在于缓存和数据库中的数据,导致每次请求都会直接访问数据库,增加了数据库负担。这可能是攻击者故意进行的,也可能是由于业务逻辑问题造成的。

3. Redis击穿
 Redis击穿是指某个热点数据突然失效或被删除,而此时大量请求正好同时访问该热点数据,导致这些请求都直接打到数据库上,导致数据库压力激增。与雪崩不同,击穿是因为某个特定的缓存数据失效导致。

示例:

让我们以一个简单的Java代码示例来说明Redis雪崩、穿透和击穿的概念。

假设有一个电影信息查询系统,用户可以根据电影ID查询电影信息。我们使用Redis作为缓存来存储电影信息,但是只对热门电影设置了缓存,其他电影没有被缓存。

@Service
public class MovieService {

    @Autowired
    private MovieRepository movieRepository;

    @Autowired
    private Jedis jedis;

    public Movie getMovieInfo(String movieId) {
        String cacheKey = "movie:" + movieId;
        String cachedInfo = jedis.get(cacheKey);

        if (cachedInfo == null) {
            Movie movie = movieRepository.findById(movieId);
            if (movie != null) {
                jedis.setex(cacheKey, 3600, movie.toString()); // 缓存1小时
                return movie;
            }
        }
        return Movie.fromString(cachedInfo);
    }
}

Redis雪崩示例:
假设在某一时刻,缓存中存储了很多电影信息,这些缓存在同一时间内同时失效,导致大量请求直接访问数据库,造成数据库压力激增。

Redis穿透示例:
有一个恶意用户不断发送不存在的电影ID,每次请求都会绕过缓存,直接查询数据库,导致数据库压力增加。

Redis击穿示例:
假设某个热门电影的缓存在某个时间点失效,而在这个时间点正好有大量用户同时查询该电影信息,导致所有请求直接访问数据库,造成数据库压力激增。

二 解决方案

2.1 对缓存数据的过期时间进行随机化,避免集中失效。

  1. 选择随机时间范围: 首先,你需要选择一个适当的随机时间范围,用于分散缓存数据的过期时间。例如,你可以选择在原始过期时间基础上添加一个随机的秒数,这样每个缓存项的过期时间就会稍微有所不同。

  2. 生成随机时间: 在获取缓存数据时,生成一个随机的秒数,然后将其添加到原始过期时间上,得到一个新的过期时间。

  3. 设置缓存数据: 将缓存数据存储到Redis中,并设置使用上一步生成的新过期时间。
     

    @Service
    public class CacheService {
    
        @Autowired
        private Jedis jedis;
    
        public String getCachedData(String key) {
            String cachedData = jedis.get(key);
    
            if (cachedData == null) {
                // 查询数据库获取数据
                String dbData = Database.queryData(key);
    
                if (dbData != null) {
                    // 生成随机的过期时间(在1小时基础上随机增加0-300秒)
                    int originalExpireTime = 3600; // 1小时的秒数
                    int randomSeconds = new Random().nextInt(300); // 0到300秒的随机数
                    int cacheDuration = originalExpireTime + randomSeconds;
    
                    // 将数据存储到缓存并设置随机过期时间
                    jedis.setex(key, cacheDuration, dbData);
    
                    return dbData;
                }
            }
    
            return cachedData;
        }
    }
    

2.2 使用布隆过滤器来过滤恶意请求,防止缓存穿透。

使用布隆过滤器来过滤恶意请求,以防止缓存穿透是一种常见的防御策略。布隆过滤器是一种数据结构,用于判断一个元素是否存在于集合中,它可以高效地进行快速查询,但可能会有一定的误判率。

下面是一个使用Spring Boot和布隆过滤器来防止缓存穿透的详细举例:

步骤:

引入依赖: 在Spring Boot项目中,添加所需的依赖,包括Spring Boot、Jedis和Google Guava(用于实现布隆过滤器)。

初始化布隆过滤器: 在启动时初始化一个布隆过滤器,用于存储已查询的缓存键。

查询缓存数据: 在获取数据之前,首先检查布隆过滤器,如果缓存键可能存在,则再查询缓存。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import redis.clients.jedis.Jedis;

@Service
public class CacheService {

    private final Jedis jedis;
    private final BloomFilter<String> bloomFilter;

    @Autowired
    public CacheService(Jedis jedis) {
        this.jedis = jedis;
        this.bloomFilter = BloomFilter.create(Funnels.stringFunnel(), 1000, 0.01); // 初始化布隆过滤器
    }

    public String getCachedData(String key) {
        if (!bloomFilter.mightContain(key)) { // 判断是否可能存在于集合中
            return null; // 不再查询缓存和数据库,直接返回null
        }

        String cachedData = jedis.get(key);

        if (cachedData == null) {
            // 查询数据库获取数据
            String dbData = Database.queryData(key);

            if (dbData != null) {
                jedis.setex(key, 3600, dbData); // 缓存1小时
                bloomFilter.put(key); // 将键添加到布隆过滤器中
                return dbData;
            }
        }

        return cachedData;
    }
}

2.3 使用互斥锁(例如分布式锁)来防止击穿,只允许一个请求去查询数据库,其他请求等待或直接使用缓存。

使用互斥锁(分布式锁)来防止击穿是一种常见的策略,可以确保在缓存失效的情况下,只有一个请求能够去查询数据库,其他请求需要等待该请求完成或直接使用缓存。下面是一个使用Spring Boot和Jedis实现分布式锁来防止击穿的代码示例:

步骤:

1、引入依赖: 在Spring Boot项目中,添加所需的依赖,包括Spring Boot和Jedis。

2、获取分布式锁: 在查询数据库之前,使用分布式锁来确保只有一个请求能够进行数据库查询。

3、释放分布式锁: 在查询完成后,释放分布式锁,让其他请求能够继续执行


@Service
public class CacheService {

    @Autowired
    private Jedis jedis;

    public String getCachedData(String key) {
        String cachedData = jedis.get(key);

        if (cachedData == null) {
            // 尝试获取分布式锁,设置锁的过期时间,防止死锁
            String lockKey = "lock:" + key;
            String lockValue = "lockValue";
            SetParams params = new SetParams().ex(60).nx(); // 设置60秒过期时间,只有不存在时才设置

            String acquiredLock = jedis.set(lockKey, lockValue, params);

            if (acquiredLock != null) {
                try {
                    // 查询数据库获取数据
                    String dbData = Database.queryData(key);

                    if (dbData != null) {
                        jedis.setex(key, 3600, dbData); // 缓存1小时
                        return dbData;
                    }
                } finally {
                    // 释放分布式锁
                    jedis.del(lockKey);
                }
            } else {
                // 等待一段时间后重新查询缓存
                try {
                    Thread.sleep(200); // 可以根据实际情况调整等待时间
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }

                // 重新查询缓存
                cachedData = jedis.get(key);
            }
        }

        return cachedData;
    }
}

2.4 合理设置缓存策略,确保热门数据始终保持缓存,避免缓存雪崩。

确保热门数据始终保持缓存,避免缓存雪崩,需要采取一些合理的缓存策略。以下是一些常见的合理方案:

1. 定时刷新缓存: 使用定时任务或调度器,定期刷新热门数据的缓存。这可以确保缓存中的数据始终保持最新,避免数据过期。

2. 永不过期策略:对于热门数据,可以设置永不过期的缓存策略。但要注意,如果热门数据发生变化,需要手动更新缓存。

3. 热点数据预加载:在应用启动时,预先加载热门数据到缓存中,确保缓存中存在最常用的数据。

4. 基于访问频率的过期策略: 根据数据的访问频率动态调整过期时间。访问频率高的数据设置较长的过期时间,访问频率低的数据设置较短的过期时间。

5. 分布式锁控制:** 在缓存失效时,使用分布式锁来防止多个请求同时查询数据库,确保只有一个请求进行查询并更新缓存。

6. 降级策略: 如果缓存失效,可以暂时使用降级策略,例如返回默认值或静态数据,以避免直接访问数据库。

7. 多级缓存: 使用多级缓存架构,将热门数据存储在多个缓存层中,例如内存缓存和分布式缓存,以提高数据的访问速度和稳定性。

8. 请求合并: 对于同时涌入的大量请求,可以考虑将它们合并成一个请求,只查询一次数据库,然后将结果分发给多个请求。

9. 缓存预热: 在系统负载较低的时候,提前将热门数据加载到缓存中,以减少在高负载时的数据库压力。

10. 动态缓存策略: 根据系统的实际情况,动态调整缓存策略,例如根据时间段、节假日等因素来设置不同的缓存策略。

选择合适的方案取决于你的业务需求和系统特点。通常,结合多个方案可以更好地保护热门数据,避免缓存雪崩问题。文章来源地址https://www.toymoban.com/news/detail-653271.html

到了这里,关于【Java面试】redis雪崩、穿透和击穿详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

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

    我们通过对数据库的数据进行查询后在redis中缓存,但是在高并发环境下,某个保存的key值在失效的瞬间被大量并发请求访问,这些持续的大并发量就会穿破缓存,直接请求数据库,会对数据库造成巨大压力,这些请求还会使数据多次写入缓存,多了许多不必要的操作。    

    2024年02月08日
    浏览(45)
  • Redis缓存穿透,雪崩,击穿

    1、定义 缓存 就是数据交换的 缓冲区 ,缓存就是 缓冲区内的数据 ,一般从数据库中获取,存储于本地代码。 由于其被 Static 修饰,所以随着类的加载而被加载到 内存之中 ,作为本地缓存,由于其又被 final 修饰,所以其引用和对象之间的关系是固定的,不能改变,因此不用担心赋值(=

    2024年02月10日
    浏览(49)
  • redis缓存雪崩、穿透和击穿

    缓存雪崩   对于系统 A,假设每天高峰期每秒 5000 个请求,本来缓存在高峰期可以扛住每秒 4000 个请求,但是缓存机器意外发生了全盘宕机或者大量缓存集中在某一个时间段失效。缓存挂了,此时 1 秒 5000 个请求全部落数据库,数据库必然扛不住,它会报一下警,然后就挂了

    2024年01月22日
    浏览(39)
  • Redis 缓存穿透击穿和雪崩

             Redis 缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解。如果对数据的一致性要求很高,那么就不能使用缓存。 2.1 概念    

    2024年02月10日
    浏览(46)
  • Redis 缓存雪崩、穿透、击穿、预热

            在实际工程中,Redis 缓存问题常伴随高并发场景出现。例如, 电商大促、活动报名、突发新闻 时,由于缓存失效导致大量请求访问数据库,导致 雪崩 、 击穿 、 穿透 等问题。因此,新系统上线前需 预热 缓存,以应对高并发,减轻数据库压力。本章主要围绕这

    2024年04月12日
    浏览(48)
  • Redis——如何解决redis穿透、雪崩、击穿问题

    查询商品信息的常规代码示例 2.1、缓存击穿的理解 高并发时,当一个kev非常热点(类似于爆款)在不停的扛着大并发当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库并设置到缓存中,导致性能下降。 2.2、缓存击穿的解决方案 设置缓存永不过期 加锁排队 2

    2024年02月11日
    浏览(36)
  • Redis 缓存穿透、缓存雪崩、缓存击穿

    缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。 常见的解决方案有两种:         缓存空对象                  优点:实现简单,维护方便                 缺点: 额外的内存消耗 可能造

    2024年02月02日
    浏览(46)
  • Redis01-缓存击穿、穿透和雪崩

    目录 开场白-追命3连 使用场景 01缓存穿透场景与方案 02布隆过滤器 03缓存击穿场景与方案 04缓存雪崩场景与方案 开场白-追命3连 看你项目中有说用到Redis,都是哪些场景使用了Redis呢? 如果发生了缓存穿透、击穿、雪崩如何应对呢?缓存中数据的持久化和双写一致怎么实现的

    2024年02月05日
    浏览(31)
  • Redis - 三大缓存问题(穿透、击穿、雪崩)

    概念: 查询一个数据库中也不存在的数据,数据库查询不到数据也就不会写入缓存,就会导致一直查询数据库 解决方法: 如果数据库也查询不到,就把空结果进行缓存 缺点是 - 消耗内存 布隆过滤器的作用 :检索一个元素是否在某个集合中 布隆过滤器由组成 : 位图 + 若干

    2024年02月14日
    浏览(41)
  • redis 缓存雪崩 && 缓存击穿 && 缓存穿透

    什么是缓存雪崩 当我们提到缓存系统中的问题,缓存雪崩是一个经常被讨论的话题。缓存雪崩是指在某一时刻发生大量的缓存失效,导致瞬间大量的请求直接打到了数据库,可能会导致数据库瞬间压力过大甚至宕机。尤其在高并发的系统中,这种情况会导致连锁反应,整个系

    2024年02月07日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包