欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

成神之路之Redis从头开始学习(二)

程序员文章站 2022-05-23 11:27:10
...

成神之路之Redis从头开始学习(二)

四 Java连接Redis

Jedis连接Redis,Lettuce连接Redis

4.1 Jedis连接Redis

1、创建maven项目

成神之路之Redis从头开始学习(二)

2、导入需要的依赖包

https://mvnrepository.com/

<dependencies>
  <!--1、Jedis依赖包-->
  <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
  <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
  </dependency>
  <!--2、Junit测试-->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
  </dependency>
  <!--3、Lombok依赖包-->
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
  </dependency>
</dependencies>

3、测试

public class Demo1 {
    @Test
    public void set(){
        //1、连接Redis
        Jedis jedis = new Jedis("127.0.0.1",6379);
        //2、操作Redis - redis的命令是什么jedis对应的方法就是什么
        jedis.set("name","zhangsan");
        //3、释放资源
        jedis.close();
    }
    @Test
    public void get(){
        //1、连接Redis
        Jedis jedis = new Jedis("127.0.0.1",6379);
        //2、操作Redis - redis的命令是什么jedis对应的方法就是什么
        String value = jedis.get("name");
        System.out.println(value);
        //3、释放资源
        jedis.close();
    }
}

 

4.2 Jedis如何存储一个对象到Redis

准备一个User实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
​
    private Long id;
​
    private String name;
​
    private Date birthday;
}

导入spring-context依赖

<!--4、导入spring-context-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.20.RELEASE</version>
</dependency>

创建Demo测试类,编写内容

public class Demo2 {
    //存储对象 -- 以byte[]形式存储在redis中
    @Test
    public void setByteArray(){
        //1、连接redis服务
        Jedis jedis = new Jedis("127.0.0.1",6379);
        //2.1 准备key(String) - value(User)
        String key = "user";
        User user = new User(1L,"张三",new Date());
        //2.2 将key和value转换为byte[]
        byte[] byteKey = SerializationUtils.serialize(key);
        //user对象序列化和反序列化,需要在User类实现Serializable接口
        byte[] byteValue = SerializationUtils.serialize(user);
        //2.3 将key和value存储到redis
        jedis.set(byteKey,byteValue);
        //3、释放资源
        jedis.close();
    }
    @Test
    public void getByteArray(){
        //1、连接redis服务
        Jedis jedis = new Jedis("127.0.0.1",6379);
        //2.1 准备key(String)
        String key = "user";
        //2.2 将key转换为byte[]
        byte[] byteKey = SerializationUtils.serialize(key);
        //2.3 获取value
        byte[] byteValue = jedis.get(byteKey);
        //2.4 将value反序列化为user对象
        User user2 = (User)SerializationUtils.deserialize(byteValue);
        System.out.println(user2);
        //3、释放资源
        jedis.close();
    }
}

 

4.3 Jedis如何存储一个对象到Redis,以String的形式存储

导入一个fastjson依赖

<!--5、导入fastjson-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.71</version>
</dependency>

编写测试类

public class Demo3 {
    //存储的对象,以String形式
    @Test
    public void setString(){
        //1、连接redis
        Jedis jedis = new Jedis("127.0.0.1",6379);
        //2.1 准备key(String) - value(User)
        String stringKey = "stringUser";
        User value = new User(2L,"李四",new Date());
        //2.2 使用fastjson将value格式化为json字符串
        String stringVlue = JSON.toJSONString(value);
        //2.3 存储到redis中
        jedis.set(stringKey,stringVlue);
        //3关闭连接
        jedis.close();
    }
    @Test
    public void getString(){
        //1、连接redis
        Jedis jedis = new Jedis("127.0.0.1",6379);
        //2.1 准备key
        String stringKey = "stringUser";
        //2.2 去redis中查询value
        String stringValue =jedis.get(stringKey);
        //2.3 将value反序列化为User
        User user = JSON.parseObject(stringValue,User.class);
        System.out.println(user);
        //3关闭连接
        jedis.close();
    }
}

 

4.4 Jedis连接池的操作

@Test
public void pool2(){
    //1、创建连接池的配置信息
    GenericObjectPoolConfig config = new GenericObjectPoolConfig();
    //连接池中最大的活跃数
    config.setMaxTotal(100);
    //最大空闲数
    config.setMaxIdle(10);
    //最大空闲数
    config.setMinIdle(5);
    //当连接池空了之后,多久没获取到jedis对象就超时,单位毫秒
    config.setMaxWaitMillis(3000);
    //2、创建连接池
    JedisPool pool = new JedisPool(config,"127.0.0.1",6379);
    //3、获取jedis
    Jedis jedis = pool.getResource();
    //4、操作
    String value = jedis.get("stringUser");
    System.out.println(value);
    //6、释放连接
    jedis.close();
}

 

4.5 Redis的管道操作

因为在操作Redis的时候,执行一个命令需要先发送请求到Redis服务器,这个过程需要经历网络延迟,Redis还需要给客户端一个响应。

如果我需要一次性执行很多个命令,上述的方式效率很低,可以通过Redis的管道,先将命令放到客户端的一个pipeline中,之后一次性的将全部命令发送到Redis服务器,Redis服务一次性的将全部的返回结果响应给客户端。

//Redis的管道操作
@Test
public void pipeline(){
    //1、创建连接
    JedisPool pool = new JedisPool("127.0.0.1",6379);
    long start = System.currentTimeMillis();
    //2、获取一个连接对象
    Jedis jedis = pool.getResource();
//        //3、执行incr - 10000次
//        for (int i = 0; i < 50000; i++) {
//            jedis.incr("pp");
//        }
//        //4、释放资源
//        jedis.close();
    //------------------
​
    //3、创建管道
    Pipeline pipeline = jedis.pipelined();
    //4、执行incr - 10000次放到管道中
    for (int i = 0; i < 50000; i++) {
        pipeline.incr("qq");
    }
    pipeline.syncAndReturnAll();
    //5、释放资源
    jedis.close();
    long end = System.currentTimeMillis();
    System.out.println(end-start);
}

 

五 Redis其他配置及集群

修改yaml文件,以方便后期修改Redis配置信息

#指定本 yml 依从的 compose 哪个版本制定的
version: '3.1'
#定义服务
services:
#定义一个服务
  redis:
    #指定镜像
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    #容器名称
    container_name: redis
    #添加环境变量。指定时区
    environment:
      - TZ=Asia/Shanghai
    #添加端口映射
    ports:
      - 6379:6379
    #将主机当前目录的conf目录下的redis.conf挂载到容器里的/usr/local/redis.conf。
    volumes:
      - ./conf/redis.conf:/usr/local/redis.conf
    #覆盖容器启动的默认命令。
    command: ["redis-server","/usr/local/redis.conf"]

执行docker命令:

#停止和删除容器、网络、卷、镜像。先停止和删除之前的redis容器
docker-compose down
#重新创建容器并后台启动
docker-compose up -d

 

5.1 Redis的AUTH

方式一:通过修改Redis的配置文件,实现Redis的密码校验

#在./conf/redis.conf里面添加如下配置
requirepass 密码
​
然后重启redis容器:docker-compose restart

三种客户端的连接方式

  1. redis-cli:在输入正常命令之前,先输入auth密码即可

  2. 图形化界面:在连接Redis的信息中添加上验证的密码

  3. Jedis客户端:

    第一种:jedis.auth(password);(不推荐)

    第二种:使用JedisPool的方式

public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password)

 

方式二:在不修改redis.conf文件的前提下,在第一次连接redis时,输入命令:Config set requirepass 密码,后续再次操作redis时,需要先AUTH做一次校验。(不推荐这种方式)重启之后密码就失效了。

 

5.2 Redis的事务

Redis的事务:一次事务,该成功的成功,该失败的失败。

先开启事务,执行一系列的命令,但是密码不会立即执行,会被放在一个队列中,如果你执行事务,那么这个队列中的命令全部执行,如果取消事务,一个队列中的命令全部作废。

  1. 开启事务:multi

  2. 输入要执行的命令,命令被放入到一个队列中

  3. 执行事务:exec

  4. 取消事务:discard

Redis的事务想发挥功能,需要配合watch监听机制

在开启事务之前,先通过watch命令监听一个或者多个key,在开启事务之后,如果有其他客户端修改了我监听的key,事务会自动取消。

如果执行了事务或者取消了事务,watch监听自动消除,一般不需要手动执行unwatch释放监听。

 

5.3 Redis持久化机制

RDB方式-默认

RDB是Redis默认的持久化机制

  1. RDB持久化文件,速度比较快,而且存储的是一个二进制的文件,传输起来很方便。

  2. RDB持久化的时机:

    save 900 1 #在900秒内,有1个key改变,就执行RDB持久化 save 300 10 #在300秒内,有10个key改变,就执行RDB持久化 save 60 10000 #在60秒内,有10000个key改变,就执行RDB持久化

  3. RDB无法保证数据的绝对安全

#RDB主要配置项
#持久化时机:在900秒内,有1个key改变,就执行RDB持久化
save 900 1
#持久化时机:在300秒内,有10个key改变,就执行RDB持久化
save 300 10
#持久化时机:在60秒内,有10000个key改变,就执行RDB持久化
save 60 10000
​
#开启RDB持久化的压缩
rdbcompression yes
#RDB持久化文件的名称
dbfilename dump.rdb

 

AOF方式

AOF持久化机制默认是关闭的,Redis官方推荐同时开启RDB和AOF持久化,更安全,避免数据丢失。在aof无法使用的时候,再用rdb的备份文件做替补恢复

  1. AOF持久化的速度相对RDB较慢,存储的是一个文本文件,时间久了文件会比较大,传输困难

  2. AOF持久化机制:

    #每执行一个写操作,立即持久化到AOF文件中,性能比较低

    appendfsync always

    #每秒执行一次持久化 appendfsync everysec #会根据你的操作系统不同,环境的不同,在一定时间执行一次持久化

    appendfsync no

  3. AOF相对RDB更安全,推荐同时开启AOF和RDB。

#AOF主要配置项
#代表开启AOF持久化
appendonly yes
#AOF文件的名称
appendfilename "redis.aof"
#AOF持久化执行的时机
#每执行一个写操作,立即持久化到AOF文件中,性能比较低
appendfsync always
#每秒执行一次持久化
appendfsync everysec
#会根据你的操作系统不同,环境的不同,在一定时间执行一次持久化
appendfsync no

同时开启RDB和AOF的注意事项:

如果同时开启了AOF和RDB持久化,那么Redis宕机重启之后,需要加载一个持久化文件,优先选择AOF文件。

如果先开启了RDB,然后之后开启AOF,如果RDB执行了持久化,那么RDB文件中的内容会被AOF覆盖掉。

 

5.4 Redis主从架构

单机版Redis存在读写瓶颈的问题

成神之路之Redis从头开始学习(二)

docker-compose.yml文件:

#指定本 yml 依从的 compose 哪个版本制定的
version: '3.1'
#定义服务
services:
#定义一个服务
  redis1:
    #指定镜像
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    #容器名称
    container_name: redis1
    #添加环境变量。指定时区
    environment:
      - TZ=Asia/Shanghai
    #添加端口映射
    ports:
      - 7001:6379
    #将主机当前目录的conf目录下的redis.conf挂载到容器里的/usr/local/redis.conf。
    volumes:
      - ./conf/redis1.conf:/usr/local/redis.conf
    #覆盖容器启动的默认命令。
    command: ["redis-server","/usr/local/redis.conf"]
  redis2:
    #指定镜像
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    #容器名称
    container_name: redis2
    #添加环境变量。指定时区
    environment:
      - TZ=Asia/Shanghai
    #添加端口映射
    ports:
      - 7002:6379
    #将主机当前目录的conf目录下的redis.conf挂载到容器里的/usr/local/redis.conf。
    volumes:
      - ./conf/redis2.conf:/usr/local/redis.conf
    #配置链接,redis1容器别名master
    links:
      - redis1:master
    #覆盖容器启动的默认命令。
    command: ["redis-server","/usr/local/redis.conf"]
  redis3:
    #指定镜像
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    #容器名称
    container_name: redis3
    #添加环境变量。指定时区
    environment:
      - TZ=Asia/Shanghai
    #添加端口映射
    ports:
      - 7003:6379
    #将主机当前目录的conf目录下的redis.conf挂载到容器里的/usr/local/redis.conf。
    volumes:
      - ./conf/redis3.conf:/usr/local/redis.conf
    links:
      - redis1:master
    #覆盖容器启动的默认命令。
    command: ["redis-server","/usr/local/redis.conf"]   

#redis2和redis3从节点配置 replicaof <masterip> <masterport>
replicaof master 6379

具体操作步骤

  1. 在/opt目录下面创建工作目录

    mkdir docker_redis_master_salve

  2. vi docker-compose.yml

    复制上面配置信息到yml

  3. 在docker_redis_master_salve下创建conf目录

  4. touch redis1.conf

  5. touch redis2.conf

  6. touch redis3.conf

  7. 向redis2.conf和redis3.conf中添加配置:replicaof master 6379

 

5.5 哨兵

哨兵可以帮助我们解决主从架构中的单点故障问题

成神之路之Redis从头开始学习(二)

修改docker-compose.yml,为了可以在容器内部使用哨兵的配置

#指定本 yml 依从的 compose 哪个版本制定的
version: '3.1'
#定义服务
services:
#定义一个服务
  redis1:
    #指定镜像
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    #容器名称
    container_name: redis1
    #添加环境变量。指定时区
    environment:
      - TZ=Asia/Shanghai
    #添加端口映射
    ports:
      - 7001:6379
    #将主机当前目录的conf目录下的redis.conf挂载到容器里的/usr/local/redis.conf。
    volumes:
      - ./conf/redis1.conf:/usr/local/redis.conf
      - ./conf/sentinel1.conf:/data/sentinel.conf  #添加的内容
    #覆盖容器启动的默认命令。
    command: ["redis-server","/usr/local/redis.conf"]
  redis2:
    #指定镜像
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    #容器名称
    container_name: redis2
    #添加环境变量。指定时区
    environment:
      - TZ=Asia/Shanghai
    #添加端口映射
    ports:
      - 7002:6379
    #将主机当前目录的conf目录下的redis.conf挂载到容器里的/usr/local/redis.conf。
    volumes:
      - ./conf/redis2.conf:/usr/local/redis.conf
      - ./conf/sentinel2.conf:/data/sentinel.conf  #添加的内容
    #配置链接,redis1容器别名master
    links:
      - redis1:master
    #覆盖容器启动的默认命令。
    command: ["redis-server","/usr/local/redis.conf"]
  redis3:
    #指定镜像
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    #容器名称
    container_name: redis3
    #添加环境变量。指定时区
    environment:
      - TZ=Asia/Shanghai
    #添加端口映射
    ports:
      - 7003:6379
    #将主机当前目录的conf目录下的redis.conf挂载到容器里的/usr/local/redis.conf。
    volumes:
      - ./conf/redis3.conf:/usr/local/redis.conf
      - ./conf/sentinel3.conf:/data/sentinel.conf  #添加的内容
    links:
      - redis1:master
    #覆盖容器启动的默认命令。
    command: ["redis-server","/usr/local/redis.conf"]

准备哨兵的配置文件,并且在容器内部手动启动哨兵即可

哨兵基本配置:

#哨兵需要后台启动
daemonize yes
#指定Master节点的ip和端口(主) 哨兵 监视 主节节点 主节点IP/名称 端口 2个从节点
sentinel monitor master localhost 6379 2
#指定Master节点的ip和端口(从) sentinel monitor mymaster 127.0.0.1 6379 2
sentinel monitor master master 6379 2
#哨兵每隔多久监听一次redis架构,默认为3秒,这里设置1秒好看效果
sentinel down-after-milliseconds master 10000

./conf/sentinel1.conf

#哨兵需要后台启动
daemonize yes
#指定Master节点的ip和端口(主) 哨兵 监视 主节节点 主节点IP/名称 端口 2个从节点
sentinel monitor master localhost 6379 2
#哨兵每隔多久监听一次redis架构,默认为3秒,这里设置1秒好看效果
sentinel down-after-milliseconds master 10000

./conf/sentinel2.conf

#哨兵需要后台启动
daemonize yes
#指定Master节点的ip和端口(从) sentinel monitor mymaster 127.0.0.1 6379 2
sentinel monitor master master 6379 2
#哨兵每隔多久监听一次redis架构,默认为3秒,这里设置1秒好看效果
sentinel down-after-milliseconds master 10000

./conf/sentinel3.conf

#哨兵需要后台启动
daemonize yes
#指定Master节点的ip和端口(从) sentinel monitor mymaster 127.0.0.1 6379 2
sentinel monitor master master 6379 2
#哨兵每隔多久监听一次redis架构,默认为3秒,这里设置1秒好看效果
sentinel down-after-milliseconds master 10000

修改docker-compose.yml和增加sentinel的配置文件之后重新构建容器。

docker-compose down
docker-compose up -d

在Redis容器内部启动sentinel即可,三个容器分别进入启动。

redis-sentinel sentinel.conf

启动成功之后,如果我们down掉redis1这个容器,集群会自动选举redis2或者redis3为Master.

 

5.6 Redis集群

Redis集群在保证主从加哨兵的基本功能之外,还能提升Redis存储数据的能力。

成神之路之Redis从头开始学习(二)

搭建集群

#docker-compose.yml
version: "3.1"
services:
  redis1:
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    container_name: redis1
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7001:7001
      - 17001:17001
    volumes:
      - ./conf/redis1.conf:/usr/local/redis/redis.conf
    command: ["redis-server","/usr/local/redis/redis.conf"]
  redis2:
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    container_name: redis2
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7002:7002
      - 17002:17002
    volumes:
      - ./conf/redis2.conf:/usr/local/redis/redis.conf
    command: ["redis-server","/usr/local/redis/redis.conf"]
  redis3:
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    container_name: redis3
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7003:7003
      - 17003:17003
    volumes:
      - ./conf/redis3.conf:/usr/local/redis/redis.conf
    command: ["redis-server","/usr/local/redis/redis.conf"]
  redis4:
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    container_name: redis4
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7004:7004
      - 17004:17004
    volumes:
      - ./conf/redis4.conf:/usr/local/redis/redis.conf
    command: ["redis-server","/usr/local/redis/redis.conf"]
  redis5:
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    container_name: redis5
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7005:7005
      - 17005:17005
    volumes:
      - ./conf/redis5.conf:/usr/local/redis/redis.conf
    command: ["redis-server","/usr/local/redis/redis.conf"]
  redis6:
    image: daocloud.io/library/redis:5.0.7
    #容器总是从新启动
    restart: always
    container_name: redis6
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7006:7006
      - 17006:17006
    volumes:
      - ./conf/redis6.conf:/usr/local/redis/redis.conf
    command: ["redis-server","/usr/local/redis/redis.conf"]

#redis.conf
# 指定redis的端口号
port 7001
#开启redis集群
cluster-enabled yes
# 集群信息的文件
cluster-config-file nodes-7001.conf
# 集群的对外ip地址
cluster-announce-ip 192.168.102.11
# 集群的对外端口号
cluster-announce-port 7001
#集群的总线端口号
cluster-announce-bus-port 17001

启动6个Redis的节点。

随便跳转到一个容器内部,使用redis-cli管理集群,他会自动分配好主从节点以及hash槽

redis-cli --cluster create 192.168.102.11:7001 192.168.102.11:7002 192.168.102.11:7003 192.168.102.11:7004 192.168.102.11:7005 192.168.102.11:7006 --cluster-replicas 1

测试

使用redis-cli -h 192.168.102.11 -p 7001 连接指定一个redis节点,此时set key可能设置不进去,因为通过计算key应该在另外的节点。如果需要在客户端连接,但是set数据能跳转到其他节点set,连接命令需要加-c,如下

redis-cli -h 192.168.102.11 -p 7001 -c

 

5.7 Java连接Redis集群

使用JedisCluster对象连接Redis集群

public class Demo5 {
​
    public void clusterTest(){
        //创建Set<HostAndPort>
        Set<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort("192.168.102.11",7001));
        nodes.add(new HostAndPort("192.168.102.11",7002));
        nodes.add(new HostAndPort("192.168.102.11",7003));
        nodes.add(new HostAndPort("192.168.102.11",7004));
        nodes.add(new HostAndPort("192.168.102.11",7005));
        nodes.add(new HostAndPort("192.168.102.11",7006));
        //创建jedisCluster集群对象
        JedisCluster jedisCluster = new JedisCluster(nodes);
​
        String value = jedisCluster.get("a");
        System.out.println(value);
    }
}

六 Redis常见问题

6.1 key的生存时间到了,Redis会立即删除吗?

不会立即删除

  1. 定期删除:

    Redis每隔一段时间就会去查看Redis设置了过期时间的key,会在大概100ms的间隔中默认查看3个key.

  2. 惰性删除

    当去查询一个已经过了生存时间的key时,Redis会先查看当前key的生存时间是否已经到了,直接删除当前key,并且给用户返回一个空值。

 

6.2 Redis的淘汰机制

在Redis内存已经满的时候,添加一个新的数据,就会执行淘汰策略。

  1. volatile-lru:在内存不足时,Redis会在设置了过期时间的key中淘汰掉一个最近最少使用的key

  2. allkeys-lru:在内存不足时,Redis会在全部的key中淘汰掉一个最近最少使用的key

  3. volatile-lfu:在内存不足时,Redis会在设置了过期时间的key中淘汰掉一个最近最少频次使用的key

  4. allkeys-lfu:在内存不足时,Redis会在全部的key中淘汰掉一个最近最少频次使用的key

  5. volatile-random:在内存不足时,Redis会在设置了过期时间的key中随机淘汰掉一个key

  6. allkeys-random:在内存不足时,Redis会在全部的key中随机淘汰掉一个key

  7. volatile-ttl:在内存不足时,Redis会在设置了过期时间的key中随机淘汰掉一个剩余生存时间最少的key

  8. noeviction:(默认):在内存不足时,直接报错

指定淘汰机制的方式:maxmemory-policy noeviction(具体策略)

设置Redis最大内存:maxmemory <bytes>

 

6.3 缓存的常见问题

缓存穿透

问题出现的原因:查询的数据,Redis中没有,数据库中也没有。如何解决?

  1. 根据Id查询时,如果id是自增的,将id的最大值放到Redis中,在查询数据库之前,直接比较一下id.

  2. 如果id不是整形的,可以将全部id放到set中,在用户查询之前,去set中查看一些是否有这个id.

  3. 获取客户端的ip地址,可以将ip的访问添加限制。

  4. 将访问的key直接在Redis中缓存一个空值,下次访问的时候可直接查redis放回空值

  5. 根据缓存数据Key的设计规则,将不符合规则的key采用布隆过滤器进行过滤

缓存击穿

问题出现的原因:缓存中的热点数据,突然到期了,造成大量的请求都去访问数据库,造成数据库宕机

  1. 在访问缓存中没有的时候,添加一个锁,让几个请求去访问数据库,避免数据库宕机

  2. 去掉热点数据的生存时间

缓存雪崩

问题出现的原因:当大量缓存同时到期时,最终大量的同时去访问数据库,导致数据库宕机

  1. 将缓存中的数据设置不同的生存时间,例如设置为30~60分钟的要给随机时间

缓存倾斜

问题出现的原因:热点数据放在一个Reids节点上,导致Redis节点无法承受住大量的请求,最终导致Redis宕机。

  1. 扩展主从架构,搭建多个从节点,缓解Redis的压力

  2. 可以在Tomcat中做JVM缓存,在查询Redis之前,先去查询Tomcat中的缓存。

 

好了,本次Redis学习就到这里了。相关的示例代码已上传码云,学习文档也已放百度云,仓库地址和文档地址可关注"良辰"公众号,回复"学无止境"或者"redis"获取

学无止境,关注我,我们一起进步。如果觉得文章还可以,点个赞,点个在看呗,谢谢~我们下期见。

成神之路之Redis从头开始学习(二)