點選上方“芋道原始碼”,選擇“置頂公眾號”
技術文章第一時間送達!
原始碼精品專欄
來源:https://www.jianshu.com/p/4df5f2356de9
keys
我把這個命令放在第一位,是因為筆者曾經做過的專案,以及一些朋友的專案,都因為使用keys
這個命令,導致出現效能毛刺。這個命令的時間複雜度是O(N),而且redis又是單執行緒執行,在執行keys時即使是時間複雜度只有O(1)例如SET或者GET這種簡單命令也會堵塞,從而導致這個時間點效能抖動,甚至可能出現timeout。
強烈建議生產環境遮蔽keys命令(後面會介紹如何遮蔽)。
scan
既然keys命令不允許使用,那麼有什麼代替方案呢?有!那就是scan
命令。如果把keys命令比作類似select * from users where username like '%afei%'
這種SQL,那麼scan應該是select * from users where id>? limit 10
這種命令。
官方檔案用法如下:
SCAN cursor [MATCH pattern] [COUNT count]
初始執行scan命令例如scan 0
。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中,可以透過命令
config set slowlog-log-slower-than 2000
配置並且不需要重啟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命令的執行情況:
[afei@redis ~]# 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
例如:config set slowlog-max-len 100
,config set maxclients 1024
這樣修改的話,如果以後由於某些原因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]
你可能用的比較多的就是set key 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,那對方一定眼前一亮,心裡對你豎起大拇指,但嘴上不會說。
關於redis分散式鎖方案,強烈建議你閱讀redis官方檔案Redis分散式鎖:http://redis.cn/topics/distlock.html
如果你對 Dubbo / Netty 等等原始碼與原理感興趣,歡迎加入我的知識星球一起交流。長按下方二維碼噢:
目前在知識星球更新了《Dubbo 原始碼解析》目錄如下:
01. 除錯環境搭建
02. 專案結構一覽
03. 配置 Configuration
04. 核心流程一覽
05. 拓展機制 SPI
06. 執行緒池
07. 服務暴露 Export
08. 服務取用 Refer
09. 註冊中心 Registry
10. 動態編譯 Compile
11. 動態代理 Proxy
12. 服務呼叫 Invoke
13. 呼叫特性
14. 過濾器 Filter
15. NIO 伺服器
16. P2P 伺服器
17. HTTP 伺服器
18. 序列化 Serialization
19. 叢集容錯 Cluster
20. 優雅停機
21. 日誌適配
22. 狀態檢查
23. 監控中心 Monitor
24. 管理中心 Admin
25. 運維命令 QOS
26. 鏈路追蹤 Tracing
… 一共 69+ 篇
目前在知識星球更新了《Netty 原始碼解析》目錄如下:
01. 除錯環境搭建
02. NIO 基礎
03. Netty 簡介
04. 啟動 Bootstrap
05. 事件輪詢 EventLoop
06. 通道管道 ChannelPipeline
07. 通道 Channel
08. 位元組緩衝區 ByteBuf
09. 通道處理器 ChannelHandler
10. 編解碼 Codec
11. 工具類 Util
… 一共 61+ 篇
目前在知識星球更新了《資料庫物體設計》目錄如下:
01. 商品模組
02. 交易模組
03. 營銷模組
04. 公用模組
… 一共 17+ 篇