9個提升逼格的redis命令

9個提升逼格的redis命令

keys

我把這個命令放在第一位,是因為筆者曾經做過的項目,以及一些朋友的項目,都因為使用 keys這個命令,導致出現性能毛刺。這個命令的時間複雜度是O(N),而且redis又是單線程執行,在執行keys時即使是時間複雜度只有O(1)例如SET或者GET這種簡單命令也會堵塞,從而導致這個時間點性能抖動,甚至可能出現timeout。

強烈建議生產環境屏蔽keys命令(後面會介紹如何屏蔽)。

scan

既然 keys 命令不允許使用,那麼有什麼代替方案呢?有!那就是 scan 命令。如果把keys命令比作類似 select*fromuserswhereusername like'%afei%' 這種 SQL ,那麼 scan 應該是 select*fromuserswhereid>?limit10 這種命令。

初始執行 scan 命令例如 scan0 。SCAN 命令是一個基於遊標的迭代器。這意味著命令每次被調用都需要使用上一次這個調用返回的遊標作為該次調用的遊標參數,以此來延續之前的迭代過程。當 SCAN 命令的遊標參數被設置為 0時,服務器將開始一次新的迭代,而當redis服務器向用戶返回值為0的遊標時,表示迭代已結束,這是唯一迭代結束的判定方式,而不能通過返回結果集是否為空判斷迭代結束。

slowlog

上面提到不能使用 keys 命令,如果就有開發這麼做了呢,我們如何得知?與其他任意存儲系統例如 mysql,mongodb 可以查看慢日誌一樣,redis 也可以,即通過命令 slowlog 。

subcommand 主要有:

  • get:用法:slowlog get [argument],獲取 argument 參數指定數量的慢日誌。
  • len:用法:slowlog len,總慢日誌數量。
  • reset:用法:slowlog reset,清空慢日誌。
命令耗時超過多少才會保存到 slowlog 中,可以通過命令 configsetslowlog-log-slower-than2000 配置並且不需要重啟 redis 。注意:單位是微妙,2000 微妙即 2 毫秒。

rename-command

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

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

bigkeys

隨著項目越做越大,緩存使用越來越不規範。我們如何檢查生產環境上一些有問題的數據。 bigkeys 就派上用場了。需要注意的是,這個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 環境 OPS 比較高,那麼建議結合 linux 管道命令優化,只輸出 keys 命令的執行情況。

info

如果說哪個命令能最全面反映當前 redis 運行情況,那麼非 info 莫屬。用法如下:

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 實例

例如: configsetslowlog-max-len100, configsetmaxclients1024

這樣修改的話,如果以後由於某些原因 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 命令也能提升逼格,你可能用的比較多的就是 setkey 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


分享到:


相關文章: