成神之路之Redis從頭開始學習(二)

四 Java連接Redis

Jedis連接Redis,Lettuce連接Redis

4.1 Jedis連接Redis

1、創建maven項目

image-20201021082340924

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存在讀寫瓶頸的問題

image-20201024165216365

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 哨兵

哨兵可以幫助我們解決主從架構中的單點故障問題

image-20201024215538511

修改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存儲數據的能力。

image-20201025090045480

搭建集羣

#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"獲取

學無止境,關注我,我們一起進步。如果覺得文章還可以,點個贊,點個在看唄,謝謝~我們下期見。

img

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章