我有一个非常大的文件压缩,gzip位于磁盘上。生产环境基于“云”,因此存储性能很差,但CPU很好。以前我们的数据处理流程始于gzip -dc
从磁盘上传输数据。
现在,为了并行工作,我想运行多个管道,每个管道都需要一对字节偏移 - 开始和结束 - 并获取该文件的块。使用普通文件可以使用head
和tail
来实现,但我不确定如何使用压缩文件有效地执行此操作;如果我gzip -dc
并且管道进入head
,那么朝向文件末尾的偏移对将涉及浪费地搜索整个文件,因为它会慢慢解压缩。
所以我的问题实际上是关于gzip算法 - 理论上是否有可能在底层文件中寻找字节偏移量或获取它的任意一块,而没有解压缩整个文件的全部含义到那一点?如果没有,我怎样才能有效地为多个进程的“随机”访问分区文件,同时最小化I / O吞吐量开销?
答案 0 :(得分:23)
是的,您可以通过顺序读取整个事物并构建索引来随机访问gzip文件。请参阅examples/zran.c发行版中的zlib。
如果您可以控制创建gzip文件,那么您可以通过构建随机访问入口点并在压缩时构造索引来为此目的优化文件。
您还可以在zlib的Z_SYNC_FLUSH
中使用Z_FULL_FLUSH
后跟deflate()
来创建带标记的gzip文件,以插入两个标记并使下一个块独立于之前的数据。这样可以减少压缩,但如果不经常这样做,则会减少压缩。例如。一旦每兆字节应该影响很小。然后你可以搜索一个9字节的标记(比bzip2的六字节标记的假阳性要小得多):00 00 ff ff 00 00 00 ff ff
。
答案 1 :(得分:15)
你不能用gzip做到这一点,但是你可以用bzip2来实现它,它是块而不是基于流的 - 这就是Hadoop DFS在MapReduce算法中分割和并行化大文件与不同映射器的读取的方式。也许将文件重新压缩为bz2是有意义的,这样你就可以利用这一点;比某些特殊方式更容易将文件分块。
我在Hadoop中找到了正在实现此功能的补丁:https://issues.apache.org/jira/browse/HADOOP-4012
这是关于该主题的另一篇文章:BZip2 file read in Hadoop
也许浏览Hadoop源代码可以让您了解如何按块读取bzip2文件。
答案 2 :(得分:9)
gzip
实际上确实能够从头开始流式传输文件。你无法从中间开始。
您可以做的是将文件分解为使用gzip
分段压缩的块,然后连接在一起。您可以为每件作品选择任何尺寸,例如10MB或100MB。然后从包含所需字节偏移的片段的开头开始解压缩。由于gzip
的一个鲜为人知的特性(解压缩文件是几个较小的压缩文件的串联产生与解压缩每个较小文件相同的输出并将结果连接在一起)的分段压缩大如果您下载整个文件,该文件也可以使用标准gzip -d
/ gunzip
。
棘手的部分:您必须维护一个索引,该索引包含大文件中每个压缩块的开头的字节偏移量。
答案 3 :(得分:0)
FWIW: 我在zlib的 zran.c 上开发了一个命令行工具,该工具为gzip文件创建索引,从而可以在它们内部进行非常快速的随机访问: https://github.com/circulosmeos/gztool
它甚至可以为仍在增长的gzip文件创建索引(例如,由rsyslog直接以gzip格式创建的日志),从而在实践中将索引创建时间减少为零。请参阅-S(监督)选项。