聊一聊Redis的離線分析

Catcher8發表於2022-04-18

背景

Redis 或許是我們大部分場景都會用到的一個利器,雖然是利器,用的姿勢不對的話,終究還是會整出么蛾子的。

比較常見的問題,不外乎記憶體暴增,慢查詢等情況。

那麼對於記憶體問題,可以藉助redis自帶的bigkey分析,也可以藉助一些第三方工具來進行離線分析,如 redis-rdb-tools 和 rdr。

為什麼是離線分析呢?

redis 在執行時,根據配置會生成一個 dump.rdb 的備份檔案,這個備份檔案是一個二進位制檔案,也是存在 redis 裡面的資料的一個快照。

離線分析,分析的就是這個 rdb 檔案。

受這兩個專案的啟發,老黃也用了好幾個週末的時間寫了個簡單的離線分析工具。

下面簡單介紹一下如何使用這個小工具。

rdb-tools

專案地址: https://github.com/catcherwong/rdb-tools

工具下載方式:

  1. 從 Github Release 下載最新穩定版本 https://github.com/catcherwong/rdb-tools/releases/
  2. 通過 nuget 下載安裝 https://www.nuget.org/packages/rdb-cli/

在 Github Release 下載的是無需執行時的單檔案,壓縮後是 5MB 左右,解壓後是 11MB 左右,需要根據不同的作業系統下載不同的可執行檔案,

nuget 的話,自然就是在安裝了 .net 6 的前提下, 通過 dotnet tool install 的方式來安裝

輸入 ./rdb-cli -h 可以看到幫助資訊。

其中最主要的還是 memory 命令。

從幫助資訊可以看到,需要指定 rdb 檔案,和一些特定的選項。

一個比較簡單常用的示例如下:

./rdb-cli memory /tmp/test/demo.rdb -ot html

這個會分析 demo.rdb ,同時分析結果以 html 的形式展現。

可以看到分析一個 2GB 的檔案,大概需要 32秒左右。

html 如下:

第一部分是基礎資訊,rdb 的版本資訊, redis 的版本資訊,總的記憶體,總的 key 數量。

第二部分是幾個柱狀圖,主要是不同資料型別的記憶體和數量分佈,以及過期時間的記憶體和數量分佈。

第三部分是幾個表格,前幾的 Key 字首列表、前幾的大 Key 列表、前幾的 Stream 列表,Function 列表(Redis 7.0)。

當然,如果想進行一些過濾,可以指定不同的引數選項即可。

只想分析 db 9 和 db 10

./rdb-cli memory /tmp/test/demo.rdb -ot html --db 9 --db 10

只想分析 hash 和 string 型別

./rdb-cli memory /tmp/test/demo.rdb -ot html --type string --type hash

rdb-tools 除了這個直接可用的 cli 工具外,還有一個 parser 的類庫,這個類庫就是解析的核心類庫, cli 也是基於這個做了一個 ReadCallback。

所以完全可以基於這個 parser 的類庫,打造一個自定義的離線分析工具。

一些細節

分析 rdb 檔案,其實就是分析一個二進位制檔案。

不同版本的 redis,其 rdb 檔案不一定一樣,畢竟 rdb 檔案也有版本的概念。

目前最新的 redis 7 ,rdb 的版本是 10,

redis 5.x ~ 6.x ,rdb 的版本則是 9 。

rdb-tools 裡面,是用 BinaryReader 來讀取 rdb 檔案的。

目前大部分 rdb 檔案的解析應該都是按照下面這個文件來的。

https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format

不過它目前還沒有包含 listpack 的解析。

最直觀的方式是對照 redis 原始碼裡面的 rdb.c 這個檔案。

https://github.com/redis/redis/blob/7.0-rc3/src/rdb.c

rdb 對數字這一塊的解碼操作要特別注意,不一定能用 BitConverter.ToIntXX 來獲得正確的值!!

另外有一些地方對大端和小端儲存也有區分,這個是很容易踩坑的地方。

記憶體資料統計的時候用的是生產者消費者模式(BlockingCollection),邊解析邊統計,避免一次性把 redis 的資料都載入到記憶體中,造成記憶體溢位。

目前解析一次,佔用的記憶體基本是在幾十M 左右。

總結

可能有人會問,為什麼已經有這樣的工具了,還要再寫一個?

主要是考慮到下面幾個吧

  1. 活躍度的問題和對新版 redis 的支援程度
  2. 自定義序列化這一塊的擴充套件性
  3. 不同領域的探索和社群支援

寫這麼一個工具,也加深了 redis 底層儲存和資料結構的一些認知。

感興趣的可以一起參與完善。

相關文章