天天看點

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操作方式)。

将csv導入到關系型資料庫,用sql來操作,比較靈活 。關于資料庫選型:在試驗過mysql和postgres兩款關系型資料庫後,感觸挺深, mysql單表導入完上面csv中大概3億多條資料後,查詢直接癱瘓!postgres導入資料後依然堅挺(平均一條like 查詢十幾秒左右,還是可以接受的!)。

just try!

rdb 檔案轉換為csv

(這裡因為是操作的内部的業務資料,有些資料細節不便公開,僅貼出相關重要指令以及一些踩坑後的經驗方法等)

docker run -it -v your_path/xxx.rdb:/data/xxx.rdb python bash

pip install rdbtools python-lzf

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比較友善,還是導到資料庫來的實惠。

docker run --name postgres -v /xxx/memory2.csv:/memory.csv -d postgres:9.6

docker exec -it postgres psql -u postgres

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

);

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幾到二十幾秒左右,整體速度還是讓人能接受的,畢竟隻是做下離線分析。

歡迎工作一到五年的java工程師朋友們加入java架構開發: 855835163

群内提供免費的java架構學習資料(裡面有高可用、高并發、高性能及分布式、jvm性能調優、spring源碼,mybatis,netty,redis,kafka,mysql,zookeeper,tomcat,docker,dubbo,nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

繼續閱讀