標籤:
Redis資料匯入工具最佳化過程總結 背景
使用C++開發了一個Redis資料匯入工具
從oracle中將所有表資料匯入到redis中;
不是單純的資料匯入,每條oracle中的原有記錄,需要經過商務邏輯處理,
並添加索引(redis集合);
工具完成後,效能是個瓶頸;
最佳化效果
使用了2個樣本資料測試:
樣本資料a表8763 條記錄;
b表940279 條記錄;
最佳化前,a表耗時11.417s;
最佳化後,a表耗時1.883s;
用到的工具
gprof, pstrace,time
使用time工具查看每次執行的耗時,分別包含使用者時間和系統時間;
使用pstrace列印即時運行,查詢進程主要的系統調用,發現耗時點;
使用gprof統計程式的耗時匯總,集中精力最佳化最耗時的地方;
使用簡介:
1.對g++的所有編輯和串連選項都必須要加上-pg(第一天由於沒有在串連處加上-pg選項,導致無法出統計報告);
2.執行完程式後,本目錄會產生gmon.out檔案;
3.gprof redistool gmou.out > report,產生可讀檔案report,開啟report集中最佳化最耗時的函數;
最佳化過程
最佳化前11.417s:
time ./redistool im a a.csvreal 0m11.417suser 0m6.035ssys 0m4.782s (發現系統調用時間過長)
檔案記憶體映射
系統調用時間過長,主要是檔案讀寫,初步考慮是讀取檔案時,調用api次數過於頻繁;
讀取樣本採用的是檔案fgets一行行的讀取,採用檔案記憶體映射mmap後,可直接使用指標操作整個檔案記憶體快;
日誌開關提前
改進了檔案讀寫後,發現最佳化效果比較有限(提高了2s左右);fgets是C的檔案讀取庫函數,相比系統read(),是帶了緩衝區了,應該不會太慢(網上有人測試,檔案記憶體映射相比fgets()能快上一個數量級,感覺情境應該比較特殊);
之後通過pstrace工具發現log.dat開啟次數過多;原來是調試日誌的開關寫到了後面,導致 調試日誌都是會開啟記錄檔open("log.dat");
將日誌開關提前;改進後,3.53s
time ./redistool im a a.csvreal 0m3.530suser 0m2.890ssys 0m0.212s
vector空間預先分配
後續通過gprof分析,某個函數的vector記憶體配置次數多,並有不少複製次數:
改進以下這行代碼:
vector <string> vSegment;
使用靜態vector變數,並預先分配記憶體:
static vector <string> vSegment;vSegment.clear();static int nCount = 0;if( 0 == nCount){ vSegment.reserve(64);}++nCount;
最佳化後,提升至2.286s
real 0m2.286suser 0m1.601ssys 0m0.222s
同樣,另外一個類中的成員vector也使用預先分配空間(在建構函式中):
m_vtPipecmd.reserve(256);
最佳化後,提升至2.166s;
real 0m2.166suser 0m1.396ssys 0m0.204s
函數改寫 && 內聯
繼續執行程式,發現SqToolStrSplitByCh()函數消耗過大,改寫整個函數邏輯,並將改寫後的函數內聯:
最佳化後,提升至1.937s
real 0m1.937suser 0m1.301ssys 0m0.186s
去除調試符和最佳化監測符號
最後,去掉debug和pg偵錯符號後,最終效果為1.883s;
real 0m1.883suser 0m1.239ssys 0m0.191s
滿足生產要求
以上最後幾步看似毫秒級的提升,擴大到全表資料後,效果就很明顯了;
最佳化後,生產上a表為152w,匯入耗時大約326s(~6分鐘);
b表資料420w,匯入耗時大約1103s(~18分鐘)
Posted by: 大CC | 28JUN,2015
部落格:blog.me115.com [訂閱]
Github:大CC
Redis資料匯入工具最佳化過程總結