keys
我把這個命令放在第一位淘捡,是因為筆者曾經(jīng)做過的項目藕各,以及一些朋友的項目,都因為使用keys
這個命令焦除,導致出現(xiàn)性能毛刺激况。這個命令的時間復雜度是O(N),而且redis又是單線程執(zhí)行膘魄,在執(zhí)行keys時即使是時間復雜度只有O(1)例如SET或者GET這種簡單命令也會堵塞乌逐,從而導致這個時間點性能抖動,甚至可能出現(xiàn)timeout创葡。
強烈建議生產(chǎn)環(huán)境屏蔽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]
初始執(zhí)行scan命令例如scan 0
。SCAN命令是一個基于游標的迭代器棘幸。這意味著命令每次被調用都需要使用上一次這個調用返回的游標作為該次調用的游標參數(shù)焰扳,以此來延續(xù)之前的迭代過程。當SCAN命令的游標參數(shù)被設置為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命令停蕉,如果就有開發(fā)這么做了呢,我們如何得知钙态?與其他任意存儲系統(tǒng)例如mysql慧起,mongodb可以查看慢日志一樣,redis也可以册倒,即通過命令slowlog
蚓挤。用法如下:
SLOWLOG subcommand [argument]
subcommand主要有:
- get,用法:slowlog get [argument]驻子,獲取argument參數(shù)指定數(shù)量的慢日志灿意。
- len,用法:slowlog len崇呵,總慢日志數(shù)量缤剧。
- reset,用法:slowlog reset域慷,清空慢日志荒辕。
執(zhí)行結果如下:
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 ---- 導致慢日志的命令執(zhí)行的時間點犹褒,如果api有timeout抵窒,可以通過對比這個時間,判斷可能是慢日志命令執(zhí)行導致的
3) (integer) 26424 ---- 導致慢日志執(zhí)行的redis命令叠骑,通過4)可知李皇,執(zhí)行config rewrite導致慢日志,總耗時26ms+
4) 1) "config"
2) "rewrite"
命令耗時超過多少才會保存到slowlog中宙枷,可以通過命令
config set slowlog-log-slower-than 2000
配置并且不需要重啟redis掉房。注意:單位是微妙,2000微妙即2毫秒朦拖。
rename-command
為了防止把問題帶到生產(chǎn)環(huán)境圃阳,我們可以通過配置文件重命名一些危險命令厌衔,例如keys
等一些高危命令璧帝。操作非常簡單,只需要在conf配置文件增加如下所示配置即可:
rename-command flushdb flushddbb
rename-command flushall flushallall
rename-command keys keysys
bigkeys
隨著項目越做越大富寿,緩存使用越來越不規(guī)范睬隶。我們如何檢查生產(chǎn)環(huán)境上一些有問題的數(shù)據(jù)。bigkeys
就派上用場了页徐,用法如下:
redis-cli -p 6380 --bigkeys
執(zhí)行結果如下:
... ...
-------- 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幾種數(shù)據(jù)結構的數(shù)據(jù)。string類型有524個变勇,list類型有兩個恤左;通過Biggest ... ...
可知贴唇,最大string結構的key是test
,最大list結構的key是commentlist
飞袋。
需要注意的是戳气,這個bigkeys得到的最大,不一定是最大巧鸭。說明原因前瓶您,首先說明bigkeys
的原理,非常簡單纲仍,通過scan命令遍歷呀袱,各種不同數(shù)據(jù)結構的key,分別通過不同的命令得到最大的key:
- 如果是string結構郑叠,通過
strlen
判斷夜赵; - 如果是list結構,通過
llen
判斷乡革; - 如果是hash結構油吭,通過
hlen
判斷; - 如果是set結構署拟,通過
scard
判斷婉宰; - 如果是sorted set結構,通過
zcard
判斷推穷。
正因為這樣的判斷方式心包,雖然string結構肯定可以正確的篩選出最占用緩存,也可以說最大的key馒铃。但是list不一定蟹腾,例如,現(xiàn)在有兩個list類型的key区宇,分別是:numberlist--[0,1,2]娃殖,stringlist--["123456789123456789"],由于通過llen判斷议谷,所以numberlist要大于stringlist炉爆。而事實上stringlist更占用內存。其他三種數(shù)據(jù)結構hash卧晓,set芬首,sorted set都會存在這個問題。使用bigkeys一定要注意這一點逼裆。
monitor
假設生產(chǎn)環(huán)境沒有屏蔽keys等一些高危命令郁稍,并且slowlog中還不斷有新的keys導致慢日志。那我們如何揪出這些命令是由誰執(zhí)行的呢胜宇?這就是monitor
的用處耀怜,用法如下:
redis-cli -p 6380 monitor
如果當前redis環(huán)境OPS比較高恢着,那么建議結合linux管道命令優(yōu)化,只輸出keys命令的執(zhí)行情況:
[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*"
執(zhí)行結果中很清楚的看到keys命名執(zhí)行來源财破。通過輸出的IP和端口信息然评,就能在目標服務器上找到執(zhí)行這條命令的進程,揪出元兇狈究,勒令整改碗淌。
info
如果說哪個命令能最全面反映當前redis運行情況,那么非info莫屬抖锥。用法如下:
INFO [section]
section可選值有:
- Server:運行的redis實例一些信息亿眠,包括:redis版本,操作系統(tǒng)信息磅废,端口纳像,GCC版本,配置文件路徑等拯勉;
- Clients:redis客戶端信息竟趾,包括:已連接客戶端數(shù)量,阻塞客戶端數(shù)量等宫峦;
- Memory:使用內存岔帽,峰值內存,內存碎片率导绷,內存分配方式犀勒。這幾個參數(shù)都非常重要;
- Persistence:AOF和RDB持久化信息妥曲;
-
Stats:一些統(tǒng)計信息贾费,最重要三個參數(shù):OPS(
instantaneous_ops_per_sec
),keyspace_hits
和keyspace_misses
兩個參數(shù)反應緩存命中率檐盟; - Replication:redis集群信息褂萧;
- CPU:CPU相關信息;
- Keyspace:redis中各個DB里key的信息葵萎;
config
config是一個非常有價值的命令导犹,主要體現(xiàn)在對redis的運維。因為生產(chǎn)環(huán)境一般是不允許隨意重啟的陌宿,不能因為需要調優(yōu)一些參數(shù)就修改conf配置文件并重啟锡足。redis作者早就想到了這一點,通過config命令能熱修改一些配置壳坪,不需要重啟redis實例,可以通過如下命令查看哪些參數(shù)可以熱修改:
config get *
熱修改就比較容易了掰烟,執(zhí)行如下命令即可:
config set
例如:config set slowlog-max-len 100
爽蝴,config set maxclients 1024
這樣修改的話沐批,如果以后由于某些原因redis實例故障需要重啟,那通過config熱修改的參數(shù)就會被配置文件中的參數(shù)覆蓋蝎亚,所以我們需要通過一個命令將config熱修改的參數(shù)刷到redis配置文件中持久化九孩,通過執(zhí)行如下命令即可:
config rewrite
執(zhí)行該命令后,我們能在config文件中看到類似這種信息:
# 如果conf中本來就有這個參數(shù)发框,通過執(zhí)行config set躺彬,那么redis直接原地修改配置文件
maxclients 1024
# 如果conf中沒有這個參數(shù),通過執(zhí)行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實現(xiàn)分布式鎖分為兩步:首先執(zhí)行SETNX key value
缔刹,然后執(zhí)行EXPIRE key seconds
。很明顯劣针,這種實現(xiàn)有很嚴重的問題校镐,因為兩步執(zhí)行不具備原子性,如果執(zhí)行第一個命令后出現(xiàn)某些未知異常導致無法執(zhí)行EXPIRE key seconds
捺典,那么分布式鎖就會一直無法得到釋放灭翔。
通過SET
命令實現(xiàn)分布式鎖的正式姿勢應該是SET key value EX seconds NX
(EX和PX任選,取決于對過期時間精度要求)辣苏。另外肝箱,value也有要求,最好是一個類似UUID這種具備唯一性的字符串稀蟋。當然如果問你redis是否還有其他實現(xiàn)分布式鎖的方案煌张。你能說出redlock,那對方一定眼前一亮退客,心里對你豎起大拇指骏融,但嘴上不會說。
關于redis分布式鎖方案萌狂,強烈建議你閱讀redis官方文檔Redis分布式鎖:http://redis.cn/topics/distlock.html