1. 程式人生 > 實用技巧 >Redis入門教程筆記

Redis入門教程筆記

最近學習了某站上老師講的Redis入門課程,老師講的很基礎,從最初的Redis安裝到搭建叢集,到最後的問題講解。適合剛剛接觸Redis和想要複習Redis的初學者,在這裡和老師的筆記做了個同步文件,希望可以對大家有幫助。
教程來源:https://www.bilibili.com/video/BV1FZ4y1u7ny


因為這裡沒有用docker,所以5.1章節抽取本站教程轉載。

一、Redis介紹

1.1 引言

1.由於使用者量增大,請求數量也隨之增大,資料壓力過大。

例:資料庫根據SQL語句去磁碟通過io來拿到資料,資料壓力就會比較大,輕則查詢效率降低,重則伺服器宕機。

解決:針對熱點資料新增快取,把資料放到Redis,查詢都找Redis。

原理:Redis是基於記憶體儲存資料和讀取資料的,並且支援併發量很大。

2.多臺伺服器之間,資料不同步。

例:客戶端傳送請求,說不定請求會發到哪臺伺服器中,比如客戶在登入中,在伺服器1存放了客戶的唯一標識,下一次如果請求傳送到伺服器2,就沒有標識了。

解決:不用Session來存放使用者資料,用Redis統一存放。

原理:Redis是獨立於Tomcat伺服器之外的單獨中介軟體,可以將之前儲存在Session中的共享資料統一的存放在Redis中,伺服器1和伺服器2都找Redis。

3.多臺伺服器之間的鎖,已經不存在互斥性了。

例:在伺服器1使用鎖操作,和在伺服器2使用鎖操作,兩把鎖不存在互斥性,會導致鎖失效。

解決:使用Redis

原理:Redis基於它接收使用者的請求是單執行緒的,可以幫我們實現類似鎖的功能。

1.2 NoSQL

Redis就是一款NoSQL

NoSQL -> 菲關係型資料庫 -> Not Only SQL

除了關係型資料庫都是非關係型資料庫。

NoSQL只是一種概念,泛指非關係型資料庫,和關係型資料庫做一個區分。

1.3 Redis介紹

Redis(Remote Dictionary Server)遠端字典服務,由C語言去編寫,所以不需要java環境。

二、Redis安裝

2.1 下載中文版Redis視覺化軟體

RedisDesktopManager

2.2 為Redis賦值

2.3 在Redis中檢視

三、Redis常用命令

官網Redis命令參考文件:redisdoc.com

3.1 Redis儲存資料的結構

常用的五種資料結構

  • key-string:一個key對應一個值

  • key-hash:一個key對應一個Map

  • key-list:一個key對應一個列表

  • key-set:一個key對應一個集合

  • key-zset:一個key對應一個有序的集合

    另外三種資料結構。

    HyperLogLog:計算近似值的。

    GEO:儲存地理位置(經緯度)

    BIT:一般儲存的也是一個字串,儲存的是一個byte[]

key-string:最常用的,一般用於儲存一個值

key-hash:儲存一個物件資料的

key-list:使用list結構實現棧和佇列結構

key-set:交集,差集和並集的操作

key-zest:排行榜,積分儲存等操作。

3.2 String常用命令

#1.	新增值
set key value

#2.	取值
get key

#3.	批量操作
mset key value [key value...]
mget key [key...]

#4.	自增命令(自增1)(應用場景 -> 點贊)
incr key

#5.	自減命令(自減1)
decr key

#6.	自增或自減指定數量
incrby key <increment>
decrby key <increment>

#7.	設定值的同時。指定生存時間(每次向Redis中新增資料時,儘量都設定上生存時間)
setex key <second> value

#8.	設定值,如果當前key不存在的話(如果這個key存在,什麼事都不做,如果這個key不存在,和set命令一樣)
setnx key value

#9. 在key對應的value後,追加內容
append key value

#10. 檢視value字串的長度
strlen key

3.3 hash常用命令

#1.	儲存資料
hset key field value

#2.	獲取資料
hget key field

#3.	批量操作
hmset key field value [field value ...]
hmget key field [field ...]


#4.	自增(指定自增的值)
hincrby key field increment

#5.	設定值(如果key-field不存在,那麼就正常新增,如果存在,什麼事都不做)
hsetnx key field value

#6.	檢查field是否存在
hexists key field

#7.	刪除key對應的某一個field,可以刪除多個
hdel key field [field]

#8.	獲取當前hash結構中的全部field和value
hgetall key

#9.	獲取當前hash結構中的全部field
hkeys key

#10. 獲取當前hash結構中的全部value
hvals key

#11. 獲取當前hash結構中field的數量
hlen key

3.4 list常用命令

#1.	儲存資料(從左側插入資料,從右側插入資料)
lpush key value [value ...]
rpush key value [value ...]

#2.	儲存資料(如果key不存在,什麼事都不做,如果key存在,但是不是list結構,什麼都不做)
lpushx key value
rpushx key value

#3.	修改資料(在儲存資料時,指定好你的索引位置,覆蓋之前索引位置的資料,index超出整個列表的長度,也會失敗)
lset key index value

#4.	彈棧方式獲取資料(左側彈出資料,從右側彈出資料)
lpop key
rpop key

#5.	獲取指定索引範圍的資料(start從0開始,stop輸入-1代表最後一個)
lrange key start stop

#6.	獲取指定索引位置的資料
lindex kek index

#7.	獲取整個列表的長度
llen key

#8.	刪除列表中的資料(刪除當前列表中的count個value值;count>0,從左側向右側刪除;count<0,從右側向左側刪除;count==0,刪除列表中全部資料)
lrem key count value

#9.	保留列表中的資料(保留指定索引範圍內的資料,超過整個索引範圍被移除掉)
ltrim key start stop

#10. 將一個列表中最後的一個數據,插入到另外一個列表的頭部位置
rpoplpush list1 list2

3.5 set常用命令

#1.	儲存資料
sadd key member [member ...]

#2.	獲取資料(獲取全部資料)
smembers key

#3.	隨機獲取一個數據(獲取的同時,移除資料,count預設為1,代表彈出資料的數量)
spop key [count]

#4. 交集(取多個set集合交集)
sinter set1 set2 ...

#5. 並集(獲取全部集合中的資料)
sunion set1 set2 ...

#6.	差集(獲取多個集合中不一樣的資料)
sdiff set1 set2 ... (獲取set1-set2)
sdiff set2 set1 ... (獲取set2-set1)

#7.	刪除資料
srem key member [member ...]

#8.	檢視當前的set集合中是否包含這個值
sismember key member

3.6 zset常用命令

#1.	新增資料(score必須是一個數值,member不允許重複)
zadd key score member [socre member ...]

#2. 修改member的分數(如果member是存在於key中的,正常增加分數,如果member不存在,這個命令就相當於zadd)
zincrby key increment member

#3.	檢視指定的member的分數
zscore key member

#4.	獲取zset中資料的數量
zcard key

#5.	根據score的範圍查詢member數量
zcount key min max

#6.	刪除zset中的成員
zrem key member [member ...]

#7.	根據分數從小到大排序,獲取指定範圍內的資料(withscore如果新增這個引數,那麼會返回member對應的分數)
zrange key start stop [withscores]

#8.	根據分數從大到小排序,獲取指定範圍內的資料
zrevrange key start stop [withscores]

#9.	根據分數的返回去獲取member(withscores代表返回score,新增limit,就和MySQL一樣,如果不希望等於min或者max的值被查詢出來可以採用‘(分數’相當於 < 但是不等於的方式,最大值和最小值使用+inf和-inf來表示)
zrangebyscore key min max [withscores] [limit offset count]

#10.	根據分數的返回去獲取member(withscores代表返回score,新增limit,就和MySQL一個樣)
zrangebyscore key max min [withscores] [limit offset count]

3.7 key常用命令

#1.	檢視Redis中的全部的key(pattern: *, xxx*, *xxx)
keys pattern

#2.	檢視某一個key是否存在(1 - key存在,0 - key不存在)
exists key

#3.	刪除key
del key [key ...]

#4.	設定key的生存時間,單位為秒,單位為毫秒,設定還能活多久
expire key second
pexpire key milliseconds

#5.	設定key的生存時間,單位為秒,單位為毫秒,設定能活到什麼時間點
expireat key timestamp
pexpireat key milliseconds

#6. 檢視key的剩餘生存時間,單位為秒,單位為毫秒(-2 - 當前key不存在,-1 - 當前key沒有設定生存時間,具體剩餘的生存時間)
ttl key
pttl key

#7. 移除key的生存時間(1 - 移除成功,0 - key不存在生存時間,key不存在)
persist key 

#8.	選擇操作的庫
select 0~15

#9.	移動key到另外一個庫中
move key db

3.8 庫的常用命令

#1. 清空當前所在的資料庫
flushdb

#2.	清空全部資料庫
flushall

#3.	檢視當前資料庫中有多少個key
dbsize

#4.	檢視最後一次操作的時間
lastsave

#5.	實時監控redis服務接收到的目錄
monitor

四、Java連線Redis

Jedis連線Redis,Lettuce連線Redis

4.1 Jedis連線Redis

  1. 建立maven專案
  2. 匯入需要的依賴
  3. 測試
public class JedisTest {

    @Test
    public void set(){
        //1. 連線Redis
        Jedis jedis=new Jedis("192.168.200.130",6379);

        //2. 操作Redis - 因為Redis的命令是什麼,Jedis的方法就是什麼
        jedis.set("name","王五");

        //3. 釋放資源
        jedis.close();
    }

    @Test
    public void get(){
        //1. 連線Redis
        Jedis jedis=new Jedis("192.168.200.130",6379);

        //2. 操作Redis - 因為Redis的命令是什麼,Jedis的方法就是什麼
        String value=jedis.get("name");
        System.out.println(value);

        //3. 釋放資源
        jedis.close();
    }

}

4.2 Jedis如何儲存一個物件到Redis以Byte[]的形式

準備一個User實體類

public class User implements Serializable {
    
    // serialVersionUID
    // NoArgsConstructor
    // AllArgsConstructor
    
    private Integer id;
    private String name;
    private Date birthday;
    
    // get set...
        
    // toString ...

}

​ 匯入spring-context依賴

建立Demo類,編寫測試內容

public class JedisTest2 {

    // 儲存物件 - 以byte[]形式儲存在Redis中
    @Test
    public void setByteArray(){
        //1. 連線Redis
        Jedis jedis=new Jedis("192.168.200.130",6379);

        //-------------------------------
        //2.1 準備key(String)-value(User)
        String key="user";
        User value=new User(10,"李四",new Date());
        //2.2 將key和value轉換為byte[]
        byte[] byteKey = SerializationUtils.serialize(key);
        byte[] byteValue = SerializationUtils.serialize(value);
        //2.3 將key和value儲存到Redis
        jedis.set(byteKey,byteValue);
        //-------------------------------

        //3. 釋放資源
        jedis.close();
    }

    // 獲取物件 - 以byte[]形式在Redis中獲取
    @Test
    public void getByteArray(){
        //1. 連線Redis
        Jedis jedis=new Jedis("192.168.200.130",6379);

        //-------------------------------
        //2.1 準備key
        String key="user";
        //2.2 將key轉換為byte[]
        byte[] byteKey = SerializationUtils.serialize(key);
        //2.3 jedis去Redis中獲取value
        byte[] value = jedis.get(byteKey);
        //2.4 將value反序列化為User物件
        User user = (User) SerializationUtils.deserialize(value);
        //2.5 輸出
        System.out.println(user.toString());
        //-------------------------------

        //3. 釋放資源
        jedis.close();
    }

}

4.3 Jedis如何儲存一個物件到Redis以String的形式

public class JedisTest3 {

    // 儲存物件 - 以String形式儲存
    @Test
    public void setString(){
        //1. 連線Redis
        Jedis jedis=new Jedis("192.168.200.130",6379);

        //2.1 準備key(String)-value(User)
        String stringKey="stringUser";
        User value=new User(2,"李四",new Date());
        //2.2 使用fastJSON將value轉化為json字串
        String stringValue = JSON.toJSONString(value);
        //2.3 儲存到redis中
        jedis.set(stringKey,stringValue);

        //3. 釋放資源
        jedis.close();

    }

    // 獲取物件 - 以String形式獲取
    @Test
    public void getString(){
        //1. 連線Redis
        Jedis jedis=new Jedis("192.168.200.130",6379);

        //2.1 準備一個key
        String key="stringUser";
        //2.2 去Redis中查詢value
        String value = jedis.get(key);
        //2.3 儲存到redis中
        User user = JSON.parseObject(value, User.class);
        //2.4 輸出
        System.out.println(user.toString());

        //3. 釋放資源
        jedis.close();

    }
}

4.4 Jedis的連線池操作

@Test
public void pool2(){
    
    //1. 建立連線池的配置資訊
    GenericObjectPoolConfig poolConfig=new GenericObjectPoolConfig();
    poolConfig.setMaxTotal(100); // 連線池中最大活躍數
    poolConfig.setMaxIdle(10); // 最大空閒數
    poolConfig.setMinIdle(5); // 最小空閒數
    poolConfig.setMaxWaitMillis(3000); // 當連線池空了,多久沒獲取到jedis物件就超時

    //2. 建立連線池
    JedisPool pool=new JedisPool(poolConfig,"192.168.200.130",6379);

    //3. 通過連線池獲取Jedis物件
    Jedis jedis = pool.getResource();

    //4. 操作
    String value=jedis.get("stringUser");
    System.out.println(value);

    //5. 釋放資源
    jedis.close();
}

4.5 Redis的管道操作

因為在操作Redis的時候,執行一個命令需要先發送請求到Redis伺服器,這個過程需要經歷網路的延遲,Rdis還需要給客戶端一個響應。

如果我需要一次性執行很多個命令,上述的方式效率很低,可以通過Redis的管道,先將命令放到客戶端的一個Pipeline中,之後一次性的將全部命令都發送Redis服務,Redis服務一次性的將全部的返回結果響應給客戶端。

(提高Redis併發能力,處理請求的效率更高)

// Redis管道的操作
@Test
public void pipeline(){
    //1. 建立連線池
    JedisPool pool=new JedisPool("192.168.200.130",6379);
    long l = System.currentTimeMillis();

    //2. 獲取一個連線物件
    Jedis jedis = pool.getResource();

    //3. 執行incr - 10000次
    for(int i=0;i<10000;i++){
        jedis.incr("qq");
    }

    //4. 釋放資源
    jedis.close();

    // =================================

    //2. 獲取一個連線物件
    long l1 = System.currentTimeMillis();
    Jedis jedis1=pool.getResource();
    //3. 建立管道
    Pipeline pipelined = jedis1.pipelined();
    //4. 執行incr - 10000次放到管道中
    for(int i=0;i<10000;i++){
        jedis.incr("pp");
    }
    //5. 執行命令
    pipelined.syncAndReturnAll();
    //6. 釋放資源
    jedis1.close();
    
    System.out.println(System.currentTimeMillis()-l);
    System.out.println(System.currentTimeMillis()-l1);
}

五、Redis其它配置及叢集

5.1 Redis的AUTH

Redis預設配置是不需要密碼認證的,也就是說只要連線的Redis伺服器的host和port正確,就可以連線使用。這在安全性上會有一定的問題,所以需要啟用Redis的認證密碼,增加Redis伺服器的安全性。

1. 修改配置檔案

Redis的配置檔案預設在/etc/redis.conf,找到如下行:

#requirepass foobared

去掉前面的註釋,並修改為所需要的密碼:

requirepass myPassword (其中myPassword就是要設定的密碼)

2. 重啟Redis

如果Redis已經配置為service服務,可以通過以下方式重啟:

service redis restart

如果Redis沒有配置為service服務,可以通過以下方式重啟:

/usr/local/bin/redis-cli shutdown
/usr/local/bin/redis-server /etc/redis.conf

3. 登入驗證

設定Redis認證密碼後,客戶端登入時需要使用-a引數輸入認證密碼,不新增該引數雖然也可以登入成功,但是沒有任何操作許可權。如下:

$ ./redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.

使用密碼認證登入,並驗證操作許可權:

$ ./redis-cli -h 127.0.0.1 -p 6379 -a myPassword
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "myPassword"

看到類似上面的輸出,說明Reids密碼認證配置成功。

除了按上面的方式在登入時,使用-a引數輸入登入密碼外。也可以不指定,在連線後進行驗證:

$ ./redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> auth myPassword
OK
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "myPassword"
127.0.0.1:6379> 

4. 在命令列客戶端配置密碼(redis重啟前有效)

前面介紹了通過redis.conf配置密碼,這種配置方式需要重新啟動Redis。也可以通命令列客戶端配置密碼,這種配置方式不用重新啟動Redis。配置方式如下:

127.0.0.1:6379> config set requirepass newPassword
OK
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "newPassword"

注意使用命令列客戶端配置密碼,重啟Redis後仍然會使用redis.conf配置檔案中的密碼。

5. 在Redis叢集中使用認證密碼

如果Redis伺服器,使用了叢集。除了在master中配置密碼外,也需要在slave中進行相應配置。在slave的配置檔案中找到如下行,去掉註釋並修改與master相同的密碼即可:

# masterauth master-password

6. Jedis客戶端中使用auth

//連線Redis
    Jedis jedis=new Jedis("192.168.200.130",6379);
    jedis.auth("123");
//建立連線池(3000:超時時間;123:auth密碼)
	JedisPool pool=new JedisPool(poolConfig,"192.168.200.130",6379,3000,"123");

5.2 Redis的事務

Redis的事務:一次事務操作,該成功的成功,該失敗的失敗。

先開啟事務,執行一系列的命令,但是命令不會立即執行,會被放在一個佇列中,如果你執行事務,那麼這個佇列中的命令全部執行,如果取消了事務,一個佇列中的命令全部作廢。

  1. 開啟事務:multi
  2. 輸入要執行的命令 -> 放到一個佇列中
  3. 執行事務:exec
  4. 取消事務:discard

Redis的事務向發揮功能,需要配置watch監聽機制

在開啟事務之前,先通過watch命令去監聽一個或多個key,在開啟事務之後,如果有其他客戶端修改了我監聽的key,事務會自動取消。

如果執行了事務,或者取消了事務,watch監聽自動消除,一般不需要去手動執行unwatch。

5.3 Redis持久化機制

RDB是Redis預設的持久化機制

  1. RDB是持久化檔案,速度比較快,而且儲存的是一個二進位制的檔案,傳輸起來很方便。

  2. RDB持久化的時機:

    save 900 1:在900秒內,有1個key改變了,就執行RDB持久化。
    save 300 10:在300秒內,有10個key改變了,就執行RDB持久化。
    save 60 10000:在6秒內,有10000個key改變了,就執行RDB持久化。

  3. RDB無法保證資料的絕對安全。

# 開啟RDB持久化的壓縮
rdbcompression yes
# RDB持久化檔案的名稱
dbfilename redis.rdb

​ AOF持久化機制預設是關閉的,Redis官方推薦同時開啟RDB和AOF持久化,更安全,避免資料丟失。

  1. AOF持久化的速度,相對RDB是較慢的,儲存的是一個文字檔案,到了後期檔案會比較大,傳輸困難。

  2. AOF的持久化時機。

    appendfsync always:每執行一個寫操作,立即持久化到AOF檔案中,效能比較低。

    appendfsync everysec:每秒執行一次持久化。

    appendfsync no:會根據你的作業系統不同,環境的不同,在一定時間內執行一次持久化。

  3. AOF相對RDB更安全,推薦同時開啟AOF和RDB。

# 代表開啟AOF持久化
appendonly yes
# AOF檔案的名稱
appendfilename "redis.aof"

同時開啟RDB和AOF的注意項:

如果同時開啟了AOF和RDB持久化,那麼Redis宕機重啟之後,需要載入一個持久化檔案,優先選擇AOF檔案。

如果先開啟了RDB,再次開啟AOF,如果RDB執行了持久化,那麼RDB檔案中的內容會被AOF覆蓋掉。

5.4 Redis的主從架構

單機版Redis存在讀寫瓶頸的問題

5.5 哨兵

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

準備哨兵的配置檔案,並且在容器內部手動啟動哨兵即可

# 哨兵需要後臺啟動
daemonize no
# 指定Master 節點的ip的埠(主)
sentinel monitor master localhost 6379 2
# 指定Master 節點的ip的埠(主)
sentinel monitor master master 6379 2
# 哨兵每隔多久監聽一次redis架構
sentinel down-after-milliseconds master 10000

在Redis容器內部啟動sentinel即可

5.6 Redis的叢集

Redis叢集在保證主從加哨兵的基本功能之外,還能夠提升Redis儲存的能力

  1. Redis叢集是無中心的。
  2. Redis叢集有一個ping-pang機制。
  3. 投票機制,Redis叢集節點的數量必須是2n+1。
  4. Redis叢集中預設分配了16384個hash槽,在儲存資料時,就會將key進行crc16的演算法,並且對16384取餘,根據最終的結果,將key-value存放到執行Redis節點中,而且每一個Redis叢集都在維護著相應的hash槽。
  5. 為了保證資料的安全性,每一個叢集的節點,至少要跟著一個從節點。
  6. 單獨的針對Redis叢集中的某一個節點搭建主從。
  7. 當Redis叢集中,超過半數的節點宕機之後,Redis叢集就癱瘓了。
# redis.conf
# 指定redis的埠號
port 7001
# 開啟Redis叢集
cluster-enabled yes
# 叢集資訊的檔案
cluster-config-file nodes-7001.conf
# 叢集的對外ip地址
cluster-announce-ip 192.168.200.130 
# 叢集的對外port
cluster-announce-port 7001
# 叢集的匯流排埠
cluster-announce-bus-port 17001

啟動了6個Redis的節點

隨便跳轉到一個容器內部,使用redis-cli管理叢集

六、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中隨機幹掉一個。

  6. allkeys-random:

    在記憶體不足時,Redis會在全部的key中隨機幹掉一個。

  7. volatile-ttl:

    在記憶體不足時,Redis會在已經設定過了生存時間的key中幹掉一個剩餘生存時間最少的key。

  8. noeviction:(預設)

    在記憶體不足時,直接報錯

指定淘汰機制的方式:maxmemory-policy noeviction

設定Redis的最大記憶體:maxmemory

6.3 快取的常見問題

快取穿透:

問題出現的原因:查詢的資料,Redis中沒有,資料庫也沒有。
1:根據id查詢時,如果id是自增的,將id的最大值放到Redis中,在查詢資料庫之前,直接比較一下id。

2:如果id不是整型,可以將全部的id放到set中,在使用者查詢之前,去set中檢視一下是否有一個id。

3:獲取客戶端的ip地址,可以將ip的訪問新增限制。

快取擊穿

問題:快取中的熱點資料,突然到期了,造成了大量的請求都去訪問資料庫,造成資料庫宕機。

1.在訪問快取中沒有的時候,直接新增一個鎖,讓幾個請求去訪問資料庫,避免資料庫宕機。

2.熱點資料的生存時間去掉。

快取雪崩

問題:當大量快取同時到期時,最終大量的請求同時去訪問資料庫,導致資料庫宕機。

將快取中的資料的生存時間,設定為30~60分鐘的一個隨機時間。

快取傾斜

問題:熱點資料放在了一個Redis節點上,導致Redis節點無法承受住大量的請求,最終Redis宕機。

1.擴充套件主從架構,搭建大量的從節點,緩解Redis的壓力。

2.可以在Tomcat中JVM快取,在檢視Redis之前,先去查詢Tomcat中的快取。

在記憶體不足時,Redis會在全部的key中幹掉一個最近最少頻次使用的key。

  1. volatile-random:

    在記憶體不足時,Redis會在已經設定過了生存時間的key中隨機幹掉一個。

  2. allkeys-random:

    在記憶體不足時,Redis會在全部的key中隨機幹掉一個。

  3. volatile-ttl:

    在記憶體不足時,Redis會在已經設定過了生存時間的key中幹掉一個剩餘生存時間最少的key。

  4. noeviction:(預設)

    在記憶體不足時,直接報錯

指定淘汰機制的方式:maxmemory-policy noeviction

設定Redis的最大記憶體:maxmemory

6.3 快取的常見問題

快取穿透:

問題出現的原因:查詢的資料,Redis中沒有,資料庫也沒有。
1:根據id查詢時,如果id是自增的,將id的最大值放到Redis中,在查詢資料庫之前,直接比較一下id。

2:如果id不是整型,可以將全部的id放到set中,在使用者查詢之前,去set中檢視一下是否有一個id。

3:獲取客戶端的ip地址,可以將ip的訪問新增限制。

快取擊穿

問題:快取中的熱點資料,突然到期了,造成了大量的請求都去訪問資料庫,造成資料庫宕機。

1.在訪問快取中沒有的時候,直接新增一個鎖,讓幾個請求去訪問資料庫,避免資料庫宕機。

2.熱點資料的生存時間去掉。

快取雪崩

問題:當大量快取同時到期時,最終大量的請求同時去訪問資料庫,導致資料庫宕機。

將快取中的資料的生存時間,設定為30~60分鐘的一個隨機時間。

快取傾斜

問題:熱點資料放在了一個Redis節點上,導致Redis節點無法承受住大量的請求,最終Redis宕機。

1.擴充套件主從架構,搭建大量的從節點,緩解Redis的壓力。

2.可以在Tomcat中JVM快取,在檢視Redis之前,先去查詢Tomcat中的快取。