認識Redis

生命是一团火發表於2024-06-18

認識Redis

Redis是目前最受歡迎的NoSQL資料庫之一;db-engines排名上,所有資料庫型別排名第六,鍵值對資料庫排名第一。

Redis是用C語言編寫的開源、支援多種資料結構、支援網路、基於記憶體、可選永續性的鍵值對記憶體型資料庫,具備以下特徵:

  • 基於記憶體執行、效率高
  • 單執行緒執行
  • 支援分散式
  • key-value的儲存結構
  • 開源,基於C語言編寫,遵守BSD協議,提供多種語言API

相比於其他資料庫,Redis是C/S通訊模型,單程序單執行緒模型,操作具有原子性,支援持久化,支援Lua指令碼

image-20240607102956273

image-20240607103029784

Redis應用場景

Redis的應用場景主要包括:快取系統(“熱點”資料:高頻讀、低頻寫)、計數器、排行榜、訊息佇列、社交網路和實時系統、分散式鎖、限流等。這裡不進行詳細描述,後續隨實際應用說明。

Redis的資料型別

Redis提供的資料型別包括:字串、雜湊、列表、集合、有序集合、自定義型別等,也包括點陣圖、GEO(3.2+)、Stream(5.0+)等

通用指令

通用指令是指不分資料型別,都可以使用的命令,常見的有

  • keys:檢視符合模板的所有key,遍歷所有的鍵,時間複雜度為O(n),不建議在生產環境使用
  • dbsize:直接獲取redis內建的鍵總數遍歷
  • del:刪除一個key,返回刪除成功key的個數
  • type:獲取鍵的資料結構型別;鍵不存在返回none
  • exists:檢視一個key是否存在
  • expire:給一個key設定有效期,到期後key自動刪除;過期時間單位是s
  • ttl:檢視一個key的剩餘有效期;-1代表永不過期,-2代表不存在key,其餘表示剩餘有效期

一、String型別

String是最基本的key-value結構,key是唯一標識,value是二進位制安全的字串,不僅可以儲存字串,也可以是數字(整數或浮點數)或者圖片影片等多種形式,最大長度支援512M。

1.1 常用指令

127.0.0.1:6379> set name zhangsan	# 最基本的string型別設定,設定成功返回OK
OK
127.0.0.1:6379> get name	# 獲取name的值,若name不存在,返回nil
"zhangsan"
127.0.0.1:6379> exists name		# 監測一個key是否存在,存在返回1,不存在返回0
(integer) 1
127.0.0.1:6379> strlen name		# 獲取name的value字元長度;中文字元佔3位
(integer) 8
127.0.0.1:6379> del name	# 刪除一個key
(integer) 1
127.0.0.1:6379> mset key1 value1 key2 value2	# 批次設定鍵值對
OK
127.0.0.1:6379> mget key1 key2	# 批次獲取鍵值對
1) "value1"
2) "value2"
127.0.0.1:6379> set number 0	# 設定數字型別
OK
127.0.0.1:6379> incr number		# 將number的值自增1,返回自增後的值
(integer) 1
127.0.0.1:6379> incrby number 10	# 將number的值自增指定數值,返回自增後的值
(integer) 11
127.0.0.1:6379> decrby number 10	# 將number的值自減指定數值,返回自減後的值
(integer) 1
127.0.0.1:6379> decr number		# 將number的值自減1,返回自減後的值
(integer) 0
127.0.0.1:6379> get number
"0"
127.0.0.1:6379> expire number 60	# 設定key的過期時間,單位是s;針對已經存在的key
(integer) 1
127.0.0.1:6379> ttl number		# 檢視key還有多久過期
(integer) 56
127.0.0.1:6379> ttl number
(integer) 55
127.0.0.1:6379> set key name EX 60		# 設定key-value型別的值,並設定該key的過期時間
OK
127.0.0.1:6379> ttl name		# ttl監測一個不存在的key,返回-2
(integer) -2
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> setnx name2 zhangsan2	# 不存在就插入
(integer) 1

1.2 應用場景

1.2.1、快取物件

使用String來快取物件可以有兩種方式;

第一種,直接快取整個物件的JSON字串,例子:set user:1 '{"name":"張三", "age":18}'

第二種,將key分離成 user: id : 屬性 的形式,採用mset來儲存,mget來獲取屬性值,例子:mset user:1:name 張三 mset user:1:age 19

1.2.2、常規計數

因為Redis處理命令是單執行緒執行的,執行命令的過程是原子性的。所以String型別適合計數場景,比如點贊、轉發、庫存數等

127.0.0.1:6379> set article:readcount:1001 0
OK
127.0.0.1:6379> incr article:readcount:1001
(integer) 1

1.2.3、分散式鎖

set命令有個NX引數可以實現 “key不存在就插入” 的效果,可以用它實現分散式鎖(最簡單的,不建議使用,僅供瞭解)

set lock_key unique_value NX PX 10000

解鎖的過程就是將lock_key刪除,要保證操作的客戶端就是加鎖的客戶端。在解鎖的時候,先要判斷unique_vale是否為加鎖客戶端,如果是,則將lock_key刪除。

1.2.4、共享Session資訊

在管理或者登入系統時,常用Session儲存使用者的會話狀態,這些Session會被儲存在伺服器端,但這隻適合單系統應用,對於分散式應用系統,則需要Redis的保駕護航;所有的後端伺服器連線Redis,從Redis中獲取Session資訊,這樣可以避免使用者請求被分配到不同伺服器導致的會話丟失問題。

二、List型別

列表是一個插入順序排序(有序)的字串元素集合,可以從頭部或者尾部插入元素,列表的最大長度為2^32-1;

列表底層是由雙向連結串列或壓縮連結串列實現:如果列表中元素個數小於512(list-max-ziplist-entries)同時列表中每個元素的值都小於64(list-max-ziplist-value)位元組,Redis使用ziplist作為List型別的底層資料結果;反之,使用linkedlist作為List型別的底層資料結構。

自Redis3.2+,預設使用quicklist作為List型別的底層資料結構

2.1 常用命令

127.0.0.1:6379> lpush mqlist 1 2 3 4 5 6	# 從頭部新增一個或多個元素,先入的在尾部,後入的在頭部
(integer) 6
127.0.0.1:6379> rpush mqlist 9 8 7		# 從尾部新增一個或多個元素,先入的在頭部,後入的在尾部
(integer) 9
127.0.0.1:6379> lrange mqlist 0 -1		# 遍歷列表中的元素,索引從0開始
1) "6"
2) "5"
3) "4"
4) "3"
5) "2"
6) "1"
7) "9"
8) "8"
9) "7"
127.0.0.1:6379> lpop mqlist 2	# 從左邊“彈出”兩個元素
1) "6"
2) "5"
127.0.0.1:6379> rpop mqlist	# 從右邊“彈出”一個元素,不指定count預設為1
1) "7"
127.0.0.1:6379> lrange mqlist 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
5) "9"
6) "8"
127.0.0.1:6379> lset mqlist 4 0		# 將列表中指定索引的元素設為指定值
OK
127.0.0.1:6379> lset mqlist 5 -1
OK
127.0.0.1:6379> llen mqlist		# 獲取列表的長度
(integer) 6
127.0.0.1:6379> lrange mqlist 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
5) "0"
6) "-1"

2.2 應用場景

2.2.1、訊息佇列

在講訊息佇列的實現前,需要直到如何使用list相關的指令實現佇列(先入先出)和棧(先入後出)的效果:

透過LPUSH/RPOP和RPUSH/LPOP實現佇列

$ lpush myList value1
$ lpush myList value2 value3
$ rpop myList  =>  "value1"
$ rpop myList  =>  "value2"

透過LPUSH/LPOP和RPUSH/RPOP實現棧

$ rpush myList value1 value2 value3
$ rpop myList => "value3"

如果要使用List作為訊息佇列儲存訊息,可以利用List型別先進先出的特點,滿足訊息佇列訊息保序的需求。

使用lpush+rpop(rpush+lpop)命令實現訊息佇列

在生產者向list中寫入資料時,list並不會主動通知消費者接收訊息,需要消費者不斷呼叫rpop命令。這樣帶來的問題是效能的損耗,因為要保證及時接收訊息,就需要不停rpop,消費者一直不停的rpop,對於CPU來說是種沒必要的損耗

為了解決這一問題,Redis提出了brpop命令:阻塞式讀取,消費端在沒有讀到佇列中資料時,自動阻塞,直到有新的資料寫入佇列。

同時,要保證訊息不被重複消費,就需要在寫入的時候指定一個全域性唯一ID。

List是不支援多個消費者消費同一條訊息的,因為一條訊息被一個消費者拉取到後,就會立即從List中刪除;要實現一條訊息可以被多個消費者消費,就不得不提消費組的概念,但是List不支援消費組的實現。Redis從5.0版本開始提供了Stream資料型別,可以更好的實現訊息佇列

三、Hash型別

Hash是一個String型別的鍵值對的對映表,特別適合儲存物件,類似jdk1.8前的HashMap。

Hash型別的底層資料結構是ziplist或hashtable實現的:如果元素個數小於512(hash-max-ziplist-entries)且所有值小於64(hash-max-ziplist-value)位元組,選用ziplsit;否則,選用hashtable作為底層資料結構

Redis7.0+採用listpack資料結構實現Hash型別。

3.1 常用命令

127.0.0.1:6379> hset hash1 name lisi	# 設定hash型別key-value
(integer) 1
127.0.0.1:6379> hmset hash1 age 18 sex man	# 批次設定hash型別key-value
OK
127.0.0.1:6379> hget hash1 name		# 獲取指定欄位的值
"lisi"
127.0.0.1:6379> hdel hash1 name		# 刪除指定欄位,返回刪除成功的個數
(integer) 1
127.0.0.1:6379> hlen hash1		# 獲取hash型別欄位個數
(integer) 2
127.0.0.1:6379> hgetall hash1	# 獲取hash型別所有欄位的key-value
1) "age"
2) "18"
3) "sex"
4) "man"
127.0.0.1:6379> hincrby hash1 age 2		# 對指定欄位做自增自減操作(正數為自增、負數為自減)
(integer) 20
127.0.0.1:6379> hexists hash1 name		# 判斷hash型別中指定欄位是否存在,存在返回,不存在返回0
(integer) 0

3.2 應用場景

3.2.1、快取物件

Hash型別的結構(key:{field:value})與物件的結構類似,可以用來儲存物件。比如User物件的結構如下:

uid(pk) uname uage ugender
e368e5b2-e5d0-425e-8abb-e439d23c288c 李四 19

對應在Redis中,可以這樣儲存:

$ hmset uid:e368e5b2-e5d0-425e-8abb-e439d23c288c uname 李四 uage 19 ugender 男

3.2.2、購物車

利用hincrby命令實現商品數量的增減

127.0.0.1:6379> hset cart:user-1 macbook 1	# 新增商品
(integer) 1
127.0.0.1:6379> hincrby cart:user-1 macbook 1	# 新增數量
(integer) 2
127.0.0.1:6379> hlen cart:user-1	# 獲取商品總數
(integer) 1
127.0.0.1:6379> hdel cart:user-1 macbook	# 刪除商品
(integer) 1
127.0.0.1:6379> hgetall cart:user-1		# 獲取購物車
(empty array)

四、Set型別

Set型別是一個無序且唯一的鍵值集合,它的儲存順序不會按照插入的先後順序進行儲存。一個集合最多可以儲存2^32-1個元素。

Set型別的底層資料結構是由HashTable或IntSet實現的:

​ 1. 如果集合中的元素都是整數且元素個數小於512(預設值,set-maxintset-entries配置),Redis會使用IntSet作為Set型別的底層實現

​ 2. 反之,使用HashTable作為Set型別的底層資料結構

4.1 常用命令

127.0.0.1:6379> sadd article:001 user1
(integer) 1
127.0.0.1:6379> sadd article:001 user2	# 向集合中存入元素
(integer) 1
127.0.0.1:6379> srem article:001 user1	# 從集合中刪除元素
(integer) 1
127.0.0.1:6379> smembers article:001	# 列出集合中的所有元素
1) "user2"
127.0.0.1:6379> scard article:001	# 獲取集合中的元素個數
(integer) 1
127.0.0.1:6379> sismember article:001 user1	# 判斷集合是否存在指定的元素
(integer) 0
127.0.0.1:6379> srandmember article:001	# 隨機列出count個元素
"user2"
127.0.0.1:6379> smembers article:001
1) "user2"
127.0.0.1:6379> spop article:001	# 隨機彈出count個元素,彈出即刪除
"user2"
127.0.0.1:6379> smembers article:001
(empty array)

運算操作:

Set 的差集、並集和交集的計算複雜度較高,在資料量較大的情況下,如果直接執行這些計算,會導致 Redis 例項阻塞

127.0.0.1:6379> sinter article:001 article:002	# 交集
1) "user1"
127.0.0.1:6379> sunion article:001 article:002	# 並集
1) "user1"
2) "user2"
127.0.0.1:6379> sdiff article:001 article:002	# 差集
1) "user2"

4.2 應用場景

set 型別的應用場景主要是利用集合的特性,比如:

  • 去重,利用 sadd 和 scard 命令實現元素的新增和計數。
  • 交集,並集,差集,利用 sinter,sunion 和 sdiff 命令實現集合間的運算。
  • 隨機抽取,利用 srandmember 命令實現隨機抽獎或者抽樣。

五、ZSet型別

ZSet是一種有序集合型別,他可以儲存不重複的字串資訊,並且給每個元素賦予一個排序權重值(score),透過score來為集合中的元素進行排序,ZSet中的成員是唯一的,但是權重值可以重複。一個ZSet型別的鍵最多可以儲存2^32-1個元素

5.1 常用命令

127.0.0.1:6379> zadd article:003 10 user1
(integer) 1
127.0.0.1:6379> zadd article:003 109 user2
(integer) 1
127.0.0.1:6379> zadd article:003 100 user3	# 新增元素
(integer) 1
127.0.0.1:6379> zscore article:003 user2	# 獲取元素得分
"109"
127.0.0.1:6379> zrem article:003 user2		# 刪除元素
(integer) 1
127.0.0.1:6379> zcard article:003			# 獲取元素個數
(integer) 2
127.0.0.1:6379> zincrby article:003 100 user1	# 元素自增指定值
"110"
127.0.0.1:6379> zrange article:003 0 -1 withscores	# 正序獲取索引範圍內的元素
1) "user3"
2) "100"
3) "user1"
4) "110"
127.0.0.1:6379> zrevrange article:003 0 -1 withscores	# 倒序獲取索引範圍內的元素
1) "user1"
2) "110"
3) "user3"
4) "100"
127.0.0.1:6379> zrangebyscore article:003 99 105	# 返回指定分數區間內的元素,從低到高
1) "user3"

5.2 應用場景

zset 型別的應用場景主要是利用分數和排序的特性,比如:

  • 排行榜,利用 zadd 和 zrange 命令實現分數的更新和排名的查詢
  • 延時佇列,利用 zadd 和 zpop 命令實現任務的新增和執行,並且可以定期地獲取已經到期的任務
  • 訪問統計,可以使用 zset 來儲存網站或者文章的訪問次數,並且可以按照訪問量進行排序和篩選。

部署配置

安裝環境:

系統:CentOS 7.9

核心版本:3.10.0-1160.92.1.el7.x86_64 #1 SMP Tue Jun 20 11:48:01 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

安裝版本:6.0.12


Redis的部署大體分三種:單機模式、哨兵模式、叢集模式;後兩者是對單機模式的擴充套件,突出可擴充套件性和高可用性。

不論是何種規模的部署,一些前置配置的調整是相同的:

# 主機名設定
hostnamectl --static set-hostname redis-node-1

# 關閉selinux(需重啟生效)
vim /etc/sysconfig.selinux
SELINUX=disabled

# 關閉防火牆 
systemctl stop firewalld

# 核心引數調整
# 1、記憶體分配策略,允許分配所有的實體記憶體,儘量避免OOM
echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
sysctl -p
# 2、禁用Linux大頁
echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled	# 臨時生效
sudo chmod +x /etc/rc.local	# 永久生效
sudo cat >> /etc/rc.local << EOF
echo never > /sys/kernel/mm/transparent_hugepage/enabled	
EOF
# 3、TCP監聽佇列長度
echo 2048 > /proc/sys/net/core/somaxconn
echo "echo 2048 > /proc/sys/net/core/somaxconn" >> /etc/rc.local
sysctl -p

一、單點部署

# 安裝編譯需要的gcc環境
yum -y install cpp binutils glibc glibc-kernheaders glibc-common glibc-devel gcc make gcc-c++ libstdc++-devel tcl wget

# 若gcc版本不在5.3以上,需要先進行升級
#升級到 5.3及以上版本
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
# 臨時啟用
scl enable devtoolset-9 bash
# 永久開啟
echo "source /opt/rh/devtoolset-9/enable" >> /etc/profile

# 獲取安裝包並解壓
cd /opt && wget http://download.redis.io/releases/redis-6.0.12.tar.gz && tar -zvxf redis-6.0.12.tar.gz

# 編譯安裝
cd /opt/redis-6.0.12 && make -j2 && make install PREFIX=/usr/local/redis

# 建立所需目錄
mkdir -p /usr/local/redis/{conf,data,log}

# 複製可執行檔案到安裝目錄下
\cp -rp /opt/redis-6.0.12/src /usr/local/redis 
# 預設配置檔案複製到安裝位置下 或者 直接新建配置檔案(保持屬主、許可權一致)
# cp /opt/redis-6.0.12/redis.conf /usr/local/redis/conf
touch /usr/local/redis/conf/redis.conf

# 修改配置檔案
cat >> /usr/local/redis/conf/redis.conf << EOF
bind 0.0.0.0	# 繫結ip
port 16379		# 繫結埠
tcp-backlog 2048	# socket連線數
protected-mode no 	# 關閉保護模式
requirepass	password		# 密碼認證
daemonize yes		# 後臺守護啟動
logfile	"/usr/local/redis/log/redis.log"	# 日誌檔案
dir	"/usr/local/redis/data"		# RDB檔案目錄
appendonly	yes		# 開啟AOF持久化
appendfilename "redis.aof"	# AOF檔名
rename-command KEYS "RENAMEKEYS"	# 高危命令重新命名
rename-command FLUSHALL "RENAMEFLUSHALL"
rename-command FLUSHDB  "RENAMEFLUSHDB"
maxmemory-policy volatile-lru	# 達到最大記憶體限制時,使用lru演算法移除過期key
EOF

# 配置systemd託管(可選)
cat >> /usr/lib/systemd/system/redis.service << EOF
[Unit]
Description=Redis Server
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
ExecStop=/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 16379 shutdown
Type=forking

[Install]
WantBy=multi-user.target
EOF

systemctl daemon-reload

# 加入環境變數
echo "REDIS_HOME=/usr/local/redis/bin" >> /etc/profile
echo "$PATH=$PATH:/$REDIS_HOME" >> /etc/profile
source /etc/profile

二、主從模式

主從模式是在單點模式的基礎上增加了主從複製的配置,可以是一主一從,也可以是一主多從。通常情況下說,一般是一主多從。

主從複製:從Redis Master節點複製到其他Slave節點,以實現資料的高可用性和讀寫分離。資料的複製只能是單向的(M->S)

# 搭建單點redis、參考單點模式部署
# 以一主兩從為例,兩個從節點配置檔案增加以下內容:
replicaof 192.168.252.16 16379	# 指定要同步的Master節點ip和port 
replica-priority 100 # 主節點選舉優先順序,預設100
master-auth	password # 若主節點開啟了認證,對應從節點需要配置master密碼

驗證主從複製:在主節點執行 redis-cli info replication ,若輸出結果中 connected_slaves為2且有從節點的資訊,則代表主從複製配置成功。

三、哨兵模式

哨兵的功能:在主從複製的基礎上,引入對於主節點的自動故障轉移

哨兵是一個分散式系統,對於主從結構中的服務進行監控,當出現故障後透過投票的機制選出新的Master節點,並將所有的Slace連結到新的Master,執行哨兵的叢集的節點數量不能小於3個(為了保證Master投票選舉)

哨兵模式的故障轉移:

  1. 哨兵節點定期監控發現主節點是否故障,哨兵節點週期性的向主節點、從節點和其他哨兵節點傳送Ping測,若是沒有做有效回覆,則對節點做主觀下線處理;若主觀下線的是主節點,會聯絡其他哨兵進行判斷,當超過半數認為主節點down掉後,做客觀下線處理。
  2. 主節點出現故障後,哨兵節點透過Raft演算法選舉出Leader哨兵節點;由Leader哨兵節點執行故障轉移
  3. 選舉新的主節點,其他從節點指向新的主節點;若原主節點恢復,則降級為從節點並指向新的主節點。
  4. 通知客戶端主節點已變更

主節點選舉原則:

  1. 選擇健康狀態(排除下線、斷線)的從節點,排除超過5s沒有心跳的,排除沒有回應哨兵Ping測的
  2. 選擇配置檔案中優先順序配置最高的(replica-priority,預設值為100;值越小優先順序越高
  3. 選擇複製偏移量最大的,也就是複製最完整的從節點

哨兵的部署配置

Sentinel實際上就是一個特殊的Redis服務,預設監聽26379/Tcp埠;哨兵一般同Redis服務部署在一起;哨兵的配置檔案指向sentinel.conf,使用redis-sentinel啟動。

grep -Ev '^$|^#' /usr/local/redis/conf/sentinel.conf
port 26379
daemonize yes
logfile "/usr/local/redis/log/sentinel.log"
dir "/usr/local/redis/data"
sentinel monitor redis-master 127.0.0.1 16379 2		# 指定監聽Master節點資訊,2代表quorm,即有幾個sentinel參與選舉
sentinel auth-pass redis-master password		# 若Master配置認證,需要配置Master的密碼
sentinel down-after-milliseconds redis-master 30000		# 判斷節點主觀下線的時間,單位ms
sentinel deny-scripts-reconfig yes		# 禁止修改指令碼

新增哨兵服務,方便管理

cat <<EOF > /usr/lib/systemd/system/redis-sentinel.service
[Unit]
Description=Redis Sentinel
After=network.target

[Service]
ExecStart=/usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel.conf
ExecStop=/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 26379 shutdown
Type=forking

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload

主節點執行 info sentinel 命令可以檢視sentinel狀態。

四、叢集模式

Redis Cluster是Redis 3.0後推出的分散式解決方案,提供資料分片、高可用功能;使用Redis Cluster能解決負載均衡的問題,內部採用雜湊分片規則。

安裝叢集所需軟體:Redis叢集需要使用ruby命令

yum install -y ruby
yum install -y rubygems
gem install redis	

在執行 gem install redis 命令時會報錯:

# gem install redis
Fetching: connection_pool-2.4.1.gem (100%)
ERROR:  Error installing redis:
        connection_pool requires Ruby version >= 2.5.0.

這是因為在CentOS中,yum源對於ruby的支援版本為2.0.0,而gem安裝redis提示需要2.5.0+,需要採用rvm來更新ruby

curl -sSL https://get.rvm.io | bash -s stable
# 命令執行完畢後,會在螢幕列印一串這樣的程式碼,需要我們手動複製並執行
gpg2 --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB

載入檔案,檢視庫中存在的ruby版本並安裝

source /usr/local/rvm/scripts/rvm	# 載入檔案
rvm list know	# 載入列表
rvm install 2.6.0	# 安裝新版本ruby
rvm use 2.6.0 --default		# 設定預設使用的ruby版本

重新執行 gem install redis 安裝成功,至此,Redis Cluster的前置依賴安裝完畢!

gem install redis

Redis Cluster是在單點Redis的配置上,啟動Cluster相關的配置;配置完畢後啟動redis,加入叢集

cluster-enabled yes(啟動叢集模式)
cluster-config-file node-16379.conf
cluster-node-timeout 15000
/usr/local/redis/src/redis-trib.rb create --replicas 1 xxxx.xx xxxx.xx xxxx.xx xxxx.xx
## --replicas 指定主從複製比例為1:1,即一個主節點對應一個從節點

執行完後可以使用 cluster info cluster nodes 檢視叢集節點資訊;還可以使用 redis-cli --cluster check 檢查叢集狀態。

叢集節點操作:

# 新增主節點:127.0.0.1:36372
/usr/local/redis/bin/redis-cli -a password --cluster add-node 127.0.0.1:36372 127.0.0.1:16372
# 這個時候新加入的主節點是沒有槽位的,也就是說無法進行讀寫,需要分配槽位後才能進行讀寫
/usr/local/redis/bin/redic-cli -a password --cluster reshard 127.0.0.1:36372
# 該命令是互動式的,會先詢問要分配多少槽位?
How many slots do you want to move(from 1 to 16384)? 4096
# 接著會詢問要分配給哪個節點ID,這裡要填寫新分配的主節點ID
What is the receiving node ID? 新分配主節點ID(透過redis-cli --cluster check 127.0.0.1:36372可以檢視)
# 接著會詢問要將哪個已有的節點槽位分配給新的主節點,一般填all即可,代表所有節點平均分配
Source node? all
# 最後輸入yes表示執行分配

# 給指定主節點新增從節點
/usr/local/redis/bin/redis-cli -a password --cluster add-node 127.0.0.1:46372 127.0.0.1:16372 --cluster-slave --cluster-master-id [新分配主節點ID](透過redis-cli --cluster check 127.0.0.1:36372可以檢視)

# 刪除節點
# 刪除主節點首先要刪除從節點、之後要把被刪除節點的槽位分配出去;在刪除節點之前,確保節點無會話登入
/usr/local/redis/bin/redis-cli -a password --cluster del-node 127.0.0.1:16372 [被刪除從節點id]
/usr/local/redis/bin/redis-cli -a password --cluster reshard 127.0.0.1:16372
# 相似的,這裡也是互動式操作,會詢問
/usr/local/redis/bin/redis-cli -a password --cluster del-node 127.0.0.1:16372 [被刪除主節點id]

資料持久化

Redis是一個基於記憶體的資料庫。服務一旦當機,記憶體中的資料就會全部丟失。通常的解決方案是從後端資料庫恢復資料,但是後端資料庫有效能瓶頸,如果是大資料量的恢復,1、會對資料庫帶來巨大的壓力,2、資料庫效能不如Redis,程式響應慢。所以,對於Redis來說,實現資料的持久化,避免從後端資料庫來恢復資料,顯得至關重要。

從嚴格意義上說,Redis服務提供四種持久化儲存方案:RDBAOF虛擬記憶體(VM)和 DISKSTORE。虛擬記憶體(VM)方式,從Redis Version 2.4開始就被官方明確表示不再建議使用,Version 3.2版本中更找不到關於虛擬記憶體(VM)的任何配置範例,Redis的主要作者Salvatore Sanfilippo還專門寫了一篇論文,來反思Redis對虛擬記憶體(VM)儲存技術的支援問題。

至於DISKSTORE方式,是從Redis Version 2.8版本開始提出的一個儲存設想,到目前為止Redis官方也沒有在任何stable版本中明確建議使用這用方式。在Version 3.2版本中同樣找不到對於這種儲存方式的明確支援。從網路上能夠收集到的各種資料來看,DISKSTORE方式和RDB方式還有著一些千絲萬縷的聯絡,不過各位讀者也知道,除了官方文件以外網路資料很多就是大抄。

最關鍵的是目前官方文件上能夠看到的Redis對持久化儲存的支援明確的就只有兩種方案:RDBAOF

RDB 和 AOF 是可以同時開啟的,在這種情況下,當Redis重啟的時候會優先載入 AOF 檔案來恢復原始的資料。

img

一、RDB持久化

RDB是Redis Database的縮寫,中文名為快照/記憶體快照,RDB持久化是把當前程序資料生成快照儲存到磁碟上的過程,由於是某一時刻的快照,所以快照中的值要早於或者等於記憶體中的值。

1.1 觸發方式

觸發rdb持久化的方式有2種,分別是手動觸發和自動觸發。

1.1.1 手動觸發

手動觸發分別對應save和bgsave命令

  1. save:阻塞當前redis伺服器,直至rdb過程完成為止,對於記憶體比較大的例項會造成長時間阻塞,線上環境不建議使用
  2. bgsave:redis程序fork出子程序,rdb持久化操作由子程序負責,完成後自動結束,阻塞只發生在fork子程序階段,時間很短,流程如下:image-20240425145002299

1.1.2 自動觸發

會在以下四種情況下觸發:

  1. redis.conf中配置save m n,即在m秒內有n次修改時,自動觸發bgsave生成rdb檔案;

  2. 主從複製時,從節點要從主節點進行全量複製時也會觸發bgsave操作,生成當時的快照傳送到從節點;

  3. 執行debug reload命令重新載入redis時也會觸發bgsave操作;

  4. 預設情況下執行shutdown命令時,如果沒有開啟aof持久化,那麼也會觸發bgsave操作;

1.2 配置RDB

記憶體快照雖然可以透過技術人員執行save或bgsave命令來進行,但生產環境大多情況會設定成周期性執行條件

Redis中的預設的週期性配置

# 週期性執行條件的設定格式為:
save <seconds> <changes>
# 預設的配置是:
save 900 1
save 300 10
save 60 10000

# 以下設定為關閉rdb快照功能
save ""

以上三項預設資訊設定代表的意義是:

  • 如果900秒內有1條Key資訊發生變化,則進行快照
  • 如果300秒內有10條Key資訊發生變化,則進行快照
  • 如果60秒內有10000條Key資訊發生變化,則進行快照

其他配置:

# 檔名
dbfilename dump.rdb
# 檔案路徑
dir ./
# rdb出現錯誤,主程序是否停止寫入
stop-writes-on-bgsave-error yes
# 是否壓縮
rdbcompression yes
# 匯入時是否檢查
rdbchecksum yes

1.3 RDB深入瞭解

由於生產環境中我們為Redis開闢的記憶體空間足夠大,那麼將記憶體中的資料同步到硬碟的過程中可能就會持續比較長的時間,而實際情況是這段時間內Redis服務會持續收到資料寫請求,那麼如何保證資料一致性呢?

RDB中的核心思路是Copy-on-Write,來保證在進行快照操作的這段時間,需要壓縮寫入磁碟上的資料在記憶體中不會發生變化。在正常的快照操作中,一方面Redis主程序會fork一個新的快照程序專門來做這個事情,這樣保證了Redis服務不會停止對客戶端包括寫請求在內的任何響應。另一方面這段時間發生的資料變化會以副本的方式存放在另一個新的記憶體區域,待快照操作結束後才會同步到原來的記憶體區域。

舉個例子:如果主執行緒對這些資料也都是讀操作(例如圖中的鍵值對 A),那麼,主執行緒和 bgsave 子程序相互不影響。但是,如果主執行緒要修改一塊資料(例如圖中的鍵值對 C),那麼,這塊資料就會被複制一份,生成該資料的副本。然後,bgsave 子程序會把這個副本資料寫入 RDB 檔案,而在這個過程中,主執行緒仍然可以直接修改原來的資料。

在進行rdb操作的這段時間,如果發生服務崩潰怎麼辦?

在沒有將資料全部寫入到磁碟前,這次快照操作都不算成功。如果出現服務崩潰的情況,將以上一次完整的rdb快照檔案作為恢復記憶體資料的參考。也就是說,在快照操作過程中不能影響上一次的備份資料。Redis服務會在磁碟上建立一個臨時檔案進行資料操作,待操作成功後才會用這個臨時檔案替換掉上一次的備份。

可以每秒做一次快照嗎?

如果頻繁執行全量快照,會帶來兩方面的開銷:

  • 一方面,頻繁的將全量資料寫入磁碟,會給磁碟帶來很大壓力,多個快照競爭有限的磁碟頻寬,前一個快照還沒有做完,後一個又開始了,容易造成惡性迴圈
  • 另一方面,bgsave子程序需要透過fork操作從主程序建立出來。雖然子程序在建立後不會阻塞主程序,但是,fork這個動作本身就會阻塞主執行緒,主執行緒記憶體越大,阻塞時間越長

1.4 RDB的優缺點

  • 優點
    • RDB檔案是某個時間點的快照,預設使用LZF演算法壓縮,壓縮後的檔案體積遠遠小於記憶體大小,常用於備份、全量複製等場景
    • Redis載入RDB檔案恢復資料要遠遠快於AOF方式
  • 缺點
    • 實時性不夠,無法做到秒級持久化
    • 每次呼叫bgsave都需要fork子程序,頻繁執行成本較高
    • RDB檔案是二進位制的,沒有可讀性;而AOF檔案在瞭解其結構的情況下可以手動修改或補全
    • 版本相容問題

針對RDB不適合實時持久化的問題,Redis提供了AOF持久化方式來解決。

二、AOF持久化

Redis是“寫後”日誌,Redis先執行命令,把資料寫入記憶體,然後才記錄日誌。日誌裡記錄的是Redis收到的每一條命令,這些命令是以文字形式儲存。

PS: 大多數的資料庫採用的是寫前日誌(WAL),例如MySQL,透過寫前日誌和兩階段提交,實現資料和邏輯的一致性。

為什麼採用寫後日志?

  • 避免額外開銷:redis向aof記錄日誌的時候,並不會先去對這些命令進行語法檢查。如果先記錄日誌再執行命令的話,日誌中有可能記錄了錯誤的命令,導致恢復資料出錯
  • 不會阻塞當前的寫程序

但這種方式也會存在潛在的風險:

  • 如果命令執行完畢,寫日誌之前當機了,會丟失資料
  • 主執行緒寫磁碟壓力大,導致寫盤慢,阻塞後續操作

2.1 實現AOF

AOF日誌記錄redis的每個寫命令,步驟分為:命令追加(append)、檔案寫入(write)和檔案同步(sync)

當AOF持久化功能開啟後,伺服器在執行完一個寫命令後,會以協議格式將被執行的寫命令追加到伺服器的aof_buffer緩衝區;關於何時將aof_buffer內的內容寫入到檔案中,redis提供了三種寫回策略。

配置項 寫回機制 優點 缺點
Always 同步寫回 可靠性高,資料基本不丟失 每個寫命令都要落盤,效能影響較大
Everysec 每秒寫回 效能適中 當機時丟失1秒內的資料
No 作業系統控制寫回 效能好 當機時丟失資料較多

reids.conf配置AOF:

預設情況下,redis是沒有開啟AOF的

# appendonly引數開啟AOF持久化
appendonly no

# AOF持久化的檔名,預設是appendonly.aof
appendfilename "appendonly.aof"

# AOF檔案的儲存位置和RDB檔案的位置相同,都是透過dir引數設定的
dir ./

# 同步策略
# appendfsync always
appendfsync everysec
# appendfsync no

# aof重寫期間是否同步
no-appendfsync-on-rewrite no

# 重寫觸發配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 載入aof出錯如何處理
aof-load-truncated yes

# 檔案重寫策略
aof-rewrite-incremental-fsync yes

2.2 AOF重寫

AOF會記錄每個寫命令到AOF檔案,隨著時間越來越長,AOF檔案會變得越來越大。如果不加以控制,會對Redis伺服器,甚至對作業系統造成影響,而且AOF檔案越大,資料恢復也越慢。為了解決AOF檔案體積膨脹的問題,Redis提供AOF檔案重寫機制來對AOF檔案進行“瘦身”。

2.2.1 AOF重寫會阻塞嗎?

AOF重寫過程由後臺程序bgrewriteaof完成。主執行緒fork出後臺的bgrewriteaof子程序,fork會把主執行緒的記憶體複製一份給bgrewriteaof子程序,這裡就包含了資料庫的最新資料。然後,bgrewriteaof子程序就可以在不影響主執行緒的情況下,逐一把複製的資料寫成操作,記入重寫日誌。

AOF在重寫時,在fork程序時是會阻塞主執行緒的。

2.2.2 AOF日誌何時會重寫?

有兩個配置項控制AOF重寫的觸發:

  1. auto-aof-rewrite-min-size:執行AOF重寫的檔案的最小觸發值,單位為MB
  2. auto-aof-rewrite-percentage:當前aof檔案大小和上次重寫後aof檔案大小的差值/上次重寫後aof檔案的大小;增量大小與上次重寫aof檔案的比值。

2.2.3 重寫日誌時,有新資料寫入怎麼辦?

重寫過程總結為:“一個複製,兩處日誌”。在fork出子程序時的複製,以及在重寫時,如果有新資料寫入,主執行緒就會將命令記錄到兩個aof日誌記憶體緩衝區中。如果AOF寫回策略配置的是always,則直接將命令寫回舊的日誌檔案,並且儲存一份命令至AOF重寫緩衝區,這些操作對新的日誌檔案是不存在影響的。(舊的日誌檔案:主執行緒使用的日誌檔案,新的日誌檔案:bgrewriteaof程序使用的日誌檔案)

而在bgrewriteaof子程序完成會日誌檔案的重寫操作後,會提示主執行緒已經完成重寫操作,主執行緒會將AOF重寫緩衝中的命令追加到新的日誌檔案後面。這時候在高併發的情況下,AOF重寫緩衝區積累可能會很大,這樣就會造成阻塞,Redis後來透過Linux管道技術讓aof重寫期間就能同時進行回放,這樣aof重寫結束後只需回放少量剩餘的資料即可。

最後透過修改檔名的方式,保證檔案切換的原子性。

在AOF重寫日誌期間發生當機的話,因為日誌檔案還沒切換,所以恢復資料時,用的還是舊的日誌檔案。

2.2.4 為什麼AOF重寫不復用原來的AOF日誌?

  1. 父子程序同寫一個檔案會產生競爭問題,影響父程序的效能
  2. 如果AOF重寫過程失敗了,相當於汙染了原本的AOF檔案,無法做恢復資料使用

三、RDB和AOF混合方式

Redis4.0中提出了一個混合使用AOF日誌和記憶體快照的方法。簡單來說,記憶體快照以一定的頻率執行,在兩次快照之間,使用AOF日誌記錄這期間的所有命令操作。

這樣一來,快照不用很頻繁的執行,避免了頻繁fork對主執行緒的影響;而且,AOF日誌也只記錄了兩次快照間的操作,也就是說,不需要記錄所有操作,因此,不會出現檔案過大的情況,避免重寫開銷。

這個方法既能享受到 RDB 檔案快速恢復的好處,又能享受到 AOF 只記錄操作命令的簡單優勢, 實際環境中用的很多。

常用運維指令

一、info監控指令

redis本身提供的info指令可以檢視豐富的例項執行監控資訊,這個命令是redis監控工具的基礎。

指令 監控類別
info server 檢視server端監控資訊,包括pid、配置檔案、埠等
info clients 檢視客戶端統計資訊
info stats 檢視通用統計資訊
info keyspace 檢視資料庫整體統計情況
info commandstats 檢視各命令呼叫統計資訊
info cpu 檢視CPU使用資訊
info memory 檢視Memory使用資訊
info replication 檢視主從複製統計資訊
info persistence 檢視RDB、AOF執行資訊
info cluster 檢視叢集統計資訊

二、monitor命令

monitor指令用於實時監控redis資料庫的操作,需要注意的是,執行完monitor後,當前redis視窗會話會阻塞,執行不了其他指令

monitor指令返回當前正在執行的命令詳情,包括時間戳、客戶端資訊、命令詳情等

三、慢日誌查詢及分析

redis的慢查詢日誌負責記錄超過指定執行時間的查詢操作。這個執行時間只是命令的耗時,並不包括I/O操作耗時。

一條查詢命令分為三步:1、客戶端傳送命令 2、redis服務端收到命令,進行排隊處理 3、執行命令 4、返回結果;慢查詢只記錄其中的第三步耗時。

3.1 慢查詢的兩個配置引數

慢查詢日誌的配置有兩個引數控制:

1、slowlog-log-slower-than:指定執行時間的最大值(上限值),單位是us;redis會記錄超過這個配置值的查詢操作;若是將該引數配置為負數,則代表禁用慢查詢日誌;若該引數配置為0,則代表記錄每條查詢命令

2、slowlog-max-len:用於指定慢查詢日誌的最大長度,最小值為0;當慢查詢日誌超過最大長度時,redis就會從慢查詢日誌佇列中找到最老的一條記錄並移除

可以在配置檔案(redis.conf)中配置上面兩個引數;也可以在redis執行時使用config set指令重新指定配置值並使用 config rewrite將配置持久化到配置檔案中。

127.0.0.1:16379> config set slowlog-log-slower-than 0
OK
127.0.0.1:16379> config set slowlog-max-len 10
OK
127.0.0.1:16379> config rewrite
OK

3.2 慢查詢相關命令

為了方便測試,上面已經將slowlog-log-slower-than引數設定為0,代表記錄所有查詢命令。

# slowlog get n 查詢最近n條慢查詢記錄
127.0.0.1:16379> slowlog get 1
1) 1) (integer) 11
   2) (integer) 1718614641
   3) (integer) 5
   4) 1) "get"
      2) "key2"
   5) "127.0.0.1:36824"
   6) ""
# slowlog len 查詢當前的慢查詢日誌佇列長度
127.0.0.1:16379> slowlog len
(integer) 10
# slowlog reset 重置慢查詢日誌,一旦執行,之前記錄的慢查詢日誌會被刪除
127.0.0.1:16379> slowlog reset
OK
127.0.0.1:16379> slowlog len
(integer) 1

3.3 慢查詢配置

慢查詢可以幫助我們排查到redis可能存在的效能瓶頸,但在使用過程中要注意以下幾點:

  1. slowlog-max-len:線上建議調大該引數配置,記錄慢查詢時redis會對命令做截斷處理,並不會大量佔用記憶體。增大慢查詢列表可以減緩慢查詢被剔除的可能性,線上建議配置為1000以上
  2. slowlog-log-slower-than:預設值為10ms判定為慢查詢,線上可以根據業務併發量調整該引數
  3. 慢查詢日誌只會記錄命令執行時間,並不包括命令排隊和網路傳輸時間,因此客戶端執行命令的時間會大於命令實際執行時間
  4. 慢查詢日誌佇列是一個FIFO的佇列,如果慢查詢較多的情況下,會丟失部分慢查詢日誌;建議定期執行 slowlog get 指令將慢查詢日誌轉移到其他儲存中

BigKey分析及解決

一、什麼是大key和熱key?

Redis中的大Key主要指,單個簡單的key(String型別)儲存的value大或者Hash、Set、Zset、List、Zlist這種資料型別中儲存的元素過多(>10000); 熱Key指的是那些查詢QPS大或者佔用頻寬和CPU集中的Key。

二、大Key和熱Key帶來的問題?

讀寫大Key會使客戶端執行時間過長,嚴重的導致超時甚至阻塞服務;對於大Key執行Delete操作,可能會對其他請求造成阻塞,進而引發服務異常

熱Key會佔用Redis伺服器大量的CPU和記憶體資源;當熱Key的請求QPS超過Redis的最大承受能力時,會造成快取擊穿等問題

三、如何查詢大Key和熱Key?

注:對於大Key和熱Key的查詢一般效率都不會也別高,存在阻塞的風險,若例項是主從架構,建議以下的命令優先執行在從節點

3.1 命令查詢

redis-cli自帶引數 --bigkeys和--hotkeys(version 4.0+ 提供),可以查詢出各資料型別中最大的那個Key。

原理:以loop的方式分析例項中的所有key,返回key的整體統計資訊以及Top1的那個key;準確性和實時性較差,並且只能展示Top1

[root@hcss-ecs-1b32 ~]# redis-cli -p 16379 -a password --bigkeys
[00.00%] Biggest string found so far '"key3"' with 6 bytes

-------- summary -------

Sampled 3 keys in the keyspace!
Total key length in bytes is 12 (avg len 4.00)

Biggest string found '"key3"' has 6 bytes

0 lists with 0 items (00.00% of keys, avg size 0.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
3 strings with 18 bytes (100.00% of keys, avg size 6.00)
0 streams with 0 entries (00.00% of keys, avg size 0.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)

除redis-cli自帶的引數查詢以外,redis還提供了一個debug object [key] 的命令,可以檢視每個key的具體資訊,從中得到一個key的value序列化後的大小。但是,debug object的執行效率較低,且如果想查詢庫中所有key的大小,需要迴圈呼叫該命令,會有阻塞redis的風險。該命令可做除錯用。

127.0.0.1:16379> debug object key3
Value at:0x7f68de00e4e0 refcount:1 encoding:embstr serializedlength:7 lru:7418869 lru_seconds_idle:2364

4.0以上的版本還提供了 memory uage [key]命令,可以更簡單直接的檢視當前key的記憶體佔用值,返回值單位是位元組

127.0.0.1:16379> memory usage key3
(integer) 56

3.2 雲資料庫統計

如果使用的是雲資料庫Redis,各服務商會提供有實時BigKey和HotKey統計功能,如阿里雲的實時TopKey統計功能,騰訊雲的資料庫智慧管家等功能,都能夠幫助使用者快速查詢資料庫中存在的BigKey和HotKey。

3.3 離線分析

離線分析是基於RDB檔案來操作,因此,要開展離線分析,需要先開啟RDB轉存功能:在配置檔案中指定save配置,手動執行一次轉存可以使用bgsave命令。

介紹一款比較經典的離線rdb分析工具:rdb-tools,這是一個python編寫的工具,需要python環境。例如,我的雲主機python version是2.7。先使用pip安裝下rdb-tools:pip install rdb-tools,結果提示 pip: command not found,這裡就需要先安裝pip管理工具,使用python -m ensurepip重灌下pip元件,接著提示no moudle named ensurepip,到這裡可以看出主機上的python環境其實是並不完善的;沒辦法,繼續解決問題;查詢到一篇csdn的博文,與我的情況類似;解決步驟如下:

第一步,下載get-pip.py檔案
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
第二步,執行
puthon get-pip.py
第三步,執行報錯:ERROR: This script does not work on Python 2.7 The minimum supported Python version is 3.7. Please use https://bootstrap.pypa.io/pip/2.7/get-pip.py instead. 根據提示替換連結重新下載執行解決pip工具未安裝的問題。
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py && python get-pip.py

之後,需要下載rdb-tools,由於python2官方源沒有收錄rdb-tools,所以,這裡我們需要指定pip源:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple rdbtools

另外,還需要安裝lzf包(可選,最好安裝),用於提高rdb-tools工具解析速度;在安裝時報錯,報錯資訊如下:

lzf_module.c:3:10: fatal error: Python.h: No such file or directory
        3 | #include "Python.h"
          |          ^~~~~~~~~~
    compilation terminated.
    error: command 'gcc' failed with exit status 1

這是因為缺少Python.h,需要安裝python對應的devel環境。

yum install -y python-devel   # 先安裝devel環境,之後安裝lzf包成功
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple python-lzf

當然,python2其實已經不適用於現在的業務環境;除特殊情況外,建議將原主機的python升級至3.6以上,能夠避免很多問題。

rdb-tools使用:

rdb-tools的使用主要是瞭解其引數的意義;常用的引數有-c/--command,-f/--file,-k/--key,-t/--type,-l/--largest。

-c 指定處理格式,有json、memory、justkeys、justkeyvals、protocol等

-f 指定輸出檔案

-k 指定匯出的key,這是一個正規表示式

-t 指定解析的資料型別

-b 指定大於或等於該值的key輸出

-l 指定輸出前N個key

usage: usage: rdb [options] /path/to/dump.rdb

Example : rdb --command json -k "user.*" /var/redis/6379/dump.rdb

rdb --command json dump.rdb -f dump_bigkey.json
rdb -c memory -b 128 -l -1 -f dump_bigkey_mr128b.csv
# 輸出結果包括這幾列:database,type,key,size_in_bytes,encoding,num_elements,len_largest_element,expiry

四、最佳化大Key和熱Key

1、對大Key進行拆分,比如將有數萬個元素的hash key拆分成多個hash key

2、使用讀寫分離機制,如果熱Key的產生來自於讀請求,可以將例項改造成讀寫分離架構來降低請求壓力

3、定期刪除過期key和大Key,刪除建議:

​ 3.1、redis4.0+的版本,使用 unlink命令安全刪除大key;unlink命令與del命令相似,但它是在後臺非同步刪除,不會阻塞當前客戶端,也不會阻塞redis主執行緒;並且unlink可以刪除多種型別的key。4.0之前的版本使用del命令刪除,但是要注意刪除大Key會有阻塞風險,建議漸進式刪除。

​ 3.2、藉助scan命令,遍歷大Key,每次取一部分,進行刪除,刪除完畢後再進行下一部分的刪除

​ 3.3、使用rename將大Key改名,這樣任何客戶端都不會訪問到該key,相當與邏輯刪除,再進行少量多批次的刪除

參考資料:

1、https://help.aliyun.com/zh/redis/user-guide/identify-and-handle-large-keys-and-hotkeys

2、https://www.cnblogs.com/jelly12345/p/14972572.html

3、https://www.cnblogs.com/zping/p/15185064.html