Redis記憶體空間簡單分析
背景
最近發現專案中用的 redis
記憶體消耗很大(但是印象中卻以為沒有這麼多的key的記憶體消耗才對呀?),使用 info
命令可以看到所有key佔用的一些記憶體大小以及key的數量等等,如下圖所示(只截圖了memory和keyspace部分):
可以發現, info
命令只能看到總的記憶體大小以及key的數量等。這些對於分析到底哪些或哪類key佔用的記憶體較大是遠遠不夠的!
工具調研
工欲善其事必先利其器!
在各種google搜尋之後,發現有一個工具貌似是可以的: redis-rdb-tools 。
於是分頭行動,
- 讓運維將線上rdb快照檔案用scp拷貝到一臺測試機上(畢竟在線上機器上操作是不太安全的)
- 我需要用最快最乾淨的方式來安裝一下rdb工具,這裡選擇直接在python docker中裝。
分析之路
根據該工具 文件描述 , 可以將 rdb 快照檔案轉換為 csv 格式檔案:
拿到csv檔案後有兩種做法,
- 直接用python
pandas
庫分塊讀取csv檔案,可以做一些統計、過濾等操作(幾乎有與等價於sql的api操作方式,具體操作可以參考這篇文章: 【分析篇】:Pandas像sql操作python 進行資料分析 。 - 將csv匯入到關係型資料庫,用sql來操作,比較靈活 。關於資料庫選型:在試驗過mysql和postgres兩款關係型資料庫後,感觸挺深, mysql單表匯入完上面csv中大概3億多條資料後,查詢直接癱瘓!postgres匯入資料後依然堅挺(平均一條like 查詢十幾秒左右,還是可以接受的!)。
just try!
rdb 檔案轉換為csv
(這裡因為是操作的內部的業務資料,有些資料細節不便公開,僅貼出相關重要命令以及一些踩坑後的經驗方法等)
# 1. 先執行一個python docker容器(注意將rdb檔案掛載進去) docker run-it -v YOUR_PATH/xxx.rdb:/data/xxx.rdbpython bash # 2. 安裝rdb tools pip install rdbtools python-lzf # 3. 執行rdb 轉為csv命令 (此過程根據rdb檔案大小時間不定) rdb -c memory /data/xxx.rdb-f memory.csv
上述命令中有些路徑和名稱注意替換為你自己真實的值。
csv 簡單清洗
話說這裡也是個坑來著,在往 postgres
資料庫匯入csv資料時,報了一個大概意思是 “實際的列個數和期待的列個數不匹配”錯誤。 可能rdb tools在轉換的時候某些行的值有點問題,或者其他bug導致。 這裡鑑於有異常的資料條數不多,不用太過於深究,直接用 pandas
簡單清洗一下即可。
相關python程式碼如下:
import pandas as pd import numpy as np reader = pd.read_csv('/xxxx/memory.csv', iterator=True,error_bad_lines=False) loop = True chunkSize =10000000 chunks=[] total_bytes=0 while loop: try: chunk = reader.get_chunk(chunkSize) chunks.append(chunk) except StopIteration: loop = False print("Iteration is stopped.") df = pd.concat(chunks, ignore_index=True) df.to_csv('/xxx/memory2.csv', sep=',', encoding='utf-8')
大概解釋下,這裡先讀取csv檔案,指定選項 error_bad_lines=False
,則pandas會自動忽略有問題的行。接著用分塊的方式讀完所有內容,最後合併然後寫到新檔案。
csv匯入postgres
此步驟其實理論上非必須的,上文說到其實可以直接用 pandas
操作csv幾乎可以完成跟sql類似的分析效果。 但比較還是直接用sql比較方便,還是導到資料庫來的實惠。
# 1. 執行postgres docker容器(記得把上面步驟中轉換得到的csv檔案掛載進去) docker run --name postgres -v /xxx/memory2.csv:/memory.csv-d postgres:9.6 # 2. 進入postgres容器內部 psql shell docker exec -it postgres psql -U postgres # 3. 建立臨時表 (建議是所有欄位是用text,否則匯入可能會遇到轉型錯誤,第一個欄位index是pandas帶進來的,可以匯出csv時處理下) postgres=# create table keys_dump( index integer, database text, type text, key text, size_in_bytes text, encoding text, num_elements text, len_largest_element text, expiry text ); # 4. 執行匯入csv檔案命令 postgres=# COPY keys_dump FROM '/memory.csv' WITH csv;
sql分析
現在問題會比較簡單了,這裡因為key中涉及到一些實際業務值,下面只是簡單列舉一下比如統計 string
型別的key佔用的總記憶體大小:
select sum(size_in_bytes::int) from keys_dump where type='text';
諸如此類的sql,根據你的實際場景,比如按key中某關鍵詞進行like查詢:
select sum(size_in_bytes::int) from keys_dump where type='text' and key like 'xxxx%';
或者來個統計單key大小前10條:
select *from keys_dump order by size_in_bytes::int desc limit 10;
以上sql語句,我自己都試過,在單表3億多的行數中執行,總時間大概10幾到二十幾秒左右,整體速度還是讓人能接受的,畢竟只是做下離線分析。
總結
以上僅提供redis記憶體分析的一個簡單思路,大體是: rdb–> csv –> sql 。如果你有更好的方式,歡迎在文章下方評論留言!