29

我在磁盘上有一个用 gzip 压缩的非常大的文件。生产环境是基于“云”的,所以存储性能很差,但是CPU很好。以前,我们的数据处理管道开始于gzip -dc从磁盘流式传输数据。

现在,为了使工作并行化,我想运行多个管道,每个管道采用一对字节偏移量 - 开始和结束 - 并获取文件的那个块。使用纯文件可以使用headand来实现tail,但我不确定如何使用压缩文件有效地做到这一点;如果 Igzip -dc和 pipe into head,则文件末尾的偏移对将涉及在整个文件缓慢解压缩时浪费性地寻找。

所以我的问题实际上是关于 gzip 算法的——理论上是否可以在底层文件中寻找一个字节偏移量或获取它的任意块,而没有将整个文件解压缩到那时的全部含义?如果不是,我还能如何有效地分区文件以供多个进程“随机”访问,同时最小化 I/O 吞吐量开销?

4

4 回答 4

29

是的,您可以通过顺序读取整个内容并构建索引来随机访问 gzip 文件。请参阅zlib发行版中的示例/zran.c

如果您可以控制创建 gzip 文件,那么您可以为此目的优化文件,方法是构建随机访问入口点并在压缩时构建索引。

您还可以通过在 zlib 中使用Z_SYNC_FLUSH后跟插入两个标记并使下一个块独立于先前的数据来创建带有标记的 gzip 文件。这将减少压缩,但如果您不经常这样做,则不会减少太多。例如,每兆字节一次应该几乎没有影响。然后您可以搜索一个 9 字节标记(误报的可能性比 bzip2 的 6 字节标记小得多):Z_FULL_FLUSHdeflate()00 00 ff ff 00 00 00 ff ff

于 2013-01-09T17:09:13.390 回答
17

你不能用 gzip 做到这一点,但你可以用 bzip2 做到这一点,它是块而不是基于流的——这就是 Hadoop DFS 如何在其 MapReduce 算法中使用不同的映射器拆分和并行读取大文件的方式。也许将文件重新压缩为 bz2 是有意义的,这样您就可以利用这一点;它比一些特殊的方式来分块文件更容易。

我在这里找到了在 Hadoop 中实现此功能的补丁:https ://issues.apache.org/jira/browse/HADOOP-4012

这是关于该主题的另一篇文章:在 Hadoop 中读取的 BZip2 文件

也许浏览 Hadoop 源代码会让您了解如何按块读取 bzip2 文件。

于 2013-01-08T23:30:18.190 回答
11

gzip实际上确实希望能够从一开始就流式传输文件。你不能从中间开始。

您可以做的是将文件分解为分段压缩gzip然后连接在一起的块。您可以为每件选择您喜欢的任何尺寸,例如 10MB 或 100MB。然后,您从包含所需字节偏移量的片段的开头开始解压缩。由于一个鲜为人知的特性gzip(即解压缩一个由几个较小的 gzip 文件连接的文件会产生与解压缩每个较小的文件并将结果连接在一起的相同的输出),分段压缩的大文件也适用于标准gzip -d/gunzip如果你下载整个东西。

棘手的部分:您必须维护一个索引,其中包含大文件中每个压缩片段的开始字节偏移量。

于 2013-01-08T23:33:10.057 回答
3

FWIW:我在 zlib 的zran.c上开发了一个命令行工具,它为 gzip 文件创建索引,允许在其中进行非常快速的随机访问https ://github.com/circulosmeos/gztool

它甚至可以为仍在增长的 gzip 文件(例如由 rsyslog 直接以 gzip 格式创建的日志)创建索引,从而在实践中将创建索引的时间减少到零。请参阅 -S(监督)选项。

于 2019-07-24T21:23:20.927 回答