解決了Redis大key問題,同事們都誇他牛皮

今天跟大家分享下,線上如何解決 Redis 中大 key 的方問題。

解決了Redis大key問題,同事們都誇他牛皮

什麼是大key

很多朋友肯定在想redis的key能有多大呀?

這裡就有個誤區了,

所謂的大key問題是某個key的value比較大,所以本質上是大value問題

這樣就對上了,key往往是程式可以自行設定的,value往往不受程式控制,因此可能導致value很大。

設想一種場景:

線上音樂app中,某個歌單有很多使用者收藏,假如有這樣的資料結構:

歌單和使用者之間的對映關係採用redis儲存

redis的key是歌單ID,長度可控且很小

redis的value是個list,list包含了使用者ID

使用者可能很多,就導致list長度不可控

這下明白啥是大key問題了吧!

解決了Redis大key問題,同事們都誇他牛皮

redis中有常見的幾種資料結構,每種結構對大key的定義不同,比如:

value是String型別時,size超過10KB

value是ZSET、Hash、List、Set等集合型別時,它的成員數量超過1w個

上述的定義並不絕對,主要是根據value的成員數量和位元組數來確定,業務可以根據自己的場景也確定標準

大key有什麼影響

我們都知道,redis的一個典型特徵就是:核心工作執行緒是單執行緒。

單執行緒中請求任務的處理是序列的,前面完不成,後面處理不了,同時也導致分散式架構中記憶體資料和CPU的不平衡。

執行大key命令的客戶端本身,耗時明顯增加,甚至超時

執行大key相關讀取或者刪除操作時,會嚴重佔用頻寬和CPU,影響其他客戶端

大key本身的儲存帶來分散式系統中分片資料不平衡,CPU使用率也不平衡

大key有時候也是熱key,讀取操作頻繁,影響面會很大

執行大key刪除時,在低版本redis中可能阻塞執行緒

這樣看來大key的影響還是很明顯的,

最典型的就是阻塞執行緒,併發量下降,導致客戶端超時,服務端業務成功率下降

大key是如何產生的

大key的產生往往是業務方設計不合理,沒有預見

value

的動態增長問題:

一直往value塞資料,沒有刪除機制,遲早要爆炸

資料沒有合理做分片,將大key變成小key

如何找到大key

增加記憶體&流量&超時等指標監控

由於大key的value很大,執行讀取時可能阻塞執行緒,這樣Redis整體的qps會下降,並且客戶端超時會增加,網路頻寬會上漲,配置這些報警可以讓我們發現大key的存在。

bigkeys命令

使用bigkeys命令以遍歷的方式分析Redis例項中的所有Key,並返回整體統計資訊與每個資料型別中Top1的大Key

解決了Redis大key問題,同事們都誇他牛皮

redis-rdb-tools

使用redis-rdb-tools離線分析工具來掃描RDB持久化檔案,雖然實時性略差,但是完全離線對效能無影響。

redis-rdb-tools是由Python寫的用來分析Redis的rdb快照檔案用的工具,它可以把rdb快照檔案生成json檔案或者生成報表用來分析Redis的使用詳情。

整合化視覺化工具

基於某些公有云或者公司內部架構的redis一般都會有視覺化的頁面和分析工具,來幫助我們定位大key,當然頁面底層也可能是基於bigkeys或者rdb檔案離線分析的結果。

解決了Redis大key問題,同事們都誇他牛皮

如何解決大key問題

根據大key的實際用途可以分為兩種情況:可刪除和不可刪除。

解決了Redis大key問題,同事們都誇他牛皮

刪除大key

如果發現某些大key並非熱key就可以在DB中查詢使用,則可以在Redis中刪掉:

當Redis版本大於4。0時,可使用UNLINK命令安全地刪除大Key,該命令能夠以非阻塞的方式,逐步地清理傳入的Key。

Redis UNLINK 命令類似與 DEL 命令,表示刪除指定的 key,如果指定 key 不存在,命令則忽略。

UNLINK 命令不同與 DEL 命令在於它是非同步執行的,因此它不會阻塞。

UNLINK 命令是非阻塞刪除,非阻塞刪除簡言之,就是將刪除操作放到另外一個執行緒去處理。

當Redis版本小於4。0時,避免使用阻塞式命令KEYS,而是建議透過SCAN命令執行增量迭代掃描key,然後判斷進行刪除。

Redis Scan 命令用於迭代資料庫中的資料庫鍵。

SCAN 命令是一個基於遊標的迭代器,每次被呼叫之後, 都會向用戶返回一個新的遊標, 使用者在下次迭代時需要使用這個新遊標作為 SCAN 命令的遊標引數, 以此來延續之前的迭代過程。

解決了Redis大key問題,同事們都誇他牛皮

壓縮和拆分key

value

是string時,比較難拆分,則使用序列化、壓縮演算法將key的大小控制在合理範圍內,但是序列化和反序列化都會帶來更多時間上的消耗。

當value是string,壓縮之後仍然是大key,則需要進行拆分,一個大key分為不同的部分,記錄每個部分的key,使用multiget等操作實現事務讀取。

當value是list/set等集合型別時,根據預估的資料規模來進行分片,不同的元素計算後分到不同的片。

小結

Redis的大key問題,無論在面試還是工作中都很常見,好好理解一波,非常值得。祝各位老鐵 深夜無報警,線上無bug!