歡迎光臨
每天分享高質量文章

9個提升逼格的Redis命令

來自:阿飛Javaer(微訊號:AfeiJavaer)

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
11) (integer2
   2) (integer1532656201
   3) (integer2033
   41"flushddbb"
21) (integer1  ----  慢日誌編碼,一般不用care
   2) (integer1532646897  ----  導致慢日誌的命令執行的時間點,如果api有timeout,可以透過對比這個時間,判斷可能是慢日誌命令執行導致的
   3) (integer26424  ----  導致慢日誌執行的redis命令,透過4)可知,執行config rewrite導致慢日誌,總耗時26ms+
   41"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.62of keys, avg size 28.97)
2 lists with 19 items (00.38of keys, avg size 9.50)
0 sets with 0 members (00.00of keys, avg size 0.00)
0 hashs with 0 fields (00.00of keys, avg size 0.00)
0 zsets with 0 members (00.00of 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,那對方一定眼前一亮,心裡對你豎起大拇指,但嘴上不會說。

關於redis分散式鎖方案,強烈建議你閱讀redis官方檔案Redis分散式鎖:http://redis.cn/topics/distlock.html


●編號384,輸入編號直達本文

●輸入m獲取文章目錄

推薦↓↓↓

Web開發

更多推薦18個技術類公眾微信

涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。

贊(0)

分享創造快樂