欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

针对GZIP文件类型的并行读取 LinqvelocityVBScript 

程序员文章站 2022-06-12 09:15:39
...
原文链接:http://click.aliyun.com/m/26743/
摘要: 一,前言 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的文件尾,来计算原始文件大小。

[weiguang.sunwg@buffer010101169107.et2sqa /home/weiguang.sunwg/sunwg/test]
$echo a > 1.txt

[weiguang.sunwg@buffer010101169107.et2sqa /home/weiguang.sunwg/sunwg/test]
$cat 1.txt
a

[weiguang.sunwg@buffer010101169107.et2sqa /home/weiguang.sunwg/sunwg/test]
$ll 1.txt
-rw-r--r-- 1 weiguang.sunwg users 2 May 27 13:57 1.txt
对1.txt进行压缩,并查看压缩后的文件信息:
···
[weiguang.sunwg@buffer010101169107.et2sqa /home/weiguang.sunwg/sunwg/test]
$gzip 1.txt

[weiguang.sunwg@buffer010101169107.et2sqa /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文件的并行读取,就可以很容易的通过设置更高的并行度来提高同步的效率,更好的满足用户的需求。
原文链接:http://click.aliyun.com/m/26743/