Redis持久化 三大异常问题 Jedis操作Redis

如果要该Redis配置文件

image

Redis的持久化是啥

Redis 是内存数据库,断电或重启后数据会丢失,所以需要持久化把内存数据写到磁盘,保证数据不丢。

redis两种持久化的方式

RDB和AOF

RDB使用场景

1.需要快速恢复、大数据量.

2.做定时备份、冷备份

3.对性能要求极高,写入非常频繁

4.能接受丢少量数据

AOF使用场景

1.核心业务数据,绝对不能丢或只能丢一点点.

2.要求数据安全性 > 恢复速度.

3.需要可追溯、可人工修复数据.

4.写入量不是特别夸张的业务.

常用方案

RDB + AOF 同时开启

AOF 保证数据安全

RDB 负责备份 + 快速恢复

AOF和RDB总结

想快、小、省性能 → 用 RDB

想安全、不丢数据 → 用 AOF

Redis内存淘汰机制

  Redis内存淘汰机制是指当内存使用达到上限(可通过maxmemory配置,0为不限制,即服务器内存上限),根据一定的算法来决定淘汰掉哪些数据,以保证新数据的存入。

常见的内存淘汰机制分为四大类:

  1. LRU:LRU是Least recently used,最近最少使用的意思,简单的理解就是从数据库中删除最近最少访问的数据,该算法认为,你长期不用的数据,那么被再次访问的概率也就很小了,淘汰的数据为最长时间没有被使用,仅与时间相关。

  2. LFU:LFU是Least Frequently Used,最不经常使用的意思,简单的理解就是淘汰一段时间内,使用次数最少的数据,这个与频次和时间相关。

  3. TTL:Redis中,有的数据是设置了过期时间的,而设置了过期时间的这部分数据,就是该算法要解决的对象。如果你快过期了,不好意思,我内存现在不够了,反正你也要退休了,提前送你一程,把你干掉吧。

  4. 随机淘汰:生死有命,富贵在天,是否被干掉,全凭天意了。

  通过maxmemroy-policy可以配置具体的淘汰机制,看了网上很多文章说只有6种,其实有8种,可以看Redis5.0的配置文件,上面有说明:

  1. volatile-lru -> 找出已经设置过期时间的数据集,将最近最少使用(被访问到)的数据干掉。
  2. volatile-ttl -> 找出已经设置过期时间的数据集,将即将过期的数据干掉。
  3. volatile-random -> 找出已经设置过期时间的数据集,进行无差别攻击,随机干掉数据。
  4. volatile-lfu -> 找出已经设置过期时间的数据集,将一段时间内,使用次数最少的数据干掉。

  5. allkeys-lru ->与第1个差不多,数据集从设置过期时间数据变为全体数据。
  6. allkeys-lfu -> 与第4个差不多,数据集从设置过期时间数据变为全体数据。
  7. allkeys-random -> 与第3个差不多,数据集从设置过期时间数据变为全体数据。

  8. no-enviction -> 什么都不干,报错,告诉你内存不足,这样的好处是可以保证数据不丢失,这也是系统默认的淘汰策略。

Redis过期Key清除策略

三种清除策略  Redis中大家会对存入的数据设置过期时间,那么这些数据如果过期了,Redis是怎么样把他们消灭掉的呢?我们一起来探讨一下。下面介绍三种清除策略:

惰性删除

惰性删除:当访问Key时,才去判断它是否过期,如果过期,直接干掉。这种方式对CPU很友好,但是一个key如果长期不用,一直存在内存里,会造成内存浪费。

定时删除:

设置键的过期时间的同时,创建一个定时器,当到达过期时间点,立即执行对Key的删除操作,这种方式最不友好。

定期删除:

隔一段时间,对数据进行一次检查,删除里面的过期Key,至于要删除多少过期Key,检查多少数据,则由算法决定。举个例子方便大家理解:Redis每秒随机取100个数据进行过期检查,删除检查数据中所有已经过期的Key,如果过期的Key占比大于总数的25%,也就是超过25个,再重复上述检查操作。

  Redis服务器实际使用的是惰性删除和定期删除两种策略:通过配合使用这两种删除策略,可以很好地在合理使用CPU和避免浪费内存之间取得平衡。

Redis 缓存使用中的三大经典异常问题。 Redis 缓存使用中的三大经典异常问题。

1.Redis的内存穿透

当key过期时,透过redis强制访问mysql.(查不存在的数据)

redis内存穿透如果多的话效率会降低.

遇到的场景

不存在的数据1.有人恶意刷接口:比如一直查 id=-1、id=99999999 这种不存在的数据

2.正常业务但大量查询已删除 / 不存在的数据

3.爬虫、接口被刷

解决措施

1.缓存空值

查不到也存一个 null 或空对象,设置短过期时间。

布隆过滤器

2.提前把合法 ID 全部放进布隆,不存在的直接拒绝。

3.接口校验 + 限流

参数非法直接拦截,对同一 IP 限流。

4.黑名单拦截恶意请求

2.Redis的内存击穿

一个热点key过期时要在Redis中找,Redis没有要在mysql中找,结果mysql里也没有

遇到场景

秒杀、热点商品、热门活动

某个超高并发 key 刚好过期的一瞬间

热点文章、热搜、明星相关接口

解决措施

1.互斥锁(mutex lock)

只允许一个线程去查库重建缓存,其他等待。

2.热点 key 永不过期

逻辑过期:后台定时主动刷新,不依赖自动过期。

3.提前异步刷新缓存

4.加本地缓存(Caffeine)做兜底

3.Redis的内存雪崩

大量 key 同一时间过期,Redis 直接不可用,流量全部打到数据库。

结果就是:数据库瞬间扛不住 → 数据库卡死 → 整个应用不可用 → 系统雪崩。

遇到场景

1.大量 key 设置了相同过期时间,同一时间集体失效

2.Redis 单机 / 集群宕机

3.重启 Redis、网络抖动导致缓存服务不可用

解决措施

1.过期时间加随机值

比如 60*60 + random(300),打散过期时间。

2.Redis 高可用

主从 + 哨兵 / Redis Cluster,避免单点挂掉。

3.多级缓存

本地缓存 + Redis 缓存双重保障。

4.限流、熔断、降级

数据库扛不住就限流,非核心接口直接降级。

5.互斥锁防止缓存并发重建

用Jedis操作Redis

创建maven项目

image

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.wolfcode</groupId>
    <artifactId>redis_demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.3</version>
        <relativePath/>
    </parent>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

JedisTest代码

package cn.wolfcode;

import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Set;

public class JedisTest {
    @Test
    public void testRedis(){
        //获取jedis连接池对象
        JedisPool jedisPool=new JedisPool("localhost",6379);
        //获取jedis连接对象
        Jedis jedis = jedisPool.getResource();
        //设置密码
jedis.auth("123456");
        //书写redis代码
        //String
jedis.set("str","我是string");
        //hash
        jedis.hset("user", "name", "张三");
        jedis.hset("user", "age", "20");
        jedis.hincrBy("user","age",10);
        //list
        jedis.rpush("arr","1","6","13");
        String number = jedis.lpop("arr");
        System.out.println(number);
        //set
        jedis.sadd("hobbys","java","pyhon","C++");
        Set<String> hobbys = jedis.spop("hobbys", 1);
        System.out.println(hobbys);
        //zset
        jedis.zadd("z",100,"小芳");
        jedis.zadd("z",98,"小名");
        jedis.zadd("z",80,"小红");

        //关闭连接
        jedis.close();
        //销毁连接池对象
        jedisPool.destroy();

 
    }
}

application.yml代码

image

posted on 2026-03-20 20:22  Zyy_32opr  阅读(15)  评论(0)    收藏  举报

导航