9個提升逼格的redis命令
keys
我把這個命令放在第一位,是因為筆者曾經做過的專案,以及一些朋友的專案,都因為使用 keys
這個命令,導致出現效能毛刺。這個命令的時間複雜度是O(N),而且redis又是單執行緒執行,在執行keys時即使是時間複雜度只有O(1)例如SET或者GET這種簡單命令也會堵塞,從而導致這個時間點效能抖動,甚至可能出現timeout。
強烈建議生產環境遮蔽keys命令(後面會介紹如何遮蔽)。
scan
既然 keys 命令不允許使用,那麼有什麼代替方案呢?有!那就是 scan
命令。如果把keys命令比作類似 select*fromuserswhereusername like'%afei%'
select*fromuserswhereid>?limit10
這種命令。
官方文件用法如下:
-
SCAN cursor [MATCH pattern] [COUNT count]
初始執行 scan 命令例如 scan0
。SCAN 命令是一個基於遊標的迭代器。這意味著命令每次被呼叫都需要使用上一次這個呼叫返回的遊標作為該次呼叫的遊標引數,以此來延續之前的迭代過程。當 SCAN 命令的遊標引數被設定為 0時,伺服器將開始一次新的迭代,而當redis伺服器向用戶返回值為0的遊標時,表示迭代已結束,這是唯一迭代結束的判定方式,而不能通過返回結果集是否為空判斷迭代結束。
使用方式:
-
127.0.0.1:6380> scan 0
-
1) "22"
-
2) 1) "23"
-
2) "20"
-
3) "14"
-
4) "2"
-
5) "19"
-
6) "9"
-
7) "3"
-
8) "21"
-
9) "12"
-
10) "25"
-
11) "7"
返回結果分為兩個部分:第一部分即 1) 就是下一次迭代遊標,第二部分即 2) 就是本次迭代結果集。
slowlog
上面提到不能使用 keys 命令,如果就有開發這麼做了呢,我們如何得知?與其他任意儲存系統例如 mysql,mongodb 可以檢視慢日誌一樣,redis 也可以,即通過命令 slowlog
。用法如下:
-
SLOWLOG subcommand [argument]
subcommand 主要有:
-
get:用法:slowlog get [argument],獲取 argument 引數指定數量的慢日誌。
-
len:用法:slowlog len,總慢日誌數量。
-
reset:用法:slowlog reset,清空慢日誌。
執行結果如下:
-
127.0.0.1:6380> slowlog get 5
-
1) 1) (integer) 2
-
2) (integer) 1532656201
-
3) (integer) 2033
-
4) 1) "flushddbb"
-
2) 1) (integer) 1 ---- 慢日誌編碼,一般不用care
-
2) (integer) 1532646897 ---- 導致慢日誌的命令執行的時間點,如果api有timeout,可以通過對比這個時間,判斷可能是慢日誌命令執行導致的
-
3) (integer) 26424 ---- 導致慢日誌執行的redis命令,通過4)可知,執行config rewrite導致慢日誌,總耗時26ms+
-
4) 1) "config"
-
2) "rewrite"
命令耗時超過多少才會儲存到 slowlog 中,可以通過命令
configsetslowlog-log-slower-than2000
配置並且不需要重啟 redis 。注意:單位是微妙,2000 微妙即 2 毫秒。
rename-command
為了防止把問題帶到生產環境,我們可以通過配置檔案重新命名一些危險命令,例如 keys
等一些高危命令。操作非常簡單,只需要在 conf 配置檔案增加如下所示配置即可:
-
rename-command flushdb flushddbb
-
rename-command flushall flushallall
-
rename-command keys keysys
bigkeys
隨著專案越做越大,快取使用越來越不規範。我們如何檢查生產環境上一些有問題的資料。 bigkeys
就派上用場了,用法如下:
-
redis-cli -p 6380 --bigkeys
執行結果如下:
-
... ...
-
-------- summary -------
-
-
Sampled 526 keys in the keyspace!
-
Total key length in bytes is 1524 (avg len 2.90)
-
-
Biggest string found 'test' has 10005 bytes
-
Biggest list found 'commentlist' has 13 items
-
-
524 strings with 15181 bytes (99.62% of keys, avg size 28.97)
-
2 lists with 19 items (00.38% of keys, avg size 9.50)
-
0 sets with 0 members (00.00% of keys, avg size 0.00)
-
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
-
0 zsets with 0 members (00.00% of keys, avg size 0.00)
最後 5 行可知,沒有 set,hash,zset 幾種資料結構的資料。string 型別有 524 個,list 型別有兩個;通過 Biggest......
可知,最大 string 結構的 key 是 test
,最大 list 結構的 key 是 commentlist
。
需要注意的是,這個bigkeys得到的最大,不一定是最大。說明原因前,首先說明 bigkeys
的原理,非常簡單,通過 scan 命令遍歷,各種不同資料結構的 key ,分別通過不同的命令得到最大的 key:
-
如果是 string 結構,通過
strlen
判斷; -
如果是 list 結構,通過
llen
判斷; -
如果是 hash 結構,通過
hlen
判斷; -
如果是 set 結構,通過
scard
判斷; -
如果是 sorted set 結構,通過
zcard
判斷。
正因為這樣的判斷方式,雖然 string 結構肯定可以正確的篩選出最佔用快取,也可以說最大的 key。但是 list 不一定,例如,現在有兩個 list 型別的 key,分別是:
numberlist--[0,1,2],stringlist--["123456789123456789"]
,由於通過 llen 判斷,所以 numberlist 要大於 stringlist 。而事實上 stringlist 更佔用記憶體。其他三種資料結構 hash,set,sorted set 都會存在這個問題。使用 bigkeys 一定要注意這一點。
monitor
假設生產環境沒有遮蔽 keys 等一些高危命令,並且 slowlog 中還不斷有新的 keys 導致慢日誌。那我們如何揪出這些命令是由誰執行的呢?這就是 monitor
的用處,用法如下:
-
redis-cli -p 6380 monitor
如果當前 redis 環境 OPS 比較高,那麼建議結合 linux 管道命令優化,只輸出 keys 命令的執行情況:
-
[[email protected] ~]# redis-cli -p 6380 monitor | grep keys
-
1532645266.656525 [0 10.0.0.1:43544] "keyss" "*"
-
1532645287.257657 [0 10.0.0.1:43544] "keyss" "44*"
執行結果中很清楚的看到 keys 命名執行來源。通過輸出的 IP 和埠資訊,就能在目標伺服器上找到執行這條命令的程序,揪出元凶,勒令整改。
info
如果說哪個命令能最全面反映當前 redis 執行情況,那麼非 info 莫屬。用法如下:
-
INFO [section]
section可選值有:
-
Server:執行的redis例項一些資訊,包括:redis 版本,作業系統資訊,埠,GCC 版本,配置檔案路徑等;
-
Clients:redis 客戶端資訊,包括:已連線客戶端數量,阻塞客戶端數量等;
-
Memory:使用記憶體,峰值記憶體,記憶體碎片率,記憶體分配方式。這幾個引數都非常重要;
-
Persistence:AOF 和 RDB 持久化資訊;
-
Stats:一些統計資訊,最重要三個引數:OPS(
instantaneous_ops_per_sec
),keyspace_hits
和keyspace_misses
兩個引數反應快取命中率; -
Replication:redis 叢集資訊;
-
CPU:CPU 相關資訊;
-
Keyspace:redis 中各個 DB 裡 key 的資訊;
config
config 是一個非常有價值的命令,主要體現在對 redis 的運維。因為生產環境一般是不允許隨意重啟的,不能因為需要調優一些引數就修改 conf 配置檔案並重啟。redis 作者早就想到了這一點,通過 config 命令能熱修改一些配置,不需要重啟 redis 例項,可以通過如下命令檢視哪些引數可以熱修改:
-
config get *
熱修改就比較容易了,執行如下命令即可:
-
config set
例如: configsetslowlog-max-len100
, configsetmaxclients1024
這樣修改的話,如果以後由於某些原因 redis 例項故障需要重啟,那通過 config 熱修改的引數就會被配置檔案中的引數覆蓋,所以我們需要通過一個命令將 config 熱修改的引數刷到 redis 配置檔案中持久化,通過執行如下命令即可:
-
config rewrite
執行該命令後,我們能在 config 檔案中看到類似這種資訊:
-
# 如果conf中本來就有這個引數,通過執行config set,那麼redis直接原地修改配置檔案
-
maxclients 1024
-
# 如果conf中沒有這個引數,通過執行config set,那麼redis會追加在Generated by CONFIG REWRITE字樣後面
-
# Generated by CONFIG REWRITE
-
save 600 60
-
slowlog-max-len 100
set
set 命令也能提升逼格?是的,我本不打算寫這個命令,但是我見過太多人沒有完全掌握這個命令,官方文件介紹的用法如下:
-
SET key value [EX seconds] [PX milliseconds] [NX|XX]
你可能用的比較多的就是 setkey value
,或者 SETEX key seconds value
,所以很多同學用 redis 實現分散式鎖分為兩步:首先執行 SETNX key value
,然後執行 EXPIRE key seconds
。很明顯,這種實現有很嚴重的問題,因為兩步執行不具備原子性,如果執行第一個命令後出現某些未知異常導致無法執行 EXPIRE key seconds
,那麼分散式鎖就會一直無法得到釋放。
通過 SET
命令實現分散式鎖的正式姿勢應該是 SET key value EX seconds NX
(EX和PX任選,取決於對過期時間精度要求)。另外,value也有要求,最好是一個類似 UUID 這種具備唯一性的字串。當然如果問你 redis 是否還有其他實現分散式鎖的方案。你能說出 redlock ,那對方一定眼前一亮,心裡對你豎起大拇指,但嘴上不會說。
歡迎工作一到十年的Java工程師朋友們加入Java進階高階架構:828545509
本群提供免費的學習指導 架構資料 以及免費的解答
不懂得問題都可以在本群提出來 之後還會有職業生涯規劃以及面試指導