ORC文件stripeSize引发的一起血案
1. 背景
对hive做数据更新,由于不支持事务,所以需要先对原表进行数据备份,即存到另外一张表结构一样的hive表中,其中hive表数据存储格式为ORC。
2. ORC文件结构介绍
ORC的全称是(Optimized Row Columnar),ORC文件格式是一种Hadoop生态圈中的列式存储格式,主要作用是降低文件系统的存储空间和加速查询。
文件结构:
ORC FILE包含了一组组的行数据,被称作为stripes,此外还包含其他file footer等额外信息。
ORC FILE的最后还包含一个postscript区域,该区域主要用来存储压缩参数以及压缩页脚的大小。
在默认情况下,一个stripe的大小为250MB。大尺寸的stripes使得从HDFS读数据更高效。
文件结构简略图
3. 案发现场
通过spark sql拷贝hive表数据到另外一张相同表结构的hive表中,配置很大的资源仍然很快oom。
hive表的数据存储格式为orcfile,其中,hive表的数据为8亿条左右,orc文件为54.6G,实际大小大概为400G。
日志表现:JVM内存年轻代和老年代都被占满,触发FULL GC,通过使用测试时候测试的相同数据量的资源配置仍然无法解决FULL GC问题。
疑问:为什么测试阶段,针对相同数据量,相同资源配置,作业能成功,到现网环境就不行,到底有什么差别?
通过jmap命令
执行命令:jmap -dump:format=b,file=/tmp/pid.dump pid,通过获取dump文件,可以离线分析作业运行时jvm堆内存,检查内存泄漏,检查严重影响性能的大对象,各种对象所占用的内存大小等。
dump文件日志分析图如下所示:
分析dump文件找出占用超大堆内存的具体原因,metadata中的stripeStats占用的堆内存巨大,通过ORC文件的结构可以得出,orc文件的stripe数量过多,导致读取orc文件时的metadata占用超大内存。
为什么该文件的stripe数量会如此之大?
结合现网环境排查出测试环境和现网环境的差异:测试数据是由很多128M的文件构成,现网数据则是由CDM生成的一个大文件,直接以orc的格式存储到了hdfs文件系统中,导致在做数据备份的时候,spark读取的是整个大文件,通过分析CDM代码,得出原因:stripeSize大小是固定的,针对大文件就会生成很多的stripes。
代码分析:
其实,我们根据堆栈异常也可以验证是hive在读取orc文件,初始化Metadata的时候,会以stripe为单位进行元数据的统计,如下异常所示:
4. 结论
orc文件本身的大小并不会真正影响读取数据时metadata的大小,真正影响的是stripe的数量,合理设置stripSize才是王道,stripSize可以设置为可配置项,才能以变应变。
- 点赞
- 收藏
- 关注作者
评论(0)