Hadoop/HDFS/MapReduce/Impala
被设计用于存储和处理大量文件的场景,比如TB
或者PB
级别数据量的文件。大量小文件对查询性能有很大的影响,因为NameNode
要保存大量的HDFS
文件元数据,一次性查询很多分区或者文件的话,需要获取文件列表并一个个读取文件信息,不仅会对查询性能造成很大的影响,还可能会超过操作系统的文件描述符数量限制而导致查询失败。
因此,这就意味着我们要尽可能让文件保持很大吗?当然不是。大文件对表的性能也会有影响,原因是在大多数情况下,Hadoop
用户会压缩存储在HDFS
中的数据,这样虽然可以节省磁盘空间,但是如果你有一个大的压缩文件,花费在解压上的时间也会导致查询变慢。
为了证明上面的说法,我在CDH
环境中做了以下测试:
1、我准备了一个565M
的普通Text
格式的文件和一个使用bzip2
压缩方式压缩的135M
的文件,文件下载链接:Kaggle’s Flight Delay Dataset
2、我用4个这样的bzip2
文件创建了一个名为bzip2_smallfiles_4
的表,用8个这样的文件创建了另一个名为bzip2_smallfiles_8
的表
3、然后,我还将这个文本文件合并4次,生成一个文本文件,使用bzip2
对其进行压缩,大小变为大约510MB
,并在其上创建了一个名为bzip2_bigfile_4
的表
4、和3是一样的。但我将文件合并了8次,使其变大,压缩后文件大小为1.1GB
,并创建了一个名为bzip2_bigfile_8
的新表
5、然后,我对这4个表逐个运行“SELECT COUNT(*) FROM
”查询来比较结果
毫无疑问,我看到对表bzip2_bigfile_8
的查询是最慢的。以下是对这四张表的测试数据:
bzip2_smallfiles_4:
Operator Hosts Avg Time Max Time #Rows Est. #Rows Peak Mem Est. Peak Mem Detail
00:SCAN HDFS 4 26s464ms 52s687ms 23.28M -1 40.32 MB 160.00 MB test.bzip2_smallfiles_4
Query Timeline
...
Rows available: 53.86s (53861836202)
First row fetched: 53.87s (53869836178)
Unregister query: 53.87s (53874836163)
Fragment F00
Instance fc48dc3e014eb7a5:7d7a2dc100000004 (host=xxxx:22000)
AGGREGATION_NODE (id=1)
HDFS_SCAN_NODE (id=0)
File Formats: TEXT/BZIP2:2
- DecompressionTime: 49.45s (49449847498)
bzip2_smallfiles_8:
Operator Hosts Avg Time Max Time #Rows Est. #Rows Peak Mem Est. Peak Mem Detail
00:SCAN HDFS 4 52s514ms 54s196ms 46.55M -1 40.32 MB 160.00 MB test.bzip2_smallfiles_8
Query Timeline
...
Rows available: 54.36s (54359822792)
First row fetched: 54.68s (54683821736)
Unregister query: 54.69s (54688821720)
Fragment F00
Instance 5642f67b9a975652:c19438dc00000004 (host=xxxx:22000)
AGGREGATION_NODE (id=1)
HDFS_SCAN_NODE (id=0)
File Formats: TEXT/BZIP2:2
- DecompressionTime: 51.18s (51183849937)
bzip2_bigfile_4:
Operator Hosts Avg Time Max Time #Rows Est. #Rows Peak Mem Est. Peak Mem Detail
00:SCAN HDFS 4 27s394ms 1m49s 23.28M -1 40.15 MB 176.00 MB test.bzip2_bigfile_4
Query Timeline
...
Rows available: 1.8m (109781665214)
First row fetched: 1.8m (110408663300)
Unregister query: 1.8m (110413663284)
Fragment F00
Instance 4545c110dbca4c9c:6cd1db1100000004 (host=xxxx:22000)
AGGREGATION_NODE (id=1)
HDFS_SCAN_NODE (id=0)
File Formats: TEXT/BZIP2:2
- DecompressionTime: 1.7m (104339662922)
bzip2_bigfile_8:
Operator Hosts Avg Time Max Time #Rows Est. #Rows Peak Mem Est. Peak Mem Detail
00:SCAN HDFS 4 53s902ms 3m35s 46.55M -1 40.32 MB 176.00 MB test.bzip2_bigfile_8
Query Timeline
...
Rows available: 3.6m (215992297509)
First row fetched: 3.6m (216480295920)
Unregister query: 3.6m (216484295907)
Fragment F00
Instance 8f42a3b6ca6cf1cf:72fd65e100000004 (host=xxxx:22000)
AGGREGATION_NODE (id=1)
HDFS_SCAN_NODE (id=0)
File Formats: TEXT/BZIP2:2
- DecompressionTime: 3.4m (203596406406)
我选择bzip2
压缩格式的原因是因为bzip2
是可分割的,我所有的测试查询都是使用4台主机来运行的,即使是对于那两个大的bzip2
文件也是如此。
正如我们所看到的,为了让Impala
读取最大的1.1GB bzip2
文件,解压这个文件几乎需要4分钟。对于表bzip2_smallfiles_8
,虽然我们有更多的文件需要解压,但是因为我们可以在多个主机上并行执行解压操作,因此不会对性能造成太大影响。
综上所述,太多的小文件(比如KB
或者比较小的MB
文件)在Hadoop
中是不允许的,然而,文件太少而压缩大小太大也是不好的。理想情况下,我们应该使文件大小尽可能接近块大小(在CDH
中默认为256MB
),以便优化性能。
编译自:BIG COMPRESSED FILE WILL AFFECT QUERY PERFORMANCE FOR IMPALA