9個(gè)提升逼格的redis命令

keys

我把這個(gè)命令放在第一位,是因?yàn)楣P者曾經(jīng)做過的項(xiàng)目,以及一些朋友的項(xiàng)目,都因?yàn)槭褂?code>keys這個(gè)命令,導(dǎo)致出現(xiàn)性能毛刺。這個(gè)命令的時(shí)間復(fù)雜度是O(N),而且redis又是單線程執(zhí)行,在執(zhí)行keys時(shí)即使是時(shí)間復(fù)雜度只有O(1)例如SET或者GET這種簡單命令也會堵塞,從而導(dǎo)致這個(gè)時(shí)間點(diǎn)性能抖動,甚至可能出現(xiàn)timeout。

強(qiáng)烈建議生產(chǎn)環(huán)境屏蔽keys命令(后面會介紹如何屏蔽)。

scan

既然keys命令不允許使用,那么有什么代替方案呢?有!那就是scan命令。如果把keys命令比作類似select * from users where username like '%afei%'這種SQL,那么scan應(yīng)該是select * from users where id>? limit 10這種命令。

官方文檔用法如下:

SCAN cursor [MATCH pattern] [COUNT count]

初始執(zhí)行scan命令例如scan 0。SCAN命令是一個(gè)基于游標(biāo)的迭代器。這意味著命令每次被調(diào)用都需要使用上一次這個(gè)調(diào)用返回的游標(biāo)作為該次調(diào)用的游標(biāo)參數(shù),以此來延續(xù)之前的迭代過程。當(dāng)SCAN命令的游標(biāo)參數(shù)被設(shè)置為0時(shí),服務(wù)器將開始一次新的迭代,而當(dāng)redis服務(wù)器向用戶返回值為0的游標(biāo)時(shí),表示迭代已結(jié)束,這是唯一迭代結(jié)束的判定方式,而不能通過返回結(jié)果集是否為空判斷迭代結(jié)束。

使用方式:

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"

返回結(jié)果分為兩個(gè)部分:第一部分即1)就是下一次迭代游標(biāo),第二部分即2)就是本次迭代結(jié)果集。

slowlog

上面提到不能使用keys命令,如果就有開發(fā)這么做了呢,我們?nèi)绾蔚弥颗c其他任意存儲系統(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í)行結(jié)果如下:

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  ----  導(dǎo)致慢日志的命令執(zhí)行的時(shí)間點(diǎn),如果api有timeout,可以通過對比這個(gè)時(shí)間,判斷可能是慢日志命令執(zhí)行導(dǎo)致的
   3) (integer) 26424  ----  導(dǎo)致慢日志執(zhí)行的redis命令,通過4)可知,執(zhí)行config rewrite導(dǎo)致慢日志,總耗時(shí)26ms+
   4) 1) "config"
      2) "rewrite"

命令耗時(shí)超過多少才會保存到slowlog中,可以通過命令config set slowlog-log-slower-than 2000配置并且不需要重啟redis。注意:單位是微妙,2000微妙即2毫秒。

rename-command

為了防止把問題帶到生產(chǎn)環(huán)境,我們可以通過配置文件重命名一些危險(xiǎn)命令,例如keys等一些高危命令。操作非常簡單,只需要在conf配置文件增加如下所示配置即可:

rename-command flushdb flushddbb
rename-command flushall flushallall
rename-command keys keysys

bigkeys

隨著項(xiàng)目越做越大,緩存使用越來越不規(guī)范。我們?nèi)绾螜z查生產(chǎn)環(huán)境上一些有問題的數(shù)據(jù)。bigkeys就派上用場了,用法如下:

redis-cli -p 6380 --bigkeys

執(zhí)行結(jié)果如下:

... ...
-------- 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ù)結(jié)構(gòu)的數(shù)據(jù)。string類型有524個(gè),list類型有兩個(gè);通過Biggest ... ...可知,最大string結(jié)構(gòu)的key是test,最大list結(jié)構(gòu)的key是commentlist

需要注意的是,這個(gè)bigkeys得到的最大,不一定是最大。說明原因前,首先說明bigkeys的原理,非常簡單,通過scan命令遍歷,各種不同數(shù)據(jù)結(jié)構(gòu)的key,分別通過不同的命令得到最大的key:

  • 如果是string結(jié)構(gòu),通過strlen判斷;
  • 如果是list結(jié)構(gòu),通過llen判斷;
  • 如果是hash結(jié)構(gòu),通過hlen判斷;
  • 如果是set結(jié)構(gòu),通過scard判斷;
  • 如果是sorted set結(jié)構(gòu),通過zcard判斷。

正因?yàn)檫@樣的判斷方式,雖然string結(jié)構(gòu)肯定可以正確的篩選出最占用緩存,也可以說最大的key。但是list不一定,例如,現(xiàn)在有兩個(gè)list類型的key,分別是:numberlist--[0,1,2],stringlist--["123456789123456789"],由于通過llen判斷,所以numberlist要大于stringlist。而事實(shí)上stringlist更占用內(nèi)存。其他三種數(shù)據(jù)結(jié)構(gòu)hash,set,sorted set都會存在這個(gè)問題。使用bigkeys一定要注意這一點(diǎn)。

monitor

假設(shè)生產(chǎn)環(huán)境沒有屏蔽keys等一些高危命令,并且slowlog中還不斷有新的keys導(dǎo)致慢日志。那我們?nèi)绾尉境鲞@些命令是由誰執(zhí)行的呢?這就是monitor的用處,用法如下:

redis-cli -p 6380 monitor

如果當(dāng)前redis環(huán)境OPS比較高,那么建議結(jié)合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í)行結(jié)果中很清楚的看到keys命名執(zhí)行來源。通過輸出的IP和端口信息,就能在目標(biāo)服務(wù)器上找到執(zhí)行這條命令的進(jìn)程,揪出元兇,勒令整改。

info

如果說哪個(gè)命令能最全面反映當(dāng)前redis運(yùn)行情況,那么非info莫屬。用法如下:

INFO [section]

section可選值有:

  • Server:運(yùn)行的redis實(shí)例一些信息,包括:redis版本,操作系統(tǒng)信息,端口,GCC版本,配置文件路徑等;
  • Clients:redis客戶端信息,包括:已連接客戶端數(shù)量,阻塞客戶端數(shù)量等;
  • Memory:使用內(nèi)存,峰值內(nèi)存,內(nèi)存碎片率,內(nèi)存分配方式。這幾個(gè)參數(shù)都非常重要;
  • Persistence:AOF和RDB持久化信息;
  • Stats:一些統(tǒng)計(jì)信息,最重要三個(gè)參數(shù):OPS(instantaneous_ops_per_sec),keyspace_hitskeyspace_misses兩個(gè)參數(shù)反應(yīng)緩存命中率;
  • Replication:redis集群信息;
  • CPU:CPU相關(guān)信息;
  • Keyspace:redis中各個(gè)DB里key的信息;

config

config是一個(gè)非常有價(jià)值的命令,主要體現(xiàn)在對redis的運(yùn)維。因?yàn)樯a(chǎn)環(huán)境一般是不允許隨意重啟的,不能因?yàn)樾枰{(diào)優(yōu)一些參數(shù)就修改conf配置文件并重啟。redis作者早就想到了這一點(diǎn),通過config命令能熱修改一些配置,不需要重啟redis實(shí)例,可以通過如下命令查看哪些參數(shù)可以熱修改:

config get *

熱修改就比較容易了,執(zhí)行如下命令即可:

config set 

例如:config set slowlog-max-len 100config set maxclients 1024

這樣修改的話,如果以后由于某些原因redis實(shí)例故障需要重啟,那通過config熱修改的參數(shù)就會被配置文件中的參數(shù)覆蓋,所以我們需要通過一個(gè)命令將config熱修改的參數(shù)刷到redis配置文件中持久化,通過執(zhí)行如下命令即可:

config rewrite

執(zhí)行該命令后,我們能在config文件中看到類似這種信息:

# 如果conf中本來就有這個(gè)參數(shù),通過執(zhí)行config set,那么redis直接原地修改配置文件
maxclients 1024
# 如果conf中沒有這個(gè)參數(shù),通過執(zhí)行config set,那么redis會追加在Generated by CONFIG REWRITE字樣后面
# Generated by CONFIG REWRITE
save 600 60
slowlog-max-len 100

set

set命令也能提升逼格?是的,我本不打算寫這個(gè)命令,但是我見過太多人沒有完全掌握這個(gè)命令,官方文檔介紹的用法如下:

SET key value [EX seconds] [PX milliseconds] [NX|XX]

你可能用的比較多的就是set key value,或者SETEX key seconds value,所以很多同學(xué)用redis實(shí)現(xiàn)分布式鎖分為兩步:首先執(zhí)行SETNX key value,然后執(zhí)行EXPIRE key seconds。很明顯,這種實(shí)現(xiàn)有很嚴(yán)重的問題,因?yàn)閮刹綀?zhí)行不具備原子性,如果執(zhí)行第一個(gè)命令后出現(xiàn)某些未知異常導(dǎo)致無法執(zhí)行EXPIRE key seconds,那么分布式鎖就會一直無法得到釋放。

通過SET命令實(shí)現(xiàn)分布式鎖的正式姿勢應(yīng)該是SET key value EX seconds NX(EX和PX任選,取決于對過期時(shí)間精度要求)。另外,value也有要求,最好是一個(gè)類似UUID這種具備唯一性的字符串。當(dāng)然如果問你redis是否還有其他實(shí)現(xiàn)分布式鎖的方案。你能說出redlock,那對方一定眼前一亮,心里對你豎起大拇指,但嘴上不會說。

關(guān)于redis分布式鎖方案,強(qiáng)烈建議你閱讀redis官方文檔Redis分布式鎖:http://redis.cn/topics/distlock.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容