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

不到 10 個提升逼格的 Redis 命令

點擊上方“芋道原始碼”,選擇“置頂公眾號”

技術文章第一時間送達!

原始碼精品專欄

 

來源:https://www.jianshu.com/p/4df5f2356de9

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命令的執行情況:

[[email protected] ~]# 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





如果你對 Dubbo / Netty 等等原始碼與原理感興趣,歡迎加入我的知識星球一起交流。長按下方二維碼噢

目前在知識星球更新了《Dubbo 原始碼解析》目錄如下:

01. 除錯環境搭建
02. 專案結構一覽
03. 配置 Configuration
04. 核心流程一覽

05. 拓展機制 SPI

06. 執行緒池

07. 服務暴露 Export

08. 服務取用 Refer

09. 註冊中心 Registry

10. 動態編譯 Compile

11. 動態代理 Proxy

12. 服務呼叫 Invoke

13. 呼叫特性 

14. 過濾器 Filter

15. NIO 服務器

16. P2P 服務器

17. HTTP 服務器

18. 序列化 Serialization

19. 集群容錯 Cluster

20. 優雅停機

21. 日誌適配

22. 狀態檢查

23. 監控中心 Monitor

24. 管理中心 Admin

25. 運維命令 QOS

26. 鏈路追蹤 Tracing

… 一共 69+ 篇

目前在知識星球更新了《Netty 原始碼解析》目錄如下:

01. 除錯環境搭建
02. NIO 基礎
03. Netty 簡介
04. 啟動 Bootstrap

05. 事件輪詢 EventLoop

06. 通道管道 ChannelPipeline

07. 通道 Channel

08. 位元組緩衝區 ByteBuf

09. 通道處理器 ChannelHandler

10. 編解碼 Codec

11. 工具類 Util

… 一共 61+ 篇

目前在知識星球更新了《資料庫物體設計》目錄如下:


01. 商品模塊
02. 交易模塊
03. 營銷模塊
04. 公用模塊

… 一共 17+ 篇

赞(0)

分享創造快樂