精华内容
下载资源
问答
  • RC ORC Parquet 格式比较和性能测试

    万次阅读 2016-12-16 21:48:37
    RC ORC Parquet 格式比较和性能测试作者:刘旭晖 Raymond 转载请注明出处 Email:colorant at 163.com BLOG:http://blog.csdn.net/colorant/为什么要比较这三者为什么要比较,起因是为了提高Hadoop集群的存储和...

    RC ORC Parquet 格式比较和性能测试

    作者:刘旭晖 Raymond 转载请注明出处
    Email:colorant at 163.com
    BLOG:http://blog.csdn.net/colorant/

    为什么要比较这三者

    为什么要比较,起因是为了提高Hadoop集群的存储和计算效率,尤其是离线Hive作业的效率,为什么比较的是这三者,是因为三者是目前Hive离线作业中正在大规模使用或可能大规模使用的三种主流的相对成熟的文件格式

    对于ORC性能的评测,Hortonworks发过一篇被广泛传播和引用的博客 : ORCFILE IN HDP 2: BETTER COMPRESSION, BETTER PERFORMANCE

    这篇文章在ORC改进原理等方面说的比较客观,但是实际的benchmark比较数据,即使不说是有故意偏颇的嫌疑,至少也是不科学不客观的,特别是下面这张文件尺寸比较,带有很大的误导性。

    并不科学的比较

    这个测试的数据集,看起来用了TPC-DS的数据,貌似很专业的样子

    但是首先,这里的测试方法明显的就不科学,压缩算法并不相同有什么好比的(Snappy侧重性能,Zlib侧重压缩率)?不知道作者对RCFile采用了什么压缩算法,但是Parquet+Snappy,ORC+Zlib,这种比较的基调就不公正(当然,这个问题,作者说是因为这是它们默认的压缩格式,但是科学严谨的来说,benchmark应该用统一的标准来衡量)

    其次,套多数hive作业任务的的场景,TPC-DS的数据特性和典型的Hive应用场景(至少我们这边的场景)里的数据看起来并不一致。RC File的压缩还不到15%,这压缩率明显不是Hive离线处理数据场景和压缩算法下RCFile的典型表现

    三种文件格式简单介绍

    Parquet

    Parquet的设计方案,整体来看,基本照搬了Dremel中对嵌套数据结构的打平和重构算法,通过高效的数据打平和重建算法,实现按列存储(列组),进而对列数据引入更具针对性的编码和压缩方案,来降低存储代价,提升计算性能。想要了解这一算法逻辑的,可以看Dremel的论文:Dremel: Interactive Analysis of WebScaleDatasets

    从文件结构上来看,如下图所示:

    基本上就是一个文件由多个列组组成,数据先按列组(rowgroup)分段(也就是先做行切割),然后在列组内部对每个列的数据分列连续存储(columnchunk)(也就第二步做列切割),每个列内部的数据,再细分成page(可以近似的认为是再做行切割),最后,在文件的尾部,存储所有列组的元数据信息

    这么分层设计,从并发度的角度考虑,行切割的目的,主要做为任务的切分单元,比如一个Map任务处理一个列组里的数据。然后列切割的目的,除了按需读取数据,也是做为IO的并发单元。最后Page的拆分,主要是从编码和压缩的角度,进行拆分,以page为单位进行压缩编码,如果近似的理解,也可以认为一定程度上起到了内存和CPU上用量的控制,从Parquet文件的层面来说,Page是数据最小的读写单元。

    最后,对列数据提供多种编码方式,比如:字典(Dictionary),游程(RLE),增量(DELTA)等等

    综上,Parquet主要还是对Dremel的存储模型这部分的一个实现,在Dremel存储模型定义范围之外,自己额外做的工作,并不多。(这里指的文件格式底层技术实现方面,工程上和大数据生态系各个组件的打通结合方面,还是做了大量的工作的)

    ORC

    ORC文件格式的一些基础思想和Parquet很像,也是先按行水平切割,在按列垂直切割,针对不同的列,采用特定的编码格式,最后再进一步对编码后的数据进行压缩。支持的编码格式(游程,字典,增量,bit),压缩格式(zlib,snappy,LZO等等)也基本一致

    与Parquet不同的地方是,Parquet对嵌套型数据结构的打散和重构的算法,来源于Dremel,通过两种level信息(definition level,repetition level)来标识特定数据在数据结构中层次位置,这两种信息和具体的列数据直接绑定,仅依靠这些信息和对象整体的Schema就能重构出这一列信息原有的层次结构。

    而ORC的实现,更加简单直白一些,类似元素是否为Null的信息,就是一组bit位图,而对于元素个数不定的结构,如List,Map等数据结构,则在虚拟的父结构中维护了一个所拥有的子元素数量的信息。这样的带来的问题是,由单纯的某一叶节点列元素的数据出发,是无法独立构建复原出该列数据的结构层次的,需要借助父元素的辅助元数据才能完整复原。

    在实现中,ORC对于每个列(基本的或符合结构的)采用了多个Stream分别存储数据和上述各类元数据。

    比如String类型的列,如果使用字典编码,那么会生成4个stream,PRESENT Stream用来标识具体String元素是否为Null,DATA Stream,连续存储字符串自身,DICTIONARY_DATA Stream存储字典信息,LENGTH Stream存储每个元素的长度(用来从DATA Stream中定位和拆分数据)

    再比如Map类型的列,使用一个PRESENT Stream来标识具体每个Map元素是否为Null,用LENGTH
    Stream来标识每个Map元素内部有几个对象

    这种处理方式对比Dremel,看起来的确老土很多,理论深度上被甩了不止一条街,不过如果对于嵌套层次不复杂的数据结构,也还是简单有效的。但是,ORC的风评最近感觉明显比Parquet要盛,这又是为什么呢?

    个人感觉,主要还是工程实现上的问题,除了核心的数据结构的打散和重建逻辑,ORC的文件格式里,还包含了其它的一些工程优化手段。比如索引(并不是传统意义上的全量排序用索引,更接近统计信息,比如列组的min,max,avg,count等信息,可以用作粗过滤手段,也可以覆盖部分聚合计算的需求),比如Bloomfilter等。而Parquet在这些方面有规划,但是目前似乎基本都没有做。

    另外,如果仅从Hive的角度来说,一方面ORC是亲儿子,有些工作开展得比较早,另一方面扁平的数据结构,让Parquet在支持嵌套数据结构方面的优势并不能很好的体现,大概也是原因之一吧。

    RC File

    RC File的格式,就简单很多了,基本除了先水平切Row,再垂直切Column以外,就剩下每个行组的Metadata里维护了行组的纪录数和每个column及每个Column纪录的长度,除此之外就没有太多别的黑科技了。编码方面Metadata使用RLE编码,Column Data使用Gzip等压缩格式(取决于写入方,比如MR程序)

    具体看论文 RCFile: A Fast and Space-efficient Data Placement Structure in MapReduce-based Warehouse Systems

    性能比较

    主要做了RC和ORC的比较,Parquet做了一部分,主要还是在Hive的场景下,目前看来ORC会更适合一些(基于hive 1.2.1)

    !!! 需要注意的是,具体性能数据取决于集群各种参数配置,具体数据格式内容等因素影响,所以绝对值大小并没有实际意义,比例大小的绝对值也不见得完全有代表性,比例的正负趋势才是基本可以参考的,另外时间有限,部分测试还有一些存疑问题尚未验证

    首先是压缩率和写性能,从上表可以看到采用不同的压缩格式,不同的压缩级别,对应不同数据类型,其实结论并不是简单一致的

    基本上,当前版本情况下,对于String类型比重大的数据,RC文件的尺寸,最佳表现要优于ORC的默认格式(ZLIB, SPEED),但是差距不大(3-5%左右),而对于存int bigint等类型的数据,ORC文件表现优于RC文件是比较一致的

    再分析理解一下,可以认为,ORC的编码(Encoding)优势,使得在同等条件下,结果文件尺寸大小要优于RC(30%~100%),而对于复杂String类型比重大的数据,RC文件由于LZ4压缩算法比ZLIB 低压缩率设置下的压缩率的优势,最终结果数据RC+LZ4在CPU耗时略优的情况下,压缩率也略优。 ORC+Zlib可以通过更高压缩率反转尺寸优势,但是CPU耗时就大大增加了。当前hive 1.2.1版本集成的ORC文件格式(0.12+一些改进)还不支持LZ4压缩格式(独立的ORC 1.2.2版本支持),可以想见,一旦集成了,同等条件下,ORC+LZ4的表现应该是最优的。

    而Parquet这边,压缩率方面看起来和ORC也没有很明显差距,小幅度的区别的原因应该还是具体Encoding和compress算法的区别。但是CPU耗时方面,明显高出RC和ORC,应该是列打散算法的消耗造成的,也不排除目前Parquet对Dremel算法的应用还有优化的空间。

    下面的数据测试读取性能,RC-LZ4 v.s. ORC-ZLIB SPEED

    可以看到第一例case中,ORC格式由于column data统计数据的存在,在数据过滤方面可以更好的使用Filter Push down技术,所以性能要明显由于RC格式(数据量100倍)。 无条件count这种,很明显,ORC大概能做到只需要检索原始数据500-2000分之一的数据量,RC大概是十五分之一左右(当然,这取决于表的字段数,RC文件的加速来源于分列存储,ORC格式的加速来源于meta统计信息里Count信息的存在)

    而第二例有条件过滤计数case中,ORC还是优于RC,不过我们的数据集case中,检索数据量的大小差异大概只有三倍,大致可以认为是meta统计信息中范围信息起到的过滤作用。 不过,很奇怪的是,理论上ORC文件中添加了Bloom Filter以后,应该可以更好的加速过滤检索,但实际效果并没有见到,还需要再验证,是否是我的测试方法或者测试集又问题,还是当前版本还有Bug存在(1.2.1的版本之前BF这块都有bug,并不能发挥作用,但1.2.1 版本以后,jira上已经找不到这方面bug的报告了)

    CPU耗时方面,差异没有那么显著 50%,这也和这个case中,IO是瓶颈,MR任务数量多,平均执行时间短,启动耗时占比不能忽略等因素有关

    再看Parquet,还是同样的问题,CPU的耗时明显要偏高(尽管使用了比RC和ORC更快的Snappy压缩方式)

    小结

    总体可以认为,在我们当前的数据集和hive版本环境下,在文件写入方面,ORC相比RC文件的优势不显著,一些场合RC文件还要更优,在查询检索方面,ORC则基本是更优的,性能差距大小取决于具体数据集和检索模式。如果Hive能集成ORC更新的版本,支持LZ4,并修复一些Bug,那应该就没有任何再使用RC的理由了。

    至于Parquet,可以考虑在需要支持深度嵌套的数据结构的应用场合中去使用

    需要进一步验证的点

    • 内存消耗情况比较
    • ORC高版本与Hive集成的进展情况跟踪
    • 各种block/strip/page大小参数对文件尺寸,读写性能的影响
    • ORC BloomFilter问题的跟踪
    • 更大范围的性能验证比较

    附录

    各种资料

    String 和 TimeStamp类型存储日期的比较

    理论上用TimeStamp和Date类型的数据结构,应该是要比用String类型的方式表达日期要更高效(毕竟有明确的类型信息),这点从上表中同样的数据使用不同的格式以后压缩率的对比情况上就能看得出来。不过,稍微有点意外的是,在CPU耗时方面,TimeStamp类型远远超过String类型(差4倍。。。),这样使用专门的日期类型的价值就完全被湮没了。照理不应该这么差,不是我哪里姿势没搞对,就是在Hive中,这些类型的读写比较等性能方面还存在很大的改进空间。


    顺道,推销一下个人公众号 “望月的蚂蚁”, 和技术完全无关。。。。 以一些有趣的兴趣爱好等为主题,比如乐高,桌游,旅行,摄影。。。工作生活要平衡不是;)

    望月的蚂蚁

    展开全文
  • (转)RC ORC Parquet 格式比较和性能测试 原博:http://blog.csdn.net/colorant/ 为什么要比较这三者 为什么要比较,起因是为了提高Hadoop集群的存储和计算效率,尤其是离线Hive作业的效率,为什么比较的是这三...

    (转)RC ORC Parquet 格式比较和性能测试

    原博:http://blog.csdn.net/colorant/

    为什么要比较这三者

    为什么要比较,起因是为了提高Hadoop集群的存储和计算效率,尤其是离线Hive作业的效率,为什么比较的是这三者,是因为三者是目前Hive离线作业中正在大规模使用或可能大规模使用的三种主流的相对成熟的文件格式

    对于ORC性能的评测,Hortonworks发过一篇被广泛传播和引用的博客 : ORCFILE IN HDP 2: BETTER COMPRESSION, BETTER PERFORMANCE

    这篇文章在ORC改进原理等方面说的比较客观,但是实际的benchmark比较数据,即使不说是有故意偏颇的嫌疑,至少也是不科学不客观的,特别是下面这张文件尺寸比较,带有很大的误导性。

    并不科学的比较

    这个测试的数据集,看起来用了TPC-DS的数据,貌似很专业的样子

    但是首先,这里的测试方法明显的就不科学,压缩算法并不相同有什么好比的(Snappy侧重性能,Zlib侧重压缩率)?不知道作者对RCFile采用了什么压缩算法,但是Parquet+Snappy,ORC+Zlib,这种比较的基调就不公正(当然,这个问题,作者说是因为这是它们默认的压缩格式,但是科学严谨的来说,benchmark应该用统一的标准来衡量)

    其次,套多数hive作业任务的的场景,TPC-DS的数据特性和典型的Hive应用场景(至少我们这边的场景)里的数据看起来并不一致。RC File的压缩还不到15%,这压缩率明显不是Hive离线处理数据场景和压缩算法下RCFile的典型表现

    三种文件格式简单介绍

    Parquet

    Parquet的设计方案,整体来看,基本照搬了Dremel中对嵌套数据结构的打平和重构算法,通过高效的数据打平和重建算法,实现按列存储(列组),进而对列数据引入更具针对性的编码和压缩方案,来降低存储代价,提升计算性能。想要了解这一算法逻辑的,可以看Dremel的论文:Dremel: Interactive Analysis of WebScaleDatasets

    从文件结构上来看,如下图所示:

    基本上就是一个文件由多个列组组成,数据先按列组(rowgroup)分段(也就是先做行切割),然后在列组内部对每个列的数据分列连续存储(columnchunk)(也就第二步做列切割),每个列内部的数据,再细分成page(可以近似的认为是再做行切割),最后,在文件的尾部,存储所有列组的元数据信息

    这么分层设计,从并发度的角度考虑,行切割的目的,主要做为任务的切分单元,比如一个Map任务处理一个列组里的数据。然后列切割的目的,除了按需读取数据,也是做为IO的并发单元。最后Page的拆分,主要是从编码和压缩的角度,进行拆分,以page为单位进行压缩编码,如果近似的理解,也可以认为一定程度上起到了内存和CPU上用量的控制,从Parquet文件的层面来说,Page是数据最小的读写单元。

    最后,对列数据提供多种编码方式,比如:字典(Dictionary),游程(RLE),增量(DELTA)等等

    综上,Parquet主要还是对Dremel的存储模型这部分的一个实现,在Dremel存储模型定义范围之外,自己额外做的工作,并不多。(这里指的文件格式底层技术实现方面,工程上和大数据生态系各个组件的打通结合方面,还是做了大量的工作的)

    ORC

    ORC文件格式的一些基础思想和Parquet很像,也是先按行水平切割,在按列垂直切割,针对不同的列,采用特定的编码格式,最后再进一步对编码后的数据进行压缩。支持的编码格式(游程,字典,增量,bit),压缩格式(zlib,snappy,LZO等等)也基本一致

    与Parquet不同的地方是,Parquet对嵌套型数据结构的打散和重构的算法,来源于Dremel,通过两种level信息(definition level,repetition level)来标识特定数据在数据结构中层次位置,这两种信息和具体的列数据直接绑定,仅依靠这些信息和对象整体的Schema就能重构出这一列信息原有的层次结构。

    而ORC的实现,更加简单直白一些,类似元素是否为Null的信息,就是一组bit位图,而对于元素个数不定的结构,如List,Map等数据结构,则在虚拟的父结构中维护了一个所拥有的子元素数量的信息。这样的带来的问题是,由单纯的某一叶节点列元素的数据出发,是无法独立构建复原出该列数据的结构层次的,需要借助父元素的辅助元数据才能完整复原。

    在实现中,ORC对于每个列(基本的或符合结构的)采用了多个Stream分别存储数据和上述各类元数据。

    比如String类型的列,如果使用字典编码,那么会生成4个stream,PRESENT Stream用来标识具体String元素是否为Null,DATA Stream,连续存储字符串自身,DICTIONARY_DATA Stream存储字典信息,LENGTH Stream存储每个元素的长度(用来从DATA Stream中定位和拆分数据)

    再比如Map类型的列,使用一个PRESENT Stream来标识具体每个Map元素是否为Null,用LENGTH 
    Stream来标识每个Map元素内部有几个对象

    这种处理方式对比Dremel,看起来的确老土很多,理论深度上被甩了不止一条街,不过如果对于嵌套层次不复杂的数据结构,也还是简单有效的。但是,ORC的风评最近感觉明显比Parquet要盛,这又是为什么呢?

    个人感觉,主要还是工程实现上的问题,除了核心的数据结构的打散和重建逻辑,ORC的文件格式里,还包含了其它的一些工程优化手段。比如索引(并不是传统意义上的全量排序用索引,更接近统计信息,比如列组的min,max,avg,count等信息,可以用作粗过滤手段,也可以覆盖部分聚合计算的需求),比如Bloomfilter等。而Parquet在这些方面有规划,但是目前似乎基本都没有做。

    另外,如果仅从Hive的角度来说,一方面ORC是亲儿子,有些工作开展得比较早,另一方面扁平的数据结构,让Parquet在支持嵌套数据结构方面的优势并不能很好的体现,大概也是原因之一吧。

    RC File

    RC File的格式,就简单很多了,基本除了先水平切Row,再垂直切Column以外,就剩下每个行组的Metadata里维护了行组的纪录数和每个column及每个Column纪录的长度,除此之外就没有太多别的黑科技了。编码方面Metadata使用RLE编码,Column Data使用Gzip等压缩格式(取决于写入方,比如MR程序)

    具体看论文 RCFile: A Fast and Space-efficient Data Placement Structure in MapReduce-based Warehouse Systems

    性能比较

    主要做了RC和ORC的比较,Parquet做了一部分,主要还是在Hive的场景下,目前看来ORC会更适合一些(基于hive 1.2.1)

    !!! 需要注意的是,具体性能数据取决于集群各种参数配置,具体数据格式内容等因素影响,所以绝对值大小并没有实际意义,比例大小的绝对值也不见得完全有代表性,比例的正负趋势才是基本可以参考的,另外时间有限,部分测试还有一些存疑问题尚未验证

    首先是压缩率和写性能,从上表可以看到采用不同的压缩格式,不同的压缩级别,对应不同数据类型,其实结论并不是简单一致的

    基本上,当前版本情况下,对于String类型比重大的数据,RC文件的尺寸,最佳表现要优于ORC的默认格式(ZLIB, SPEED),但是差距不大(3-5%左右),而对于存int bigint等类型的数据,ORC文件表现优于RC文件是比较一致的

    再分析理解一下,可以认为,ORC的编码(Encoding)优势,使得在同等条件下,结果文件尺寸大小要优于RC(30%~100%),而对于复杂String类型比重大的数据,RC文件由于LZ4压缩算法比ZLIB 低压缩率设置下的压缩率的优势,最终结果数据RC+LZ4在CPU耗时略优的情况下,压缩率也略优。 ORC+Zlib可以通过更高压缩率反转尺寸优势,但是CPU耗时就大大增加了。当前hive 1.2.1版本集成的ORC文件格式(0.12+一些改进)还不支持LZ4压缩格式(独立的ORC 1.2.2版本支持),可以想见,一旦集成了,同等条件下,ORC+LZ4的表现应该是最优的。

    而Parquet这边,压缩率方面看起来和ORC也没有很明显差距,小幅度的区别的原因应该还是具体Encoding和compress算法的区别。但是CPU耗时方面,明显高出RC和ORC,应该是列打散算法的消耗造成的,也不排除目前Parquet对Dremel算法的应用还有优化的空间。

    下面的数据测试读取性能,RC-LZ4 v.s. ORC-ZLIB SPEED

    可以看到第一例case中,ORC格式由于column data统计数据的存在,在数据过滤方面可以更好的使用Filter Push down技术,所以性能要明显由于RC格式(数据量100倍)。 无条件count这种,很明显,ORC大概能做到只需要检索原始数据500-2000分之一的数据量,RC大概是十五分之一左右(当然,这取决于表的字段数,RC文件的加速来源于分列存储,ORC格式的加速来源于meta统计信息里Count信息的存在)

    而第二例有条件过滤计数case中,ORC还是优于RC,不过我们的数据集case中,检索数据量的大小差异大概只有三倍,大致可以认为是meta统计信息中范围信息起到的过滤作用。 不过,很奇怪的是,理论上ORC文件中添加了Bloom Filter以后,应该可以更好的加速过滤检索,但实际效果并没有见到,还需要再验证,是否是我的测试方法或者测试集又问题,还是当前版本还有Bug存在(1.2.1的版本之前BF这块都有bug,并不能发挥作用,但1.2.1 版本以后,jira上已经找不到这方面bug的报告了)

    CPU耗时方面,差异没有那么显著 50%,这也和这个case中,IO是瓶颈,MR任务数量多,平均执行时间短,启动耗时占比不能忽略等因素有关

    再看Parquet,还是同样的问题,CPU的耗时明显要偏高(尽管使用了比RC和ORC更快的Snappy压缩方式)

    小结

    总体可以认为,在我们当前的数据集和hive版本环境下,在文件写入方面,ORC相比RC文件的优势不显著,一些场合RC文件还要更优,在查询检索方面,ORC则基本是更优的,性能差距大小取决于具体数据集和检索模式。如果Hive能集成ORC更新的版本,支持LZ4,并修复一些Bug,那应该就没有任何再使用RC的理由了。

    至于Parquet,可以考虑在需要支持深度嵌套的数据结构的应用场合中去使用

    需要进一步验证的点

    • 内存消耗情况比较
    • ORC高版本与Hive集成的进展情况跟踪
    • 各种block/strip/page大小参数对文件尺寸,读写性能的影响
    • ORC BloomFilter问题的跟踪
    • 更大范围的性能验证比较

    附录

    各种资料

    String 和 TimeStamp类型存储日期的比较

    理论上用TimeStamp和Date类型的数据结构,应该是要比用String类型的方式表达日期要更高效(毕竟有明确的类型信息),这点从上表中同样的数据使用不同的格式以后压缩率的对比情况上就能看得出来。不过,稍微有点意外的是,在CPU耗时方面,TimeStamp类型远远超过String类型(差4倍。。。),这样使用专门的日期类型的价值就完全被湮没了。照理不应该这么差,不是我哪里姿势没搞对,就是在Hive中,这些类型的读写比较等性能方面还存在很大的改进空间。

    展开全文
  • 一直是大数据集群老生常谈的问题,今天就一起聊聊最基本的大数据文件存储格式的区别对比,尤其是Hive建表的时候需要选择文件存储格式最为常用,而为什么单独拎出来说RC, ORC,Parquet文件呢?是因为这三者是当今Hive...

    背 景

      大数据如火如荼的发展中,以hadoop集群为基础的数据存储和计算框架也日新月异的精进,而如何减少存储空间又提升计算效率,一直是大数据集群老生常谈的问题,今天就一起聊聊最基本的大数据文件存储格式的区别对比,尤其是Hive建表的时候需要选择文件存储格式最为常用,
      而为什么单独拎出来说RC, ORC,Parquet文件呢?而我们windows常用的文件txt,csv,excel等又怎么提都不提呢?首先,excel,word这些只适用于windows,大数据集群通常是linux集群,这些文件显然传到linux都解码不了,通常来说就是打开乱码,至于txt,csv在大数据集群用是能用,但是因为其本身压缩率低,查询效率低,行存储,而且列之间的分隔符就算取任何字符,始终都有可能和字段内包含这个分隔符本身起冲突,所以始终是个隐患,所以txt,csv,临时文件可以玩玩,大数据架构方案内,显然只能淘汰,而自带schema的jsonxml显然就比txtcsv在大数据集群出名的多,但是因为压缩比,压缩空间,以及支持的架构以及文件本身可split等原因,并不是最佳文件存储格式的选择;
      反观RC, ORC,Parquet三者,是当今Hive建表使用频率最多,效率相对成熟稳定,可支持列式存储,天生自带序列化和反序列化资质,而且资历也比较老的三位帅哥( 其实目前ORC基本取代了RC,RC也没什么地位了),而究竟谁才是真正的数据文件存储格式的一哥呢,请我们一探究竟。

    列存储简介

      看三种文件前,我们先了解下列存储,列存储和行存储的比较,当然首先要抛开极端数据模型,你不能拿单独1列n行的数据二维表来比较行列存储,这样行存储的行索引在搜索的时候有显然优势,1行n列二维表同理,那么在行列分布相对常见的n行m列的前提,下列存储和行式存储相比有哪些优势呢:

    1. 可以跳过不符合条件的数据,只读取需要的数据,降低 IO 数据量;
    2. 压缩编码可以降低磁盘存储空间。由于同一列的数据类型是一样的,可以使用更高效的压缩编码(例如 Run Length Encoding 和 Delta Encoding)进一步节约存储空间;
    3. 只读取需要的列,支持向量运算,能够获取更好的扫描性能;
    4. 数据分析使用的聚合统计,开窗函数,列存储操作起来有天然的快速高效优势。

      关系型数据的列式存储,可以将每一列的值直接排列下来,不用引入其他的概念,也不会丢失数据。关系型数据的列式存储比l较好理解,如图1;

    在这里插入图片描述

    图1 关系型数据列式存储

      而嵌套类型数据的列存储则会遇到一些麻烦。如图 2 所示,我们把嵌套数据类型的一行叫做一个记录(record),嵌套数据类型的特点是一个 record 中的 column 除了可以是 Int, Long, String 这样的原语(primitive)类型以外,还可以是 List, Map, Set 这样的复杂类型。在行式存储中一行的多列是连续的写在一起的,在列式存储中数据按列分开存储,例如 (A.B.C)、( A.E) 和 (A.B.D)都是各自一列,要怎么存就很有学问了,最暴力的,这里出现的A反复存,这样对于嵌套层少的,数据量小的,存储空间上可以吃点亏,也不是不可,但是对于大数据量加嵌套层次10几层甚至更深的,这个显然就不科学了,具体怎么解决,请往下看Parquet,ORC文件的实现机制。
    在这里插入图片描述

    图2 嵌套数据列式存储

    三种存储文件格式简介

    1.Parquet文件简介

    Parque支持的计算框架

      Parquet 是语言无关的,而且不与任何一种数据处理框架绑定在一起,适配多种语言和组件,能够与 Parquet 配合的组件有:

    • 查询引擎: Hive, Impala, Pig, Presto, Drill, Tajo, HAWQ, IBM Big SQL
    • 计算框架: MapReduce, Spark, Cascading, Crunch, Scalding, Kite
    • 数据模型: Avro, Thrift, Protocol Buffers, POJOs

      那么 Parquet 是如何与这些组件协作的呢?这个可以通过图3来说明。数据从内存到 Parquet 文件或者反过来的过程主要由以下三个部分组成:

    1. 存储格式 (storage format) parquet-format 项目定义了 Parquet内部的数据类型、存储格式等;
    2. 对象模型转换器 (object model converters) 这部分功能由 parquet-mr项目来实现,主要完成外部对象模型与 Parquet 内部数据类型的映射;
    3. 对象模型 (object models) 对象模型可以简单理解为内存中的数据表示,Avro, Thrift, Protocol Buffers, Hive SerDe, Pig Tuple, Spark SQL InternalRow等这些都是对象模型;

      以上三点我们只做概念上的普及,至于底层实现的代码,可能就需要大家亲自去翻阅下源码或者例子了;
      这里需要注意的是 Avro, Thrift, Protocol Buffers 都有他们自己的存储格式,但是 Parquet 并没有使用他们,而是使用了自己在parquet-format 项目里定义的存储格式。所以如果你的应用使用了 Avro 等对象模型,这些数据序列化到磁盘还是使用的 parquet-mr 定义的转换器把他们转换成 Parquet自己的存储格式,这个思想是不是很熟悉?你外界怎么处理我不管,但是跟我对接,我提供一层中间转换层,统一给你转成我这边协议一致的标准接口,很多架构都采用了这种设计理念。
    在这里插入图片描述

    图3 Parquet 项目的结构

    Parquet数据模型

      理解 Parquet 首先要理解这个列存储格式的数据模型。我们以一个下面这样的 schema 和数据为例来说明这个问题。

    message AddressBook {
     required string owner;
     repeated string ownerPhoneNumbers;
     repeated group contacts {
       required string name;
       optional string phoneNumber;
     }
    }
    

    每个 schema 的结构是这样的:根叫做 message,message 包含多个 fields。每个 field 包含三个属性:repetition, type, name。repetition 可以是以下三种:required(出现 1 次),optional(出现 0 次或者 1 次),repeated(出现 0 次或者多次)。type 可以是一个 group 或者一个 primitive 类型(Int, Long, String)。

      这个 schema 中每条记录表示一个人的 AddressBook。有且只有一个 owner,owner 可以有 0 个或者多个 ownerPhoneNumbers,owner 可以有 0 个或者多个 contacts。每个 contact 有且只有一个 name,这个 contact 的 phoneNumber 可有可无。这个 schema 可以用图4的树结构来表示。
      Parquet 格式的数据类型没有复杂的Map, List, Set 等,而是使用 repeated fieldsgroups 来表示。例如 ListSet 可以被表示成一个 repeated field,Map 可以表示成一个包含有 key-value 对的 repeated field,而且 key 是 required 的,而ORC自身就有struct,map这种复杂数据类型,二者在则个设计理念就产生了偏差。
    在这里插入图片描述

    图4 AddressBook 的树结构表示

    Parquet 文件的存储格式

      那么如何把内存中每个 AddressBook 对象按照列式存储格式存储下来呢?
      在 Parquet 格式的存储中,一个 schema 的树结构有几个叶子节点,实际的存储中就会有多少 column。例如上面这个 schema 的数据存储实际上有四个 column,如图5 所示。
    在这里插入图片描述

    图5 AddressBook 实际存储的列

      Parquet 文件在磁盘上的分布情况如图6 所示。所有的数据先按一定的行数被水平切分成 Row group,如一个1亿行的文件,每1千万行为一个 Row group,就有10个Row group,当然实际情况并不一定是平均的,我只是说明问题,模拟数据如下:

    4-byte magic number “PAR1”
    <Column 1 Chunk 1 + Column Metadata>
    <Column 2 Chunk 1 + Column Metadata>

    <Column N Chunk 1 + Column Metadata>
    <Column 1 Chunk 2 + Column Metadata>
    <Column 2 Chunk 2 + Column Metadata>

    <Column N Chunk 2 + Column Metadata>

    <Column 1 Chunk M + Column Metadata>
    <Column 2 Chunk M + Column Metadata>

    <Column N Chunk M + Column Metadata>
    File Metadata
    4-byte length in bytes of file metadata
    4-byte magic number “PAR1”

      一个 Row group包含这个 Row group 对应的区间内的所有列的 column chunk;
      一个 column chunk 负责存储某一列的数据,这些数据是这一列的 Repetition levels, Definition levelsvalues(详见后文)。一个 column chunk 是由 Page组成的;
      Page 是压缩和编码的单元,对数据模型来说是透明的。一个 Parquet 文件最后是 Footer,存储了文件的元数据信息和统计信息。Row group 是数据读写时候的缓存单元,所以推荐设置较大的 Row group 从而带来较大的并行度,当然也需要较大的内存空间作为代价。一般情况下推荐配置一个 Row group 大小 1G,一个 HDFS 块大小 1G,一个 HDFS 文件只含有一个块,注意这里说的是一般,不是一定哟,这个值还是要根据实际场景和你集群自身配置以及数据文件的大小来决定的,比如你要将集群内的一个parquet文件推送给某个mysql做app运用,这个时候如果你采用这个配置,及其可能造成数据倾斜,因为mysql不一定是分布式,这个时候你要是一个parquet文件只有一个块,你反而要自己reparation了;
    总结:Row group > column chunk > PageFooter存储元数据;

    在这里插入图片描述

    图6 Parquet 文件格式在磁盘的分布

      拿我们的这个 schema 为例,在任何一个 Row group 内,会顺序存储四个 column chunk。这四个 column 都是 string 类型。这个时候 Parquet 就需要把内存中的 AddressBook 对象映射到四个 string 类型的 column 中。如果读取磁盘上的 4 个 column 要能够恢复出 AddressBook 对象。这就用到了我们前面提到的 “record shredding and assembly algorithm”。

    Striping/Assembly算法

      这里解答前面列存储简介对于嵌套数据类型列式存储Parquet的实现,我们除了存储数据的 value 之外还需要两个变量 Repetition Level(R), Definition Level(D) 才能存储其完整的信息用于序列化和反序列化嵌套数据类型。Repetition LevelDefinition Level 可以说是为了支持嵌套类型而设计的,但是它同样适用于简单数据类型。在 Parquet 中我们只需定义和存储 schema 的叶子节点所在列的 Repetition LevelDefinition Level

    Definition Level

      嵌套数据类型的特点是有些 field 可以是空的,也就是没有定义。如果一个 field 是定义的,那么它的所有的父节点都是被定义的。从根节点开始遍历,当某一个 field 的路径上的节点开始是空的时候我们记录下当前的深度作为这个 field 的 Definition Level。如果一个 field 的 Definition Level 等于这个 field 的最大 Definition Level 就说明这个 field 是有数据的。对于 required 类型的 field 必须是有定义的,所以这个 Definition Level 是不需要的。在关系型数据中,optional 类型的 field 被编码成 0 表示空和 1 表示非空(或者反之)。

    Repetition Level

      记录该 field 的值是在哪一个深度上重复的。只有 repeated 类型的 field 需要 Repetition Level,optional 和 required 类型的不需要。Repetition Level = 0 表示开始一个新的 record。在关系型数据中,repetion level 总是 0。
      下面用 AddressBook 的例子来说明 Striping 和 assembly 的过程,对于每个 column 的最大的 Repetion Level 和 Definition Level 如图7 所示。

    在这里插入图片描述

    图7 AddressBook 的 Max Definition Level 和 Max Repetition Level

    图6结果得来的思路解析
    第1步:打开图4;
    第2步:从根节点开始从左到右深度优先搜索遍历叶子节点
    第3步:判断叶子节点的repetition类型:
    第3.1步:如果为required(出现 1 次),说明该叶子节点不可能为空,除非他的父级节点为空,直接找到该叶子节点父节点所在的深度level就是这一列的Max Definition Level,如owner和contacts.name;同样的道理,required(出现 1 次),optional(出现 0 次或者 1 次),说明该叶子节点不可能重复,除非他的父级节点重复,直接找到该叶子节点父节点所在的深度level就是 这一列的Max Repetition Level;
    第3.2步 如果为optional(出现 0 次或者 1 次),repeated(出现 0 次或者多次),说明该叶子节点可能出现空,如ownerPhoneNumbers和contacts.phoneNumber,那该叶子节点所在的深度就是Max Definition Level,而只有repeated(出现 0 次或者多次)类型的叶子节点才有可能出现重复,如ownerPhoneNumbers,所以这种叶子节点的深度就是这一列的 Max Repetition Level;

      下面这样两条 record:

    AddressBook {
     owner: "Julien Le Dem",
     ownerPhoneNumbers: "555 123 4567",
     ownerPhoneNumbers: "555 666 1337",
     contacts: {
       name: "Dmitriy Ryaboy",
       phoneNumber: "555 987 6543",
     },
     contacts: {
       name: "Chris Aniszczyk"
     }
    }
    AddressBook {
     owner: "A. Nonymous"
    }
    

      以 contacts.phoneNumber 这一列为例,"555 987 6543"这个 contacts.phoneNumber 的 Definition Level 是最大 Definition Level=2。而如果一个 contact 没有 phoneNumber,那么它的 Definition Level 就是 1。如果连 contact 都没有,那么它的 Definition Level 就是 0。

      下面我们拿掉其他三个 column 只看 contacts.phoneNumber 这个 column,把上面的两条 record 简化成下面的样子:

    AddressBook {
     contacts: {
       phoneNumber: "555 987 6543"
     }
     contacts: {
     }
    }
    AddressBook {
    }
    

      这两条记录的序列化过程如图8所示:
    在这里插入图片描述

    图8 一条记录的序列化过程

      如果我们要把这个 column 写到磁盘上,磁盘上会写入这样的数据,如图9所示:
    在这里插入图片描述

    图9 一条记录的磁盘存储

      注意:NULL 实际上不会被存储,如果一个 column value 的 Definition Level 小于该 column 最大 Definition Level 的话,那么就表示这是一个空值。
      下面是从磁盘上读取数据并反序列化成 AddressBook 对象的过程:

    1. 读取第一个三元组 R=0, D=2: Value=”555 987 6543”,R=0 表示是一个新的 record,要根据 schema 创建一个新的 nested record 直到 Definition Level=2,D=2 说明 Definition Level=Max Definition Level,那么这个 Value 就是 contacts.phoneNumber 这一列的值,赋值操作 contacts.phoneNumber=”555 987 6543”。

    2. 读取第二个三元组 R=1, D=1:R=1 表示不是一个新的 record,是上一个 record 中一个新的 contacts,D=1 表示 contacts 定义了,但是 contacts 的下一个级别也就是 phoneNumber 没有被定义,所以创建一个空的 contacts。

    3. 读取第三个三元组 R=0, D=0:R=0 表示一个新的 record,根据 schema 创建一个新的 nested record 直到 Definition Level=0,也就是创建一个 AddressBook 根节点。

      可以看出在 Parquet 列式存储中,对于一个 schema 的所有叶子节点会被当成 column 存储,而且叶子节点一定是 primitive 类型的数据。对于这样一个 primitive 类型的数据会衍生出三个 sub columns (R, D, Value),也就是从逻辑上看除了数据本身以外会存储大量的 Definition Level 和 Repetition Level。那么这些 Definition Level 和 Repetition Level 是否会带来额外的存储开销呢?实际上这部分额外的存储开销是可以忽略的。因为对于一个 schema 来说 level 都是有上限的,而且非 repeated 类型的 field 不需要 Repetition Level,required 类型的 field 不需要 Definition Level,也可以缩短这个上限。例如对于 Twitter 的 7 层嵌套的 schema 来说,只需要 3 个 bits 就可以表示这两个 Level 了。
      对于存储关系型的 record,record 中的元素都是非空的(NOT NULL in SQL)。Repetion Level 和 Definition Level 都是 0,所以这两个 sub column 就完全不需要存储了。所以在存储非嵌套类型的时候,Parquet 格式也是一样高效的。
      上面演示了一个 column 的写入和重构,那么在不同 column 之间是怎么跳转的呢,这里用到了有限状态机的知识,这里不多做介绍。

    Parquet文件总结

      以上就是Parquet文件的简单介绍,Parquet 列式存储带来的性能上的提高在业内已经得到了充分的认可,特别是当你们的表非常宽(column 非常多)的时候,Parquet 无论在资源利用率还是性能上都优势明显,Spark 已经将 Parquet 设为默认的文件存储格式,Cloudera 投入了很多工程师到 Impala+Parquet 相关开发中(目前ORC文件不支持Impala),Hive/Pig 都原生支持 Parquet。Parquet 现在为 Twitter 至少节省了 1/3 的存储空间,同时节省了大量的表扫描和反序列化的时间。这两方面直接反应就是节约成本和提高性能,而和Parquet文件关系不错的Snappy压缩方式也单独对Parquet文件做过优化,一般情况下采用Parquet文件+Snappy压缩的组合做大数据的文件存储格式,如Hive的表存储类型,如果说 HDFS 是大数据时代文件系统的事实标准的话,Parquet 就是大数据时代存储格式的事实标准。

    2.ORC文件简介

    ORC存储

      ORC (Optimized Row Columnar)存储源自RC这种存储格式,可以认为是RC的二代,这也就是为什么现在RC没什么地位的原因,跟Parquet一样,也是列式存储,先按照行水平切割,再按列垂直切割存储。
      ORC相对于Parquet独有的特性,比如支持update操作,支持ACID(关系型数据库的事务),本身支持struct,array复杂类型.你可以使用复杂类型构建一个类似parquet的嵌套式数据架构;对比缺点也跟明显,嵌套层数非常多时,写起来非常麻烦和复杂,而parquet提供的schema表达方式更容易表示出多级嵌套的数据类型,另外目前不支持impala,也是硬伤之一。

    数据模型

      `和Parquet不同,ORC原生是不支持嵌套数据格式的,而是通过对复杂数据类型特殊处理的方式实现嵌套格式的支持,例如对于如下的hive表:

    
    CREATE TABLE `orcStructTable`(
      `name` string,
      `course` struct<course:string,score:int>,
      `score` map<string,int>,
      `work_locations` array<string>
    )
    

      在ORC的结构中包含了复杂类型列和原始类型,前者包括LIST、STRUCT、MAP和UNION类型,后者包括BOOLEAN、整数、浮点数、字符串类型等,其中STRUCT的孩子节点包括它的成员变量,可能有多个孩子节点,MAP有两个孩子节点,分别为key和value,LIST包含一个孩子节点,类型为该LIST的成员类型,UNION一般不怎么用得到。每一个Schema树的根节点为一个Struct类型,所有的column按照树的中序遍历顺序编号。
      ORC只需要存储schema树中叶子节点的值,而中间的非叶子节点只是做一层代理,它们只需要负责孩子节点值得读取,只有真正的叶子节点才会读取数据,然后交由父节点封装成对应的数据结构返回。
      而ORC的实现,更加简单直白一些,类似元素是否为Null的信息,就是一组bit位图,而对于元素个数不定的结构,如List,Map等数据结构,则在虚拟的父结构中维护了一个所拥有的子元素数量的信息。这样的带来的问题是,由单纯的某一叶节点列元素的数据出发,是无法独立构建复原出该列数据的结构层次的,需要借助父元素的辅助元数据才能完整复原,这一点设计思想,还是不如Parquet的Striping/Assembly算法的,过分的依赖于父节点的辅助元数据,就是为什么ORC相对Parquet在多层次的嵌套结构是显得更吃CPU和内存等资源的原因之一吧。
    l

    文件结构

      ORC文件以二进制方式存储,所以是不可以直接读取,ORC文件也是自解析的,它包含许多的元数据,这些元数据都是同构ProtoBuffer进行序列化的。ORC的文件结构如图10,其中涉及到如下的概念:
    ORC文件:保存在文件系统上的普通二进制文件,一个ORC文件中可以包含多个stripe,每一个stripe包含多条记录,这些记录按照列进行独立存储,对应到Parquet中的row group的概念。
    文件级元数据:包括文件的描述信息PostScript、文件meta信息、所有stripe的信息和文件schema信息。
    stripe:一组行形成一个stripe,每次读取文件是以行组为单位的,一般为HDFS的块大小,保存了每一列的索引和数据。
    stripe元数据:保存stripe的位置、每一个列的在该stripe的统计信息以及所有的stream类型和位置。
    row group:索引的最小单位,一个stripe中包含多个row group,默认为10000个值组成。
    stream:一个stream表示文件中一段有效的数据,包括索引和数据两类。索引stream保存每一个row group的位置和统计信息,数据stream包括多种类型的数据,具体需要哪几种是由该列类型和编码方式决定。
    在这里插入图片描述

    图10 orc文件存储格式
       在ORC文件中保存了三个层级的统计信息,分别为文件级别、stripe级别和row group级别的,他们都可以用来根据Search ARGuments(谓词下推条件)判断是否可以跳过某些数据,在统计信息中都包含成员数和是否有null值,并且对于不同类型的数据设置一些特定的统计信息。

    数据访问

      读取ORC文件是从尾部开始的,第一次读取16KB的大小,尽可能的将Postscript和Footer数据都读入内存。文件的最后一个字节保存着PostScript的长度,它的长度不会超过256字节,PostScript中保存着整个文件的元数据信息,它包括文件的压缩格式、文件内部每一个压缩块的最大长度(每次分配内存的大小)、Footer长度,以及一些版本信息。在Postscript和Footer之间存储着整个文件的统计信息(上图中未画出),这部分的统计信息包括每一个stripe中每一列的信息,主要统计成员数、最大值、最小值、是否有空值等。
      接下来读取文件的Footer信息,它包含了每一个stripe的长度和偏移量,该文件的schema信息(将schema树按照schema中的编号保存在数组中)、整个文件的统计信息以及每一个row group的行数。
      处理stripe时首先从Footer中获取每一个stripe的其实位置和长度、每一个stripe的Footer数据(元数据,记录了index和data的的长度),整个striper被分为index和data两部分,stripe内部是按照row group进行分块的(每一个row group中多少条记录在文件的Footer中存储),row group内部按列存储。每一个row group由多个stream保存数据和索引信息。每一个stream的数据会根据该列的类型使用特定的压缩算法保存。在ORC中存在如下几种stream类型:
    PRESENT:每一个成员值在这个stream中保持一位(bit)用于标示该值是否为NULL,通过它可以只记录部位NULL的值
    DATA:该列的中属于当前stripe的成员值。
    LENGTH:每一个成员的长度,这个是针对string类型的列才有的。
    DICTIONARY_DATA:对string类型数据编码之后字典的内容。
    SECONDARY:存储Decimal、timestamp类型的小数或者纳秒数等。
    ROW_INDEX:保存stripe中每一个row group的统计信息和每一个row group起始位置信息。
      在初始化阶段获取全部的元数据之后,可以通过includes数组指定需要读取的列编号,它是一个boolean数组,如果不指定则读取全部的列,还可以通过传递SearchArgument参数指定过滤条件,根据元数据首先读取每一个stripe中的index信息,然后根据index中统计信息以及SearchArgument参数确定需要读取的row group编号,再根据includes数据决定需要从这些row group中读取的列,通过这两层的过滤需要读取的数据只是整个stripe多个小段的区间,然后ORC会尽可能合并多个离散的区间尽可能的减少I/O次数。然后再根据index中保存的下一个row group的位置信息调至该stripe中第一个需要读取的row group中。
      由于ORC中使用了更加精确的索引信息,使得在读取数据时可以指定从任意一行开始读取,更细粒度的统计信息使得读取ORC文件跳过整个row group,ORC默认会对任何一块数据和索引信息使用ZLIB压缩,因此ORC文件占用的存储空间相对也更小,带来的牺牲就是CPU和内存等计算资源耗损,就是以空间换时间的代价,可参考三种文件实践对比。

    3.RC文件简介

      RC File文件格式,因为是ORC的基石,实现的功能就比较简单,基本就是列存储的精髓实现,先水平按行切割,再垂直切按列切割,然后每个行组的Metadata里维护了行组的纪录数和每个column及每个Column纪录的长度,编码方面Metadata使用RLE编码,Column Data使用Gzip等压缩格式(取决于写入方,比如MR程序),相对简单,也因为ORC的出现,基本已经完全被取代,没什么江湖地位。

    三种文件实践对比

    cloudera blog测试结果

    在这里插入图片描述

    图11 存储文件最大的谎言

      图11,对于很多人来说并不陌生,其实这样图片出自著名的cloudera blog中的一篇ORCFile in HDP 2: Better Compression, Better Performance,图片想表达的思想很简单,ORC文件天下第一,因为是cloudera blog,而且又是英文版的,以cloudera 在大数据集群的地位,这张图片也就被很多人拿出来当做吹捧ORC的圣经;

    百度测试结论

      之前瞟了一眼百度关于ORC和Parquet文件的测试报告,可惜拿不出来,结论可以参考下,之前百度采用了Array{Map{Map}}这样的嵌套数据做的测试,400G的ORC数据文件,吃了1000G的内存,而Parquet相对好点,结论大概是ORC压缩比高,但是吃CPU和内存,适合存储空间吃紧,计算资源强大的集群,既时间换空间;Parquet适合存储空间巨大,计算资源相对紧缺的资源,适合空间换时间,但是也提醒到,不能一概而论,如果可以,最好结合自己的数据结构做一下测试,另外如果集群有打算架Impala的想法,那么就要注意了,还是Parquet文件好,因为ORC目前不支持。

    Parquet和ORC对比总结

    表1 Parquet和ORC对比总结
    性状ParquetORC
    现状Apache顶级项目Apache顶级项目
    列式存储支持支持
    开发语言JavaJava
    嵌套结构完美支持支持起来比较复杂,比较耗CPU,内存等资源
    ACID(事务)不支持支持
    Update,Delete操作不支持支持
    元数据支持粗粒度的索引支持粗粒度的索引
    查询性能具体要看数据文件结构分布,一般ORC略优具体要看数据文件结构分布,一般ORC略优
    压缩能力ORC略优ORC略优
    支持的查询引擎常见的大数据查询引擎都支持不支持Impala

      总结:注意不要被关系型数据库所迷惑ACID(事务)Update,Delete操作在大数据里面是很鸡肋的,不要因为这个条件来决定使用ORC合适Parquet,因为1T的数据里面有几条数据去做Update和Delete吗?没必要的,事务就跟没必要了,因为事务防止的危险如脏读等场景,一般在大数据场景下不太要求,或者采用其他的架构来避免。

    个人建议的文件选取

      具体还是要看自己数据文件的结构,结合测试会好一点,但是如果非要我说一种搭配,可以选取Parquet文件+Snappy压缩作为热数据的存储,相对于ORC牺牲点存储空间,而且存储空间快速填充也可以成为你集群扩容的资本,毕竟如果自己搭建集群的话,内存一般比较局限,你可以评估存储不够为理由要求运维机器,从而达到扩容集群内存的目的,谈判的艺术性,一般人我不告诉他。
      而冷数据,如三年前的数据,可以采取牺牲时间换取空间的方式,采用ORC文件+Gzip压缩格式,进一步archive(归档)掉,别人申请三年前的数据,需要行政上约定提前一周时间提出申请。

    常见压缩格式对比及搭配建议

      Hadoop支持压缩格式,可以用指令hadoop checknative来获取自己Hadoop集群默认支持的压缩格式,注意这个hadoop是自己安装的hadoop目录下/tools/hadoop/hadoop-2.8.5/bin/hadoop指令hadoop,我做了环境变量

    
    [liuxiaowei@shucang-01 ~]$ hadoop checknative
    20/05/11 18:47:44 INFO bzip2.Bzip2Factory: Successfully loaded & initialized native-bzip2 library system-native
    20/05/11 18:47:44 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
    Native library checking:
    hadoop:  true /tools/hadoop/hadoop-2.8.5/lib/native/libhadoop.so.1.0.0
    zlib:    true /lib64/libz.so.1
    snappy:  true /lib64/libsnappy.so.1
    lz4:     true revision:10301
    bzip2:   true /lib64/libbz2.so.1
    openssl: false Cannot load libcrypto.so (libcrypto.so: cannot open shared object file: No such file or directory)!
    
    

      具体对比如表2:

    表2 Hadoop支持压缩格式
    压缩格式可分割算法扩展名Linux工具
    gzipDEFLATE.gzgzip
    lzo是(加索引)LZO.lzolzop
    snappySnappy.snappy
    Bzip2Bzip2.bz2bzip2
    deflateDEFLATE.deflate
    zipZIP.zipzip

      基于128MB文本文件的压缩性能测试横向比较,具体如表3:

    表3 基于128MB`文本文件`的压缩性能测试横向比
    编码器压缩时间(秒)解压缩时间(秒)压缩文件大小压缩比率
    Deflate6.886.8024,866,25918.53%
    gzip6.686.8824,866,27118.53%
    bzip23,012.3424.3119,270,21714.36%
    lzo1.697.0040,946,70430.51%
    lzop1.705.6240,946,74630.51%
    Snappy1.316.6646,108,18934.45%
    • Gzip压缩:
      优点:压缩率比较高,压缩/解压速度也比较快,hadoop本身支持。
      缺点:不支持分片。
      应用场景:当每个文件压缩之后在1个block块大小内,可以考虑用gzip压缩格式,冷数据archive(归档)

    • lzo压缩
      优点:压缩/解压速度也比较快,合理的压缩率,支持分片,是Hadoop中最流行的压缩格式,支持Hadoop native库。
      缺点:压缩率比gzip要低一些,Hadoop本身不支持,需要安装,如果支持分片需要建立索引,还需要指定inputformat改为lzo格式。
      应用场景:一个很大的文本文件,压缩之后还大于200M以上的可以考虑,而且单个文件越大,lzo优点越明显。

    • snappy压缩
      优点:支持Hadoop native库,高速压缩速度和合理的压缩率,hadoop-2.8.5自带;
      缺点:不支持分片,压缩率比gzip要低;
      应用场景:当MapReduce作业的map输出的数据比较大的时候,作为map到reduce的中间数据的压缩格式;Parquet文件的默认压缩方式。

    • bzip2压缩
      优点:支持分片,具有很高的压缩率,比gzip压缩率都高,Hadoop本身支持,但不支持native。
      缺点:压缩/解压速度慢,不支持Hadoop native库。
      应用场景:适合对速度要求不高,但需要较高的压缩率的时候,可以作为mapreduce作业的输出格式,输出之后的数据比较大,处理之后的数据需要压缩存档减少磁盘空间并且以后数据用得比较少的情况。

      总结:压缩比:bzip2 > gzip > lzo > snappy压缩速度:snappy > lzo> gzip > bzip2

      所有压缩算法都必须在压缩程度和压缩/解压缩速度之间进行权衡。我们必须根据我们的场景选择这些编解码器,假设我们必须对很少查询的数据进行存档,然后我们必须使用像Bzip2这样的编解码器,如果我们经常需要访问我们的数据,我们可以使用像Snappy这样的算法给我们最快的数据压缩和解压缩。
      个人推荐:可以选取Parquet文件+Snappy压缩作为热数据的存储,相对于ORC牺牲点存储空间,采用ORC文件+Gzip压缩格式或者ORC文件+bzip2 压缩格式,进一步archive(归档)掉,别人申请三年前的数据,需要行政上约定提前一周时间提出申请。

    参考文献

    1. Parquet与ORC:高性能列式存储格式
    2. 深入分析 Parquet 列式存储格式
    3. RC ORC Parquet 格式比较和性能测试
    4. ORCFile in HDP 2: Better Compression, Better Performance
    5. Hadoop_常用存储与压缩格式
    6. Parquet官网
    展开全文
  • orcparquet选型

    2021-02-09 00:36:38
    SparkSQL选orc还是parquet? hive有三种默认的存储格式,TEXT、ORCPARQUET。TEXT是默认的格式,ORCPARQUET是列存储格式,占用空间和查询效率是不同的,专门测试过后记录一下。 一:建表语句差别 create table ...

    SparkSQL选orc还是parquet?


    hive有三种默认的存储格式,TEXT、ORC、PARQUET。TEXT是默认的格式,ORC、PARQUET是列存储格式,占用空间和查询效率是不同的,专门测试过后记录一下。


    一:建表语句差别

    create table if not exists text(
    a bigint
    ) partitioned by (dt string)
    row format delimited fields terminated by ‘\001’
    location ‘/hdfs/text/’;

    create table if not exists orc(
    a bigint)
    partitioned by (dt string)
    row format delimited fields terminated by ‘\001’
    stored as orc
    location ‘/hdfs/orc/’;

    create table if not exists parquet(
    a bigint)
    partitioned by (dt string)
    row format delimited fields terminated by ‘\001’
    stored as parquet
    location ‘/hdfs/parquet/’;

    其实就是stored as 后面跟的不一样


    二:HDFS存储对比

    parquetorctext
    709M275M1G
    687M249M1G
    647M265M1G

    三:查询时间对比

    parquetorctext
    36.45126.13342.574
    38.42529.35341.673
    36.64727.82543.938

    四:文件如何生成

    val sparkSession = SparkSession.builder().master(“local”).appName(“pushFunnelV3”).getOrCreate()
    val javasc = new JavaSparkContext(sparkSession.sparkContext)
    val nameRDD = javasc.parallelize(util.Arrays.asList("{‘name’:‘zhangsan’,‘age’:‘18’}", “{‘name’:‘lisi’,‘age’:‘19’}”)).rdd;
    sparkSession.read.json(nameRDD).write.mode(SaveMode.Overwrite).csv("/data/aa")
    sparkSession.read.json(nameRDD).write.mode(SaveMode.Overwrite).orc("/data/bb")
    sparkSession.read.json(nameRDD).write.mode(SaveMode.Overwrite).parquet("/data/cc")

    展开全文
  • ORCParquet比较入门

    2021-02-03 14:11:56
    ORCParquet 都是 Hadoop 生态系统中流行的开源列文件存储格式,在效率和速度方面非常相似,最重要的是,它们旨在加快大数据分析工作负载。使用 ORC 文件与处理 Parquet 文件一样简单,因为它们提供了高效的读写...
  • 合并hdfs小文件工具(orcparquet) Hadoop。 合并hdfs小文件工具(orcparquet) 。 合并hdfs上的parquetorc格式小文件小工具 merge files parquet orc
  • Hive ORCParquet

    万次阅读 2016-05-21 22:19:35
    目前在开源实现中,最有名的列式存储引擎莫过于ParquetORC,并且他们都是Apache的顶级项目,在数据存储引擎方面发挥着重要的作用。 本文将重点讲解ORC文件存储格式,Parquet暂不深入说明,后续抽时间整理。
  • orcparquet格式的选择

    2020-07-25 23:11:10
    对于orcparquet这两种列式存储格式,网上能找到大量的介绍以及对比,此处简单总结一下: orc VS parquetorc存储压缩率比parquet要高; 一般来说,orc读取效率比parquet要高; parquet支持嵌套数据格式,orc...
  • Impala推荐使用parquet格式,不支持ORC,Rcfile - Hive 0.x版本推荐使用rcfile - PrestoDB推荐使用ORC - Spark支持ORC,Parquet,Rcfile ParquetORC对比 orc.compress:表示ORC文件的压缩类型,...
  • parquet不支持增删改。 ---------------------------------------------------------- 因为业务要求,需要对Hive表进行delete,在官网查询后,发现update和delete是一类问题。在此总结下如何实现Hive表的delete...
  • ORCParquet文件对比

    千次阅读 2020-08-10 14:58:38
    ORCParquet总结如下: 转载:https://blog.csdn.net/qq_22222499/article/details/106534767?utm_medium=distribute.pc_relevant.none-task-blog-baidulandingword-6&spm=1001.2101.3001.4242
  • ORCParquet均为列式存储结构,那么他们有什么不同呢? Apache Parquet 源自google Dremel 系统,Parquet 相当一Dremel中的数据存储引擎,而Apache顶级开源醒目 Drill正式Dremel的开源实现. Apache Parquet 最初的...
  • Hadoop数据存储orcparquet格式的选择

    千次阅读 2019-09-01 17:40:20
    对于orcparquet这两种列式存储格式,网上能找到大量的介绍以及对比,此处简单总结一下: orc VS parquetorc存储压缩率比parquet要高; 一般来说,orc读取效率比parquet要高; parquet支持嵌套...
  • ORCParquet对比 1,orc不支持嵌套结构,parquet支持嵌套结构 2,orc与hive的兼容性强,作为hive的常用存储格式 3,orc的压缩率较高 4,orc导入数据和数据查询的的速度比parquet
  • ORCParquet表的压缩

    2021-01-05 10:33:28
    除了直接配置MapReduce压缩功能外,Hive的ORC表和Parquet表直接支持表的压缩属性。 但支持的压缩格式有限,ORC表支持None、Zlib、Snappy压缩,默认为ZLIB压缩。但这3种压缩格式不支持切分,所以适合单个文件不是...
  • hive文件存储格式orc,parquet,avro对比

    千次阅读 2019-10-13 19:01:01
    orc文件存储格式 ...ORC文件:保存在文件系统上的普通二进制文件,一个ORC文件中可以包含多个stripe,每一个stripe包含多条记录,这些记录按照列进行独立存储,对应到Parquet中的row group的概念。 文...
  • --设置parquet表的压缩格式为SNAPPY set parquet.compression=SNAPPY; --设置orc表的压缩格式为SNAPPY set orc.compress=SNAPPY
  • 大数据处理文件格式之ORCParquet选择 1. 背景 在大数据处理中,因为无法按照传统方式将海量数据存放到mysql中。所以各个框架都想办法将这些数据很好存放起来,既能保证数据安全,有可以确保数据查询地性能。 按照...
  • ORCParquet等列式存储的优点前言ParquetORC: 前言 ORCParquet都是高性能的存储方式,这两种存储格式总会带来存储和性能上的提升。 Parquet: 1)Parquet支持嵌套的数据模型,类似于Protocol Buffers,每...
  • Parquet 行组(Row Group):按照行将数据物理上划分为多个单元,每一个行组包含一定的行数。一个行组包含这个行组对应的区间内的所有列的列块 官方建议 更大的行组意味着更大的列块,使得能够做更大的序列IO。我们...
  • 本文编译自IBM开发者社区,主要描述了HDFS中小的ORCParquet文件的问题,以及这些小文件如何影响Big SQL的读取性能,并探索了为了提高读取性能,使用现有工具将小文件压缩为大文件的可能解决方案。 简介 众所周知,...
  • create table student_txn (id int, name string ) //指定存储格式 stored as parquet //指定压缩格式(ORC只支持snappy) tblproperties ('orc.compress'='snappy');

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,734
精华内容 2,293
关键字:

orcparquet