詳解redis big key 排查思路
今天在秦曉輝的運維系統(tǒng)監(jiān)控專欄交流群中,看到了幾位朋友在討論redis big key 掃描的方案。不自覺的來了興致,參與了討論。
并且有一些比較奇特的思路。
定義big key
為了讓對redis較為陌生的朋友不清楚big key的含義有一定的認知。我們先來定義一下Big Key。
一切因為大,而導致redis去執(zhí)行命令,網(wǎng)絡(luò)傳輸而導致慢的key,都可以稱為Big Key。
- 一個String的值特別大
- 一個List的元素特別多
- 一個Hash的元素特別多
- List、Hash中某個元素特別大
都可以稱為Big Key。
那具體,多大才算大呢?那其實要看你具體業(yè)務(wù)的容忍度了,并不是一個很嚴格的限制。
這是我在知乎上看到一個博主對Big Key 大小的定義:
- 一個STRING類型的Key,它的值為5MB(數(shù)據(jù)過大)
- 一個LIST類型的Key,它的列表數(shù)量為20000個(列表數(shù)量過多)
- 一個ZSET類型的Key,它的成員數(shù)量為10000個(成員數(shù)量過多)
- 一個HASH格式的Key,它的成員數(shù)量雖然只有1000個但這些成員的value總大小為100MB(成員體積過大)
我個人認為他對這個值度量定義的門檻頗低了,我目前開發(fā)維護的系統(tǒng)中,對一個String的Key,認為超過100KB就開始算大,超過1MB是嚴禁發(fā)生的。
如何排查Big Key
那如何排查Big Key呢?何時排查Big Key呢?
一般情況下,我們應該在第一次上生產(chǎn)之前,對系統(tǒng)進行全面的各項測試,其中就應該包括Big Key 的排查。
其次,就是在生產(chǎn)運行中,也許我們測試不夠全面、也許多次迭代下來會有新的Big Key,我們應該由監(jiān)控系統(tǒng)進行掃描排查。
對于Big Key的排查來說,那應該就是把所有的Key,按照我們的閾值進行比對其占用的內(nèi)存大小,判斷其是否為Big Key。
而我們知道,對于Redis 這種高性能內(nèi)存緩存來說,我們都盡量使用一個O(1)算法復雜度的命令來調(diào)用,性能最佳。
而全部Key進行掃描,顯然是一個O(n)的復雜度,將會阻塞Redis 相當長的時間。
而群里的討論點在于:在壓測的過程中,對redis big key進行掃描,并且盡量不影響性能。
那讓我們來看看傳統(tǒng)的方案,以及個人的奇思妙想。
官方解決方案
在官方文檔 Scanning for big keys中如下描述:
In this special mode, redis-cli works as a key space analyzer. It scans the dataset for big keys, but also provides information about the data types that the data set consists of. This mode is enabled with the --bigkeys option, and produces verbose output.
$ redis-cli --bigkeys [00.00%] Biggest string found so far 'key-419' with 3 bytes [05.14%] Biggest list found so far 'mylist' with 100004 items [35.77%] Biggest string found so far 'counter:__rand_int__' with 6 bytes [73.91%] Biggest hash found so far 'myobject' with 3 fields -------- summary ------- Sampled 506 keys in the keyspace! Total key length in bytes is 3452 (avg len 6.82) Biggest string found 'counter:__rand_int__' has 6 bytes Biggest list found 'mylist' has 100004 items Biggest hash found 'myobject' has 3 fields 504 strings with 1403 bytes (99.60% of keys, avg size 2.78) 1 lists with 100004 items (00.20% of keys, avg size 100004.00) 0 sets with 0 members (00.00% of keys, avg size 0.00) 1 hashs with 3 fields (00.20% of keys, avg size 3.00) 0 zsets with 0 members (00.00% of keys, avg size 0.00)
也就是使用redis-cli --bigkeys
命令進行掃描,并會按照strings、lists、sets、hashs、zsets統(tǒng)計。
The program uses the SCAN command, so it can be executed against a busy server without impacting the operations, however the -i option can be used in order to throttle the scanning process of the specified fraction of second for each SCAN command.
這個命令是通過SCAN
指令進行實現(xiàn)的,并不是一次性直接對redis完成掃描,對于已經(jīng)繁忙(處于)壓測的服務(wù)器不會完全影響業(yè)務(wù)進行。
但是實際上,也會有一定的性能影響。這個方案,也是這位測開朋友在壓測時采用的方案。
不過,他忽略了(當然,早期的客戶端不一定支持這一參數(shù))可以使用 -i 0.01
參數(shù)可以更好的降低對redis服務(wù)器處理業(yè)務(wù)請求的影響。-i 0.01
代表著redis-cli這一客戶端在每執(zhí)行一次SCAN
指令后,會暫停0.01秒的時間。
這一參數(shù)會導致big key 掃描本身耗時有一定增加,但是對redis服務(wù)器的壓力就是降低許多,畢竟0.01秒對redis這種高性能的中間件來說,已經(jīng)是一段不斷的時間了。
所以,就目前來說,最方便也最穩(wěn)妥的方式就是redis-cli --bigkeys -i 0.01
。
解析RDB文件并統(tǒng)計
RDB文件作為redis的一個全量持久化文件。通過下載并對他的解析統(tǒng)計Big Key,這對Redis服務(wù)器的資源則沒有任何消耗,是十分合理的。
但是若是為了掃描Big Key,在壓測環(huán)境下執(zhí)行BGSAVE
這樣的持久化指令,其fork進程的過程也會產(chǎn)生一定的阻塞,在Redis對他的標記上,也是@slow的。
所以掃描一個已經(jīng)產(chǎn)生的RDB文件是可取的,特意去持久化一次,理論上對Redis產(chǎn)生的阻塞也是不小的。那具體其耗時如何,也未進行實驗驗證。
而這樣的一個工具:redis-rdb-tools 在github上也擁有4.8K的star,想必使用的用戶也是不少的。
但是,我注意到了一點,這個工程最后一次提交在2020年。
而截止目前,redis在其后已經(jīng)相繼發(fā)布了redis 6、redis 7等更高的版本,并且對于RDB文件的格式,在redis 7.0 已經(jīng)更新到了format 10。
這一“年久失修”的redis-rdb-tools 未必能夠解析新版本的RDB文件。
網(wǎng)絡(luò)統(tǒng)計
個人突發(fā)奇想,若是在網(wǎng)絡(luò)層面上,通過抓包進行分析,對redis的TCP報文進行復制,然后使用Redis對應版本的RESP2、RESP3報文解析,不就可以分析這段時間內(nèi),客戶端獲取過的Big Key了嗎?
這樣對redis服務(wù)器的CPU等資源就沒有什么消耗了。
當然,這個方案也有很明顯的缺點,除了需要自行編寫工具去分析以外,還存在很多分析不到的位置。
例如一個LRANGE指令,對指定key的list進行范圍掃描并返回:
LRANGE key start stop
它的復雜度是O(S+N),其中S的復雜度與列表的HEAD或者TAIL的距離有關(guān),而N則是范圍內(nèi)元素的個數(shù)。
所以當S很大,而N很小的時候,返回給客戶端的數(shù)據(jù)量,其實還是小的,而它可能是一個Big Key,但是我們這個方案是沒有機會發(fā)現(xiàn)它了。
新增從節(jié)點
個人覺得這是一個很妙的方式,具有可行性,但是也比較浪費,意義不是十分大的方案。
我們可以在壓測開始前,通過slave of 命令,將我們新起的一個redis節(jié)點作為壓測節(jié)點的從節(jié)點。并且這個節(jié)點對應用不可見。
那么我們在這個節(jié)點上進行big key的統(tǒng)計,就對業(yè)務(wù)沒有任何影響了。
總結(jié)
官方提供的方式:redis-cli --bigkeys -i 0.01
應該是處理運行中的 redis big key 掃描的最佳方案了,當然,我們盡量避免高峰期去執(zhí)行。
到此這篇關(guān)于詳解redis big key 排查思路的文章就介紹到這了,更多相關(guān)redis big key 排查內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis集群增加節(jié)點與刪除節(jié)點的方法詳解
這篇文章主要給大家介紹了關(guān)于Redis集群增加節(jié)點與刪除節(jié)點的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-09-09redis底層數(shù)據(jù)結(jié)構(gòu)之ziplist實現(xiàn)詳解
這篇文章主要為大家介紹了redis底層數(shù)據(jù)結(jié)構(gòu)之ziplist實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12Redis報錯UnrecognizedPropertyException: Unrecognized 
在使用SpringBoot訪問Redis時,報錯提示識別不了屬性headPart,經(jīng)過排查,發(fā)現(xiàn)并非Serializable或getset方法問題,而是存在一個方法getHeadPart,但無headPart屬性,解決方案是將getHeadPart改為makeHeadPart2024-10-10