数据治理 - TextFile格式Hive表压缩优化实践

背景

由于缺少统一的规范落地和平台工具支持,大部分的业务人员、技术人员在建表时并没有考虑到 Hive表 格式的重要性。随着数据量的上升,TextFile格式的存储浪费情况越来越严重

在数仓建设中,除了ODS层的表使用TextFile来加快数据加载外,其他层的 Hive 表都应该使用具有高压缩比的 ORC 等存储格式

Hive表 具有多种存储格式,这里先简单介绍两种存储格式:TextFile 和 ORC

TextFile

数据按行存储,默认无压缩,可选择数据压缩方式

TextFile格式的 Hive表,数据加载速度快。数仓的 ODS层 一般使用 TextFile 格式来加快数据的加载速度

TextFile具有几个明显的缺点

  1. 数据未压缩时,存储空间消耗大
  2. 数据压缩后无法进行分割和合并
  3. 数据按行存储
    1. 一行数据类型难以保持一致,压缩比低
    2. 查询只涉及某几个列时,它也会把整行数据都读取出来,不能跳过不必要的列读取

ORC

是RCFile格式的优化版,即 Optimized RCFile

数据按列存储,对于一行记录,只会读取查询需要的列数据,可以加快查询速度

由于列数据格式一致,通常具有较高的压缩比,可以有效的减少存储空间

存储大小比较

笔者对一组TextFile格式的Hive表进行了压缩测试,可以发现:ORC格式的存储大小通常只有TextFile格式的一半,甚至更少

对于一些int类型列比较多的表,ORC的存储大小甚至只是TextFile格式的1.88%,压缩比高达50多倍!

压缩前的思考

先不考虑如何将TextFile格式转化成ORC应该怎么做,先来思考一下存储格式的变化会对原有生产任务带来哪些影响

存储格式的变化

Hive Meta中有一张表SDS,其中记录了Hive表的输入输出格式类:INPUT_FORMAT、OUTPUT_FORMAT

不同的存储格式,会使用不同的输入输出格式类

存储格式INPUT_FORMATOUTPUT_FORMAT
TextFileorg.apache.hadoop.mapred.TextInputFormatorg.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
ORCorg.apache.hadoop.hive.ql.io.orc.OrcInputFormatorg.apache.hadoop.hive.ql.io.orc.OrcOutputFormat

对于Hive SQL任务,会自动根据SQL转化成对应的任务,存储格式的变化不会影响到任务。而对于代码编写的MR等任务,在读写数据时会指定对应的数据读取方式,存储格式的变化会导致这类任务的失败

表数据体积的变化

因为ORC的压缩比较高,通常ORC表的数据体积只有TextFile表的一半不到,有些特殊的表甚至能达到超高的压缩比

对于Hive SQL任务,Map阶段会根据表的大小设定Map Task的数量。由于ORC表的数据体积较少,相比于TextFile表,ORC表的Map Task数量较少

如果ORC表具有超高的压缩比,比如ORC表只有原表的1/50,那么ORC表的Map Task数量可能就会是TextFile表的1/50

TextFile表格式转换成ORC后,由于Map Task的数量减少,可能导致任务的运行耗时变长。通常来说,30%以上的压缩率对Hive SQL任务的影响较小。如果ORC表的压缩率低于30%,下游任务可能需要设置 mapred.max.split.size 来控制Map Task数量的大小

TextFile格式优化

TextFile格式存储空间浪费严重,并且查询效率不如ORC,TextFile格式优化迫在眉睫

如果有一张Hive表的存储格式为TextFile,该怎么将其转化成ORC呢?

以下优化方法针对的是Hive的外部分区表

步骤一:复制数据到中间表

  1. 创建一张ORC格式的中间表,中间表的结构与原表完全一致
-- 复制表结构,创建ORC中间表
CREATE EXTERNAL TABLE IF NOT EXISTS <ORC中间表>
LIKE <原表>
STORED AS ORC
  1. 复制数据到中间表
-- set hive.exec.dynamic.partition = true;
-- set hive.exec.dynamic.partition.mode = nonstrict;
INSERT OVERWRITE TABLE <ORC中间表> PARTITION(<分区字段>)
SELECT *
FROM <原表>

步骤二:数据校验

为了避免数据漏刷的情况,在数据复制到中间表之后需要校验一下中间表和原表的数据是否一致

校验规则:

  1. 新旧表数据量一致 - select count(1)
  2. 新旧表分区数量一致 - show partitions <Hive表>

除此之外,还可以校验一些其他规则,比如某个字段的空值率等

步骤三:任务测试

使用ORC格式的中间表,对表生产任务和下游使用数据的任务进行测试

测试通过后,再对原表进行修改

生产任务测试(重要程度:中)

可通过重跑数据生产任务来检测此次变更操作是否异常。正常情况下,Hive表存储格式的变更不会影响到生产任务(通过MR代码等方式生成数据的任务除外)

检测内容:

  1. 生产任务是否成功运行
  2. 生产任务运行耗时和之前比是否异常

下游任务测试(重要程度:高)

影响分析

Hive表的存储格式变更最主要的影响是让Hive表的数据体积发生变化

Hive根据表的大小设置Map Task的数量,ORC格式较TextFile的数据体积小,从TextFile修改到ORC格式时,会导致下游任务的Map Task数量减少,在一定程度上会导致下游任务运行耗时变长

压缩成ORC格式对下游任务的影响程度,主要取决于Hive表的压缩率

压缩率:原数据大小 / 压缩后数据大小

正常情况下,TextFile -> ORC 的压缩率在 30% ~ 50%,压缩率在 30% 以上时,对下游任务的影响较小。如果压缩率在 30% 以下时,可以调整下游任务的 mapred.max.split.size 参数来手动提高Map Task的数量

测试下游任务

检测内容:

  1. 下游任务是否成功运行
  2. 下游任务运行耗时和之前比是否异常

如果下游任务运行耗时明显变长,可以通过调整下游任务的 mapred.max.split.size 参数来手动提高Map Task的数量

步骤四:修改原表存储格式

修改原表存储格式的方式有两种

1)修改原表Location

这种方式的核心思想是,将原表的Location直接指定到中间表的Location上

主要步骤:

  1. 修改原表存储格式
  2. 修改原表Location
  3. 重建原表分区
1. 修改原表存储格式
ALTER TABLE <原表> SET FILEFORMAT ORC
2. 修改原表Location

将原表的Location指向中间表的Location

ALTER TABLE <原表> SET LOCATION '<ORC中间表Location>'

这里有一些需要注意的点:

  1. 注意保存原表Location地址,首先为了可以回滚变更操作,其次在确认变更操作无影响之后可以及时把原Location数据清除
  2. 如果采用修改Location的方式,建议把中间表的表结构删除。多表指向同一个Location时,容易在后续的运维环节中出现“误伤”数据的情况
3. 重建原表分区

Hive Meta中,每个分区都有会记录input_format、output_format和location

input_format和output_format决定表数据的读取方式,和Hive表的存储格式一一对应。因为修改了Hive表的存储格式,所以需要对分区的元数据进行重建,以更新input_format和output_format。该方式修改了location,也会一并更新

-- 1. 删除原表所有分区
ALTER TABLE <原表> DROP PARTITION(<分区字段> <= '最大分区')
 
-- 2. 修复原表分区
MSCK REPAIR TABLE <原表>

2)移动中间表数据到原表目录

通过HDFS的 mv 命令将ORC中间表的数据移动到原表Location下

主要步骤:

  1. 备份原表数据:将原表数据移动到特定目录下,以备回滚操作和删除旧数据
  2. 移动数据:将中间表数据移动到原表Location下
  3. 修改原表存储格式
  4. 重建原表分区
1. 备份原表数据
hadoop fs -mv <原表Location> <临时存放点>
2. 移动数据
hadoop fs -mv <中间表Location> <原表Location>
3. 修改原表存储格式
ALTER TABLE <原表> SET FILEFORMAT ORC
4. 重建原表分区

Hive Meta中,每个分区都有会记录input_format、output_format和location

input_format和output_format决定表数据的读取方式,和Hive表的存储格式一一对应。因为修改了Hive表的存储格式,所以需要对分区的元数据进行重建,以更新input_format和output_format

-- 1. 删除原表所有分区
ALTER TABLE <原表> DROP PARTITION(<分区字段> <= '最大分区')
 
-- 2. 修复原表分区
MSCK REPAIR TABLE <原表>

步骤五:原表数据校验

经过前面的处理后,Hive表的存储格式和数据都已经更新成ORC格式了

需要校验原表新格式的数据是否正常:

  1. 数据量校验:校验数据量是否和之前保持一致
  2. 数据校验:select 一些输出查看数据是否会出现异常

版权声明:本文为qq_38783098原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。