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
- 建立maven專案
- 匯入需要的依賴
- 測試
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的事務:一次事務操作,該成功的成功,該失敗的失敗。
先開啟事務,執行一系列的命令,但是命令不會立即執行,會被放在一個佇列中,如果你執行事務,那麼這個佇列中的命令全部執行,如果取消了事務,一個佇列中的命令全部作廢。
- 開啟事務:multi
- 輸入要執行的命令 -> 放到一個佇列中
- 執行事務:exec
- 取消事務:discard
Redis的事務向發揮功能,需要配置watch監聽機制
在開啟事務之前,先通過watch命令去監聽一個或多個key,在開啟事務之後,如果有其他客戶端修改了我監聽的key,事務會自動取消。
如果執行了事務,或者取消了事務,watch監聽自動消除,一般不需要去手動執行unwatch。
5.3 Redis持久化機制
RDB是Redis預設的持久化機制
RDB是持久化檔案,速度比較快,而且儲存的是一個二進位制的檔案,傳輸起來很方便。
RDB持久化的時機:
save 900 1:在900秒內,有1個key改變了,就執行RDB持久化。
save 300 10:在300秒內,有10個key改變了,就執行RDB持久化。
save 60 10000:在6秒內,有10000個key改變了,就執行RDB持久化。RDB無法保證資料的絕對安全。
# 開啟RDB持久化的壓縮
rdbcompression yes
# RDB持久化檔案的名稱
dbfilename redis.rdb
AOF持久化機制預設是關閉的,Redis官方推薦同時開啟RDB和AOF持久化,更安全,避免資料丟失。
AOF持久化的速度,相對RDB是較慢的,儲存的是一個文字檔案,到了後期檔案會比較大,傳輸困難。
AOF的持久化時機。
appendfsync always:每執行一個寫操作,立即持久化到AOF檔案中,效能比較低。
appendfsync everysec:每秒執行一次持久化。
appendfsync no:會根據你的作業系統不同,環境的不同,在一定時間內執行一次持久化。
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儲存的能力
- Redis叢集是無中心的。
- Redis叢集有一個ping-pang機制。
- 投票機制,Redis叢集節點的數量必須是2n+1。
- Redis叢集中預設分配了16384個hash槽,在儲存資料時,就會將key進行crc16的演算法,並且對16384取餘,根據最終的結果,將key-value存放到執行Redis節點中,而且每一個Redis叢集都在維護著相應的hash槽。
- 為了保證資料的安全性,每一個叢集的節點,至少要跟著一個從節點。
- 單獨的針對Redis叢集中的某一個節點搭建主從。
- 當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會立即刪除嗎?
不會立即刪除。
定期刪除:
Redis每隔一段時間就會去檢視Redis設定了過期時間的key。會在100ms的間隔中預設檢視3個key。
惰性刪除:
如果當你去查詢一個已經過了生存時間的key時,Redis會檢視當前key的生存時間,是否已經到了,直接刪除當前key,並且給使用者返回一個空值。
6.2 Redis的淘汰機制
在Redis記憶體已經滿的時候,添加了一個新的資料,執行淘汰機制。
volatile-lru:
在記憶體不足時,Redis會在已經設定過了生存時間的key中幹掉一個最近最少使用的key。
allkeys-lru:
在記憶體不足時,Redis會在全部的key中幹掉一個最近最少使用的key。
volatile-lfu:
在記憶體不足時,Redis會在已經設定過了生存時間的key中幹掉一個最近最少頻次使用的key。
allkeys-lfu:
在記憶體不足時,Redis會在全部的key中幹掉一個最近最少頻次使用的key。
volatile-random:
在記憶體不足時,Redis會在已經設定過了生存時間的key中隨機幹掉一個。
allkeys-random:
在記憶體不足時,Redis會在全部的key中隨機幹掉一個。
volatile-ttl:
在記憶體不足時,Redis會在已經設定過了生存時間的key中幹掉一個剩餘生存時間最少的key。
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。
volatile-random:
在記憶體不足時,Redis會在已經設定過了生存時間的key中隨機幹掉一個。
allkeys-random:
在記憶體不足時,Redis會在全部的key中隨機幹掉一個。
volatile-ttl:
在記憶體不足時,Redis會在已經設定過了生存時間的key中幹掉一個剩餘生存時間最少的key。
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中的快取。