不到 10 个提升逼格的 Redis 命令
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)?22)?(integer)?15326562013)?(integer)?20334)?1)?"flushddbb" 2)?1)?(integer)?1??----??慢日志編碼,一般不用care2)?(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?keysysbigkeys
隨著項目越做越大,緩存使用越來越不規范。我們如何檢查生產環境上一些有問題的數據。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?items524?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?100set
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
總結
以上是生活随笔為你收集整理的不到 10 个提升逼格的 Redis 命令的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nginx 学习 —— 负载均衡
- 下一篇: MySQL 优化原理(一)