最近發現項目中用的 redis
內存消耗很大(可是印象中卻覺得沒有這麼多的key的內存消耗纔對呀?),使用 info
命令能夠看到全部key佔用的一些內存大小以及key的數量等等,以下圖所示(只截圖了memory和keyspace部分):python
能夠發現, info
命令只能看到總的內存大小以及key的數量等。這些對於分析到底哪些或哪類key佔用的內存較大是遠遠不夠的!mysql
工欲善其事必先利其器!git
在各類google搜索以後,發現有一個工具貌似是能夠的: redis-rdb-tools 。github
因而分頭行動,redis
根據該工具 , 能夠將 rdb 快照文件轉換爲 csv 格式文件:sql
拿到csv文件後有兩種作法,docker
pandas
庫分塊讀取csv文件,能夠作一些統計、過濾等操做(幾乎有與等價於sql的api操做方式。(這裏由於是操做的內部的業務數據,有些數據細節不便公開,僅貼出相關重要命令以及一些踩坑後的經驗方法等)shell
# 1. 先運行一個python docker容器(注意將rdb文件掛載進去) docker run -it -v YOUR_PATH/xxx.rdb:/data/xxx.rdb python bash # 2. 安裝rdb tools pip install rdbtools python-lzf # 3. 執行rdb 轉爲csv命令 (此過程根據rdb文件大小時間不定) rdb -c memory /data/xxx.rdb -f memory.csv
上述命令中有些路徑和名稱注意替換爲你本身真實的值。數據庫
話說這裏也是個坑來着,在往 postgres
數據庫導入csv數據時,報了一個大概意思是 「實際的列個數和期待的列個數不匹配」錯誤。 可能rdb tools在轉換的時候某些行的值有點問題,或者其餘bug致使。 這裏鑑於有異常的數據條數很少,不用太過於深究,直接用 pandas
簡單清洗一下便可。api
相關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會自動忽略有問題的行。接着用分塊的方式讀完全部內容,最後合併而後寫到新文件。
此步驟其實理論上非必須的,上文說到其實能夠直接用 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;
如今問題會比較簡單了,這裏由於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等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!