針對GZIP文件類型的並行讀取

原文鏈接:[url]http://click.aliyun.com/m/26743/[/url]
摘要: 一,前言 GZIP是最常見的壓縮文件格式,目前DataX是支持對該壓縮文件直接的讀取,但每個GZIP僅僅只能啓動一個線程來讀取,當GZIP比較大,或者說針對GZIP中的數據有着較複雜的操作的情況下,執行效率往往比較低下。

一,前言
GZIP是最常見的壓縮文件格式,目前DataX是支持對該壓縮文件直接的讀取,但每個GZIP僅僅只能啓動一個線程來讀取,當GZIP比較大,或者說針對GZIP中的數據有着較複雜的操作的情況下,執行效率往往比較低下。下面就討論下如何對針對GZIP文件類型的並行讀取,大幅度提高執行效率。

二,簡單測試
首先對一個GZIP文件進行解壓縮的測試:

$ll -h event_custom_json_201705161100.0.log.gz
-rw-r--r-- 1 weiguang.sunwg users 18M May 26 21:44 event_custom_json_201705161100.0.log.gz
該壓縮文件大小爲18MB,測試解壓縮的時間:

$time gzip -d event_custom_json_201705161100.0.log.gz

real 0m1.879s
user 0m1.550s
sys 0m0.314s
僅僅不到2秒就完成了對該文件的解壓操作,看下解壓後的文件情況:

$ll -h event_custom_json_201705161100.0.log
-rw-r--r-- 1 weiguang.sunwg users 301M May 27 13:34 event_custom_json_201705161100.0.log
解壓後文件大小爲301MB,這個壓縮率還是相當可觀的。一般來說,對於結構化的數據,壓縮率都比較高。這麼看來,解壓的效率還是很高的,不會成爲性能的瓶頸,這也是我們接下來通過對GZIP文件並行讀取提高整體數據同步效率的前提。試想下,如果解壓縮的操作非常耗時,那麼並行讀取意義就不大了。

$wc -l event_custom_json_201705161100.0.log
628410 event_custom_json_201705161100.0.log
該文件中共有將近63萬條記錄。

三,並行讀取
1,拆分規則

並行讀取的前提是讀取任務可以拆分,對於類似上面這樣結構化的文件通過記錄數來拆分是最自然的想法。例如,上面的文件存在628410行記錄,啓動10個並行的話,那麼每個線程讀取62841行記錄即可。但實際操作上卻非常困難,針對一個大文件,想要準確定位到某一行絕對是件效率不高的操作。
記錄數不行,那就通過數據量(偏移量)吧,上面的文件解壓縮後有301MB,如果啓動10個並行的話,每個線程讀取30MB左右的數據(不能通過壓縮後的18MB來做拆分,這並不是實際數據的大小)。通過JAVA可以很容易的實現對壓縮文件的流式讀取,邊讀邊解壓。這時候就要求我們在讀之間最好就可以知道該文件壓縮前的大小。看下GZIP的壓縮格式,在文件的結尾部分是保存了該信息的:

ISIZE(4 byte):這是原始數據的長度以2的32次方爲模的值。GZIP中字節排列順序是LSB方式,即Little-Endian,與ZLIB中的相反。
比較悲催的一點是,ISIZE存儲的是以2的32次方爲模的值,也就是說當原始文件大於4GB的時候,該值就不能準確的反應原始文件的大小了。GZIP的規範應該很久很久以前制定的,當時估計還不支持這麼大的文件吧。這點先忽略吧,目前的項目中文件都是相對較小的。
我們來驗證下,看看如何通過讀取GZIP的文件尾,來計算原始文件大小。

[[email protected] /home/weiguang.sunwg/sunwg/test]
$echo a > 1.txt

[[email protected] /home/weiguang.sunwg/sunwg/test]
$cat 1.txt
a

[[email protected] /home/weiguang.sunwg/sunwg/test]
$ll 1.txt
-rw-r--r-- 1 weiguang.sunwg users 2 May 27 13:57 1.txt
對1.txt進行壓縮,並查看壓縮後的文件信息:
···
[[email protected] /home/weiguang.sunwg/sunwg/test]
$gzip 1.txt

[[email protected] /home/weiguang.sunwg/sunwg/test]
$xxd 1.txt.gz
0000000: 1f8b 0808 5b15 2959 0003 312e 7478 7400 ....[.)Y..1.txt.
0000010: 4be4 0200 07a1 eadd 0200 0000 K...........
···
最後4個字節爲0200 0000,高低位轉換後爲0000 0002,意思該壓縮文件對應的原始文件爲2個字節。

在看下前面那個壓縮後爲18MB的文件,文件尾如下:

1145930: 4a21 c510 92a8 5177 0c9e b3da 7858 2867 J!....Qw....xX(g
1145940: 56f3 370f 28ff 3fa8 692e bc92 7dc0 12 V.7.(.?.i...}..
最後4個字節爲927d c012,高低位轉換後爲12c0 7d92,轉換爲10進製爲314604946,即爲解壓後文件大小。

$ll event_custom_json_201705161100.0.log
-rw-r--r-- 1 weiguang.sunwg users 314604946 May 27 13:34 event_custom_json_201705161100.0.log
通過解析GZIP文件尾,可以很方便的得到該原始文件大小,根據原始文件大小可以比較方便的進行並行的拆分,並且基本保證每個並行處理的數據量差不多,避免長尾。

2,記錄對齊

按數據量拆分,不能保證每個拆分點都是一行記錄的結尾,所以每個並行需要進行記錄對齊,保證讀取的是完整的一行。對齊的規則也相當簡單,開頭少讀半行,結尾多讀半行。示意圖如下:
A012.jpg
該並行讀取數據頭和尾分別爲A0和B0,根據上面的對齊規則調整爲A1和B1,保證記錄對齊。其實針對其他結構化的文件都可以如此操作,只要有明確的行分隔符。

四,結束
實現了對GZIP文件的並行讀取,就可以很容易的通過設置更高的並行度來提高同步的效率,更好的滿足用戶的需求。
原文鏈接:[url]http://click.aliyun.com/m/26743/[/url]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章