9個提升逼格的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) 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_hitskeyspace_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 100config 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,那對方一定眼前一亮,心裏對你豎起大拇指,但嘴上不會說。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章