针对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文件的并行读取,就可以很容易的通过设置更高的并行度来提高同步的效率,更好的满足用户的需求。

目录
相关文章
|
2月前
|
Android开发
文件的读取
本文介绍了文件读取和写入操作的基本概念,包括输入输出流的创建、数据读取和写入以及流的关闭。
39 1
|
7月前
|
存储 文件存储
<文件操作> 文件的打开与关闭,顺序读写,随机读写,二进制文件,读取结束的判定,文件缓冲区
<文件操作> 文件的打开与关闭,顺序读写,随机读写,二进制文件,读取结束的判定,文件缓冲区
42 1
|
7月前
|
存储 算法 Linux
Gzip的压缩级别
【4月更文挑战第29天】压缩级别
413 1
|
7月前
|
存储 算法 Linux
Gzip的压缩级别有哪些选择?
【4月更文挑战第29天】Gzip的压缩级别有哪些选择?
294 1
|
7月前
|
算法 Linux
Gzip是一种广泛使用的文件压缩程序
【4月更文挑战第28天】Gzip是一种广泛使用的文件压缩程序
80 2
|
大数据 C#
C# 读取大文件 (可以读取3GB大小的txt文件)
原文:C# 读取大文件 (可以读取3GB大小的txt文件) 在处理大数据时,有可能 会碰到 超过3GB大小的文件,如果通过 记事本 或 NotePad++去打开它,会报错,读不到任何文件。
4254 1
Java字符串压缩(两种压缩方式)
第一种,只统计字符出现次数,比如aabcccccaaa,压缩成a5b1c5 思路:利用hashMap键的唯一性
1264 0
|
SQL 分布式计算 HIVE
记一个压缩格式的问题
问题描述 Hive ORC table常规小文件过多问题,于是用Spark写了一个Application来自动的Merge分区数据,思路很简单大概就是 insert overwrite table partition (分区 XXX) select * from table where (分区 XXX)当然已经把该dataframe repartition到想要的目标并发度,来控制最终分区下的文件个数 但是发现生成的文件个数虽然是对的,但是最后整个分区的Size竟然几乎翻倍。
记一个压缩格式的问题
|
监控 算法 Cloud Native
开发函数计算的正确姿势——使用 brotli 压缩大文件
函数计算对上传的 zip 代码包尺寸限制为 50M。某些场景中代码包中会超过这一限制,比如未经裁剪的 serverless-chrome,类似的还有 libreoffice ,此外常见的还有机器学习训练的模型文件。本文会比较几种常见的解决大文件的方案,并重点介绍借助 brotli 提高压缩比的方法。
开发函数计算的正确姿势——使用 brotli 压缩大文件
|
机器学习/深度学习 C#
C#使用Gzip解压缩完整读取网页内容
using System; using System.Threading; using System.Text; using System.Text.RegularExpressions; using System.
1581 0