本文编译自IBM开发者社区,主要介绍了HDFS
中小的ORC
和Parquet
文件的问题,以及这些小文件如何影响Big SQL
的读取性能,并探索了为了提高读取性能,使用现有工具将小文件压缩为大文件的可能解决方案。
简介
众所周知,多个Hadoop
小文件(定义为明显小于HDFS
块大小的文件,默认情况下为64MB
)是Hadoop
分布式文件系统(HDFS
)中的一个大问题。HDFS
旨在存储大量数据,理想情况下以大文件的形式存储。在HDFS
中存储大量小文件,而不是存储较少的大文件,这在管理文件的目录树时给NameNode
增加了额外的开销。此外,MapReduce
和其他读取HDFS
文件的作业也会受到负面影响,因为它将涉及与HDFS
的更多通信以获取文件信息。
小文件读取性能问题对于存储格式更为严重,在存储格式中,元数据被嵌入文件中以描述所存储的复杂内容。IBM Db2 Big SQL使用的两种常见文件存储格式是ORC
和Parquet
,这些文件格式以列格式存储数据,以优化读取和过滤列的子集。ORC
和Parquet
格式将有关列和行组的信息编码到文件本身中,因此,在对文件中的数据进行解压缩、反序列化和读取之前,需要处理元数据。由于这种开销,处理以逻辑方式捆绑在一起的这些格式的多个小型文件(例如,属于Big SQL
表或分区的文件)会产生大量成本,并降低IBM Db2 Big SQL
的读取性能。
建议解决方案:压缩
避免在存储级别使用小文件的一个好习惯是对逻辑上属于一起的目录里的小文件进行压缩。在Big SQL
中,属于同一表的文件通常存储在同一目录中。IBM Db2 Big SQL
的“文件检查工具”有助于识别HDFS
中有问题的小文件,并提供文件压缩建议。将这些文件合并为更大的文件,会最大程度地减少要处理的元数据并更有效地将文件大小与HDFS
块对齐,有助于提高Big SQL
读取性能。
ORC
和Parquet
提供了它们自己的不同工具来进行文件合并或压缩:
ORC
使用HIVE DDL
Parquet
使用工具执行合并命令
ORC文件合并
使用Hive DDL
(Hive Data Definition Language
),用户可以通过在表或分区上执行concatenate
命令来有效地合并小文件为更大的文件,命令如下:
ALTER TABLE table_name [PARTITION (partition_key = 'partition_value')] CONCATENATE;
Hive
会在stripe
级别合并ORC
文件来降低数据压缩/解压和编解码的开销。
Parquet文件合并
作为Apache Parquet
项目的一部分,有一组基于Java
的命令行工具,称为parquet-tools
。最新的parquet-tools版本包括一个merge命令,该命令可以将较小的parquet
文件逻辑地追加到较大的parquet
文件中。该命令以二进制形式将parquet
文件块串联在一起,而无需序列化/反序列化、合并页脚、修改路径和偏移量元数据。
要在HDFS
中运行parquet-tools merge
命令:
hadoop jar parquet-tools-1.9.0.jar merge <input> <output>
其中,input
是源parquet
文件或目录,而output
是合并原始内容的目标parquet
文件,此合并命令不会删除或覆盖原始文件。因此,它需要手动创建一个临时目录,并用压缩后的文件替换原始的小文件,以使Big SQL
或Apache Hive
知道该文件。
另外,不管文件的存储格式如何,要考虑的解决方案是重新创建表并通过执行INSERT…SELECT
进行压缩。
使用INSERT…SELECT合并文件
通过使用INSERT…SELECT
语法直接创建一个新表作为原始表的副本来压缩效率低下的拆分数据,此过程将根据插入的并行度将数据重新组织为相对少量的较大文件。
以下是一个如何创建新表,然后在Big SQL
中插入旧表中的数据的示例:
CREATE TABLE new_table LIKE old_table;
INSERT INTO new_table select * from old_table;
该解决方案还允许通过将数据分区复制到新表中,删除原始分区并插入新的压缩分区来合并单个分区中的文件。
最后,如果需要保留小文件以供记录,建议使用Hadoop
存档资源(Hadoop Archive Resources (har))对其进行存档,降低NameNode
管理大量资源和对象的成本。
性能改进
内部测试表明,压缩ORC
和Parquet
小文件有助于显著提高Big SQL
的读取性能。
针对ORC
和Parquet
格式进行测试的方案包括:
一百万行表以两种方式存储:
HDFS
中30个大小不一的非最佳小文件HDFS
中的2个压缩大文件,是根据文件格式使用parquet tools
或Hive DDL
合并的小文件的结果
运行一个查询,计算一个数字列的总和,以通过访问所有列内容来给整个表施加压力:
SELECT SUM(column_name) FROM table_name;
结果表明:
- 在
ORC
格式的非压缩表运行查询比在压缩表上运行查询多2倍的时间 - 在
parquet
格式的非压缩表运行查询比在压缩表上运行查询多1.6倍的时间
这是针对ORC
文件格式的压缩测试的输出,其中SLS_SALES_FACT_ORC
是非压缩表,而SLS_SALES_FACT_COMPACTED_ORC
是在非压缩表上运行CONCATENATE
命令的表结果:
[host][bigsql] 1> SELECT COUNT(*) FROM GOSALESDW.SLS_SALES_FACT_ORC;
+---------+
| 1 |
+---------+
| 1000000 |
+---------+
1 row in results(first row: 0.393s; total: 0.395s)
[host][bigsql] 1> SELECT SUM(GROSS_PROFIT) FROM GOSALESDW.SLS_SALES_FACT_ORC;
WARN [State: 01003][Code: 0]: Statement processing was successful.. SQLCODE=0, SQLSTATE=01003, DRIVER=3.72.24
+------------------+
| 1 |
+------------------+
| 4615167406.55999 |
+------------------+
1 row in results(total: 7.681s)
[bigsql@host root]$ hdfs dfs -ls /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc
Found 30 items
drwxrwxrwx - bigsql hadoop 0 2017-12-14 17:54 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc/._biginsights_stats
-rw-r--r-- 3 bigsql hadoop 443027 2017-12-14 17:53 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc/i_1512166475533_-307213540_201712140553882_1.1
-rw-r--r-- 3 bigsql hadoop 179411 2017-12-14 17:53 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc/i_1512166475533_-307213540_201712140553882_1.2
-rw-r--r-- 3 bigsql hadoop 897796 2017-12-14 17:49 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc/i_1512166475533_-412191103_201712140549330_1.1
-rw-r--r-- 3 bigsql hadoop 1176528 2017-12-14 17:49 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc/i_1512166475533_-412191103_201712140549330_1.2
-rw-r--r-- 3 bigsql hadoop 3356 2017-12-14 17:59 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc/i_1512166475533_-710448882_201712140559369_1.1
...
-rw-r--r-- 3 bigsql hadoop 52854 2017-12-14 18:09 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc/i_1512166475533_-451786036_201712140609603_2.2
-rw-r--r-- 3 bigsql hadoop 435203 2017-12-14 18:09 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc/i_1512166475533_215889957_201712140609092_1.1
-rw-r--r-- 3 bigsql hadoop 1218285 2017-12-14 18:09 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc/i_1512166475533_215889957_201712140609092_1.2
-rw-r--r-- 3 bigsql hadoop 2112684 2017-12-14 17:51 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_orc/i_1512166475533_866891040_201712140551232_2.2
[host][bigsql] 1> SELECT COUNT(*) FROM GOSALESDW.SLS_SALES_FACT_COMPACTED_ORC;
+---------+
| 1 |
+---------+
| 1000000 |
+---------+
1 row in results(first row: 0.379s; total: 0.381s)
[host][bigsql] 1> SELECT SUM(GROSS_PROFIT) FROM GOSALESDW.SLS_SALES_FACT_COMPACTED_ORC;
WARN [State: 01003][Code: 0]: Statement processing was successful.. SQLCODE=0, SQLSTATE=01003, DRIVER=3.72.24
+------------------+
| 1 |
+------------------+
| 4615167406.55999 |
+------------------+
1 row in results(total: 3.673 s)
[bigsql@host root]$ hdfs dfs -ls /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_compacted_orc
Found 3 items
drwxrwxrwx - bigsql hadoop 0 2017-12-14 18:14 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_compacted_orc/._biginsights_stats
-rwxrwxrwx 3 bigsql hadoop 19602272 2017-12-15 12:19 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_compacted_orc/000000_0
-rwxrwxrwx 3 bigsql hadoop 3720403 2017-12-15 12:19 /apps/hive/warehouse/gosalesdw.db/sls_sales_fact_compacted_orc/000001_0
注意:这些测试使用单个数据集来测量压缩表的性能,我们建议您在运行文件压缩之前测试自己的基准,并研究该操作带来的性能优势。
需要注意的
建议对上述存储格式的文件脱机运行修改操作,真正的问题是写入或删除文件的操作如何不影响当前正在运行并访问旧文件的查询任务,压缩文件本身并不复杂,但是不影响正在使用文件的任务可能会成为问题。
此外,表信息存储在Big SQL
以及Hive Metastore
中,该信息包含与表关联的实际文件的详细信息。使用Parquet
工具压缩文件时,至少需要更新Hive Metastore
以反映新文件。Big SQL
具有在Hive Metastore
中拉取更改并将其传播到其自己的catalog
中的逻辑。
参考资料
编译自:Optimizing ORC and Parquet files for Big SQL queries performance