Redis高级

文章介绍了Redis的两种持久化策略AOF和RDB,以及如何配置和选择。此外,讨论了Redis的淘汰策略,包括LRU和LFU等。针对缓存问题,如雪崩、击穿和穿透,提出了解决方案,包括设置随机过期时间、使用布隆过滤器等。
摘要由CSDN通过智能技术生成

持久化 

持久化策略

持久化策略包含

  • AOF:默认每秒对数据进行持久化

  • RDB:按条件触发持久化操作,满足任意一个条件 1) 900 1 900秒中修改1次 2) 300 10 300秒中修改10次 3) 60 10000 60秒中修改10000次  

配置方法

修改redis.conf 配置文件

 

 启动AOF的配置

appendonly yes   开启AOF  
appendfsync everysec  每秒保存

选择持久化策略 

  • 允许少量数据丢失,性能要求高,选择RDB

  • 只允许很少数据丢失,选择AOF

  • 几乎不允许数据丢失,选择RDB + AOF

淘汰策略

Redis中的数据太多可能导致内存溢出,Redis会根据情况淘汰一些数据。 Redis的内存上限:64位系统,上限就是内存上限;32位系统,最大是4G

  • noevication(默认)不淘汰

  • volatile-ttl 在过期键中淘汰存活时间短的键

  • allkeys-lru (推荐)使用LRU算法淘汰比较少使用的键 LRU算法:Least Recently Used 最近最少使用算法,淘汰长期不用的缓存

    LFU算法:Least Frequently Used 频率最少使用算法,淘汰使用频率少的缓存

  • volatile-lru 在过期的键中淘汰较少使用的

  • allkeys-random 在所有键中随机淘汰

  • volatile-random 在过期键中随机淘汰

  • allkeys-lfu

  • volatile-lfu

Redis并发

缓存雪崩

原因:

  1. Redis热点数据同时过期,大量请求全部打到MySQL,MySQL宕机
  2. 单个Redis服务出现问题或重启

解决: 

  1. 将热点数据过期时间设置为随机值,避免同时过期
  2. 配置Redis集群,解决单点故障问题  

缓存击穿 

原因:

大量并发请求访问Redis同一个数据,还没有向Redis保存,有大量线程同时访问,导致MySQL压力过大

解决: 

通过上锁(双检锁)实现线程同步执行

代码示例:

 @Override
    public Food getFoodById(Long id) {

        // 获得字符串操作对象
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        // 查询Redis缓存
        Food food = (Food) ops.get(PREFIX + id);


        if (food == null) {
            // 从数据库查询
            food = foodMapper.selectById(id);
            if (food != null) {
                System.out.println("MySQL查到,返回" + food);
                // 将查询结果保存到Redis
                redisTemplate.opsForValue().set(PREFIX + id, food);
            }
        }


        // 如果Redis缓存存在,就返回数据
        if (food != null) {
            System.out.println("Redis查到,返回" + food);
            return food;
        }

        // MySQL和Redis都没有数据,则返回null
        return null;
    }
@GetMapping("/food/{id}")
    public ResponseResult<Food> getFoodById(@PathVariable Long id){
        Food food = foodService.getFoodById(id);
        return ResponseResult.ok(food);
    }

 

缓存穿透 

原因:

大量请求访问MySQL没有的数据,Redis缓存无法命中,导致数据库压力过大

解决:

  1. 在Redis中保存空对象,给空对象设置过期时间
  2. 使用布隆过滤器筛选掉不存在的数据  

代码示例1:给对象设置过期时间 

    @Override
    public Student getStudentById(Long id) {
        //获得字符串操作对象
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        //先查询Redis,如果存在数据就不执行同步代码块,直接返回
        Student stu = (Student) ops.get(PREFIX + id);
        if(stu == null) {
            synchronized (this) {
                System.out.println("进入了同步锁");
                //先查询Redis
                stu = (Student) ops.get(PREFIX + id);
                //如果Redis缓存存在数据,就直接返回
                if (stu != null) {
                    System.out.println("Redis查到,返回" + stu);
                    return stu;
                }
                //如果Redis没有查到数据,就查询MySQL
                stu = studentMapper.selectById(id);
                //MySQL查到数据,就保存到Redis
                if (stu != null) {
                    System.out.println("MySQL查到,返回" + stu);
                    ops.set(PREFIX + id, stu);
                    return stu;
                }else {
                    //MySQL没有数据,在Redis保存空对象,设置过期时间
                    System.out.println("MySQL没有数据");
                    Student student = new Student();
                    ops.set(PREFIX + id, student,5, TimeUnit.SECONDS);
                }
            }
        }else {
            System.out.println("没有执行同步锁");
        }
        return stu;
    }

代码示例2:使用布隆过滤器

步骤一:导入依赖、定义配置类 

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.16.6</version>
</dependency>

 

@Configuration
public class RedissonConfig {

    @Bean
    public RBloomFilter<String> bloomFilter(){
        Config config = new Config();
        config.setTransportMode(TransportMode.NIO);
        SingleServerConfig singleServerConfig = config.useSingleServer();
        singleServerConfig.setAddress("redis://127.0.0.1:6379");
        RedissonClient redisson = Redisson.create();
        //创建布隆过滤器
        RBloomFilter<String> bloomFilter = redisson.getBloomFilter("Food-filter");
        bloomFilter.tryInit(10000000L,0.03);
        return bloomFilter;
    }
}

步骤二: 将数据的id保存到过滤器中  

@Autowired
    private RBloomFilter<String> rBloomFilter;

@GetMapping("/init-food-filter")
    public ResponseResult<String> initFoodFilter(){
        List<Food> list = foodService.list();
        list.forEach(food -> {
            rBloomFilter.add(String.valueOf(food.getId()));
        });
        return ResponseResult.ok("ok");
    }

步骤三:使用过滤器排除不存在的数据

@Override
    public Food getFoodById(Long id) {
        // 先检查布隆过滤器,判断数据是否可能存在于Redis中
        if (rBloomFilter.contains(String.valueOf(id))) {
            // 获得字符串操作对象
            ValueOperations<String, Object> ops = redisTemplate.opsForValue();
            // 查询Redis缓存
            Food food = (Food) ops.get(PREFIX + id);

            if (food == null) {
                synchronized (this) {
                    System.out.println("执行了同步锁");
                    food = (Food) ops.get(PREFIX + id);
                    if (food == null) {
                        // 从数据库查询
                        food = foodMapper.selectById(id);
                        if (food != null) {
                            System.out.println("MySQL查到,返回" + food);
                            // 将查询结果保存到Redis
                            redisTemplate.opsForValue().set(PREFIX + id, food);
                        }
                    }
                }
            }

            // 如果Redis缓存存在,就返回数据
            if (food != null) {
                System.out.println("Redis查到,返回" + food);
                return food;
            }
        } else {
            System.out.println("布隆过滤器判断id不存在");
        }

        // MySQL和Redis都没有数据,则返回null
        return null;
    }

 

 

 

黑马Redis高级篇是一个关于Redis高级应用的教程。在这个教程中,涉及到了创建文件和目录的操作,以及配置Redis实例的过程。在创建文件和目录的步骤中,可以使用以下命令: 1. 创建文件和目录: - 创建redis目录:cd /home && mkdir redis - 在redis目录下创建myredis1、myredis2和myredis3目录:mkdir /home/redis/myredis1, mkdir /home/redis/myredis2, mkdir /home/redis/myredis3 - 在myredis1、myredis2和myredis3目录分别创建myredis.conf配置文件和data目录:touch /home/redis/myredis1/myredis.conf, mkdir /home/redis/myredis1/data, touch /home/redis/myredis2/myredis.conf, mkdir /home/redis/myredis2/data, touch /home/redis/myredis3/myredis.conf, mkdir /home/redis/myredis3/data - 创建mysentinel1、mysentinel2和mysentinel3目录:mkdir /home/redis/mysentinel1, mkdir /home/redis/mysentinel2, mkdir /home/redis/mysentinel3 2. Redis实例信息如下: - IPPORT角色 - 10.13.164.55:7001 master - 10.13.164.55:7002 master - 10.13.164.55:7003 master - 10.13.164.55:7004 slave - 10.13.164.55:7005 slave - 10.13.164.55:7006 slave 根据这些信息,你可以按照上述步骤创建文件和目录,并配置Redis实例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马Redis6高级篇](https://blog.csdn.net/D_boj/article/details/131712945)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值