前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >澄清 | snappy压缩到底支持不支持split? 为啥?

澄清 | snappy压缩到底支持不支持split? 为啥?

作者头像
数据仓库践行者
发布2022-04-18 16:08:56
1.9K0
发布2022-04-18 16:08:56
举报

前两天,群里小伙伴问了一个问题:

不是说snappy压缩不支持split嘛,为什么我改小mapred.max.split.size一倍之后,mapper数翻倍?

一直以来大家都知道snappy是不支持切分的,但是在测试时,又发现在某些情况下,貌似支持切分,这让人很疑惑... ...

关于snappy压缩,在网上大家的说法也不是很统一,有人说不支持split,有人说支持:

凡是稍微有点深度的有问题,从网上求答案,真的是太难了......

这篇从群里小伙伴的这个问题出发,分析一下有关snappy压缩的一些事情及spark 在处理这一块的源码层面分析。

先给结论

1、snappy压缩格式本身是不可切分的;

2、snappy压缩格式作用在文本类文件格式上不可切分;

3、snappy压缩格式作用在Sequence、Avro、parquet、orc等这些容器类的文件格式上,能够支持切分。但这里的切分并不是因为snappy变的可切分了,而是因为这些容器类的文件格式牛逼~~

再理解一遍啥是可切分?啥是不可切分?原因是啥?

可切分:是否可以搜索数据流的任意位置并进一步往下读取数据。

啥意思?

1、假设有一个1GB的不压缩的文本文件,如果HDFS的块大小为128M,那么该文件将被存储在8个块中,把这个文件作为输入数据的MapReduc/Spark作业,将创建8个map/task任务,其中每个数据块对应一个任务作为输入数据。

对于不压缩的文本文件来说,是可切分,因为每个block都存了完整的数据信息,读取的时候可以按照规定的方式去读:比如按行读。

2、假如一个文本文件经过snappy压缩后,文件大小为1GB。与之前一样,HDFS也是将这个文件存储成8个数据块。但是每个单独的map/task任务将无法独立于其他任务进行数据处理,官方一点的说法,原因就是压缩算法无法从任意位置进行读取。

通俗的讲解,就是因为存储在HDFS的每个块都不是完整的文件,我们可以把一个完整的文件认为是具有首尾标识的,因为被切分了,所以每个数据块有些有头标示,有些有尾标示,有些头尾标示都没有,所以就不能多任务来并行对这个文件进行处理。

粗暴点来讲,就是因为经过snappy压缩后的文本文件不是按行存了,但是又没有相关的结构能记录数据在每个block里是怎么存储的,每行的起止位置在哪儿,所以只有将该文件的所有HDFS的数据块都传输到一个map/task任务来进行处理,但是大多数数据块都没有存储在这个任务的节点上,所以需要跨节点传输,且不能并行处理,因此运行的时间可能很长。

总结:决定可不可分,主要是看能不能有个清晰的规则支持从任意位置读数据,对于文本文件来说,按行读,哪怕两个map task来读同一个block,只要按照定好的规则也是能读的,不会发生错乱。

而一些不可切分的压缩算法,做不到这点(当然,如果你能给开发个对应的规则去读,也是可以的,哈哈,但是这个很难吧,要不然也不会说是不可切分了)

文件的存储格式和压缩格式的关系

存储格式:text、Sequence、Avro、parquet、orc等

压缩格式:Gzip、snappy、lzo、lz4、zlib等

压缩格式并不是一种文件格式,我们可以认为他是一种算法

一个orc格式的文件,可以用zlib压缩算法来压缩、也可以用snappy压缩算法来压缩,用完这些压缩算法后,该文件还是orc格式

从spark源码中看,文件格式的实现类是上面几种,没有见有snappy、zlib文件格式的。所以说,这一点一定要分清。

以orc为例分析snappy是怎么作用到容器类的文件格式上的

orc文件格式本身可切分的

orc虽然是二进制存储,但因为orc中提供了各种索引,使得在读取数据时支持从指定任意一行开始读取,所以,orc是切分的。

文件压缩

在orc格式的hive表中,记录首先会被横向的切分为多个stripes,然后在每一个stripe内数据以列为单位进行存储。

条带( stripe):ORC文件存储数据的地方,每个stripe一般为HDFS的块大小,包含以下3部分:

  • index data:保存了所在条带的一些统计信息,以及数据在 stripe中的位置索引信息。
  • row data:数据存储的地方,由多个行组构成,每10000行构成一个行组,数据以流( stream)的形式进行存储。
  • Stripe Footer:保存数据所在的文件目录

文件脚注( File Footer):包含了文件中stripe的列表,每个 stripe的行数,以及每个列的数据类型。它还包含每个列的最小值、最大值、行计数、求和等聚合信息。

Postscript:含有压缩参数和压缩大小相关的信息

而orc在压缩时,压缩算法起作用的地方是数据流,也就是上图右侧的红色圈出的部分:

orc文件使用两级压缩机制,首先将一个数据流使用流式编码器进行编码,然后使用一个可选的压缩器(snappy or zlib)对数据流进行进一步压缩。

也就是说,snappy作用的地方是stripe里的row data部分。

两个位置

当读取一个orc文件时,orc reader需要有两个位置信息就可准确的进行数据读取操作:

  • metadata streams和data stream中每个行组的开始位置

由于每个stripe中有多个行组,orc reader需要知道每个group的metadata streams和data stream的开始位置。而这些信息存储在index data里,index data并没有被snappy压缩

  • stripes的开始位置

由于一个orc文件可以包含多个stripes,并且一个hdfs block也能包含多个stripes。为了快速定位指定stripe的位置,需要知道每个stripe的开始位置。而这些信息主要保存在orc file的 File Footer中。File Footer也没有被snappy压缩

综上,我们知道orc使用snappy压缩后,索引信息还在,这就使得在压缩后,仍然能支持从指定任意一行开始读取。

spark 层面的源码分析

spark 通过FileSourceScanExec 来处理hdfs文件:

找到判断文件是否可切分的逻辑

我们重点看一下OrcFileFormat 和 TextFileFormat部分的实现:

OrcFileFormat:

返回true,默认可切分

TextFileFormat:

先给结论:

1、没有做【把整个文件当成一行来读】这样的配制

2、没有压缩或者如果压缩了,压缩的算法必须是SplittableCompressionCodecr的子类

满足上面两个条件,该文件才可切分。

而snappy的压缩是没有继承SplittableCompressionCodecr的,所以用snappy的算法来压缩文本文件,是不可切分的。

TextFileFormat的父类是TextBasedFileFormat:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据仓库践行者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 先给结论
  • 再理解一遍啥是可切分?啥是不可切分?原因是啥?
  • 文件的存储格式和压缩格式的关系
  • 以orc为例分析snappy是怎么作用到容器类的文件格式上的
    • orc文件格式本身可切分的
      • 文件压缩
        • 两个位置
        • spark 层面的源码分析
          • OrcFileFormat:
            • TextFileFormat:
            相关产品与服务
            对象存储
            对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档