大数据 Hadoop 之——HDFS 小文件问题与处理实战操作
一、背景
每个文件均按块存储,每个块的元数据存储在 NameNode 的内存中,因此 HDFS 存储小文件会非常低效。因为大量的小文件会耗尽 NameNode 中的大部分内存。但注意,存储小文件所需要的磁盘容量和数据块的大小无关。每个块的大小可以通过配置参数(
dfs.blocksize
)来规定,默认的大小128M
。例如,一个 1MB 的文件设置为 128MB 的块存储,实际使用的是 1MB 的磁盘空间,而不是 128MB。
Hadoop 高可用环境部署,可参考我之前的文章:大数据Hadoop之——Hadoop 3.3.4 HA(高可用)原理与实现(QJM)
1)小文件是如何产生的?
动态分区插入数据,产生大量的小文件,从而导致 map 数量剧增;
reduce 数量越多,小文件也越多,reduce 的个数和输出文件个数一致;
数据源本身就是大量的小文件;
2)文件块大小设置
同样对于如何设置每个文件块的大小,官方给出了这样的建议:
所以对于块大小的设置既不能太大,也不能太小,太大会使得传输时间加长,程序在处理这块数据时会变得非常慢,如果文件块的大小太小的话会增加每一个块的寻址时间。所以文件块的大小设置取决于磁盘的传输速率。
3)HDFS 分块目的
HDFS 中分块可以减少后续中 MapReduce 程序执行时等待文件的读取时间,HDFS 支持大文件存储,如果文件过大 10G 不分块在读取时处理数据时就会大量的将时间耗费在读取文件中,分块可以配合 MapReduce 程序的切片操作,减少程序的等待时间。
二、HDFS 小文件问题处理方案
HDFS 中文件上传会经常有小文件的问题,每个块大小会有 150 字节的大小的元数据存储 namenode 中,如果过多的小文件每个小文件都没有到达设定的块大小,都会有对应的 150 字节的元数据,这对 namenode 资源浪费很严重,同时对数据处理也会增加读取时间。对于小文件问题,Hadoop 本身也提供了几个解决方案,分别为:Hadoop Archive
,Sequence file
和CombineFileInputFormat
,除了 hadoop 本身提供的方案,当然还有其它的方案,下面会详细讲解。
1)Hadoop Archive(HAR)
Hadoop Archive(HAR)
是一个高效地将小文件放入 HDFS 块中的文件存档工具,它能够将多个小文件打包成一个 HAR 文件,这样在减少 namenode 内存使用的同时,仍然允许对文件进行透明的访问。
【示例】对某个目录/foo/bar
下的所有小文件存档成/outputdir/zoo.har
:
当然,也可以指定 HAR 的大小(使用
-Dhar.block.size
)。
HAR 是在 Hadoop file system 之上的一个文件系统,因此所有 fs shell 命令对 HAR 文件均可用,只不过是文件路径格式不一样,HAR 的访问路径可以是以下两种格式:
可以这样查看 HAR 文件存档中的文件:
使用 HAR 时需要注意两点:
对小文件进行存档后,原文件并不会自动被删除,需要用户自己删除;
创建 HAR 文件的过程实际上是在运行一个 mapreduce 作业,因而需要有一个 hadoop 集群运行此命令。
此外,HAR 还有一些缺陷:
一旦创建,Archives 便不可改变。要增加或移除里面的文件,必须重新创建归档文件。
要归档的文件名中不能有空格,否则会抛出异常,可以将空格用其他符号替换(使用
-Dhar.space.replacement.enable=true
和-Dhar.space.replacement
参数)。不支持修改
2)Sequence file
Sequence file
由一系列的二进制 key/value 组成,如果为 key 小文件名,value 为文件内容,则可以将大批小文件合并成一个大文件。Hadoop-0.21.0 中提供了 SequenceFile,包括 Writer,Reader 和 SequenceFileSorter 类进行写,读和排序操作。如果 hadoop 版本低于 0.21.0 的版本。
和 HAR 不同的是,这种方式还支持压缩。该方案对于小文件的存取都比较自由,不限制用户和文件的多少,但是 SequenceFile 文件不能追加写入,适用于一次性写入大量小文件的操作。也是不支持修改的。
3)CombineFileInputFormat
CombineFileInputFormat 是一种新的 inputformat,用于将多个文件合并成一个单独的 split,在 map 和 reduce 处理之前组合小文件。
4)开启 JVM 重用
有小文件场景时开启 JVM 重用;如果没有产生小文件,不要开启 JVM 重用,因为会一直占用使用到的 task 卡槽,直到任务完成才释放。JVM 重用可以使得 JVM 实例在同一个 job 中重新使用 N 次,N 的值可以在 Hadoop 的
mapred-site.xml
文件中进行配置。通常在 10-20 之间。
5)合并本地的小文件,上传到 HDFS(appendToFile )
将本地的多个小文件,上传到 HDFS,可以通过 HDFS 客户端的
appendToFile
命令对小文件进行合并。
6)合并 HDFS 的小文件,下载到本地(getmerge)
可以通过 HDFS 客户端的
getmerge
命令,将很多小文件合并成一个大文件,然后下载到本地。
三、HDFS 小文件问题处理实战操作
1)通过 Hadoop Archive(HAR)方式进行合并小文件
在本地准备 2 个小文件:
将文件 put 上 hdfs
进行合并
查看 yarn 任务:http://local-168-182-110:8088/
查看 har 文件
解压 har 文件
【温馨提示】眼尖的小伙伴,可以已经发现了一个问题,就是
cp
串行解压,会在解压的目录下保留 har 文件。
Archive 注意事项:
Hadoop archives 是特殊的档案格式, 扩展名是*.har;
创建 archives 本质是运行一个 Map/Reduce 任务,所以应该在 Hadoop 集群运行创建档案的命令;
创建 archive 文件要消耗和原文件一样多的硬盘空间;
archive 文件不支持压缩;
archive 文件一旦创建就无法改变,要修改的话,需要创建新的 archive 文件;
当创建 archive 时,源文件不会被更改或删除;
2)合并本地的小文件,上传到 HDFS(appendToFile )
在本地准备 2 个小文件:
合并方式:
web HDFS:http://local-168-182-110:9870/explorer.html#/
3)合并 HDFS 的小文件,下载到本地(getmerge)
4)针对 Hive 表小文件数合并处理(CombineFileInputFormat)
1、输入阶段合并
需要更改 Hive 的输入文件格式即参
hive.input.format
,默认值是org.apache.hadoop.hive.ql.io.HiveInputFormat
我们改成org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
。这样比起上面对 mapper 数的调整,会多出两个参数是
mapred.min.split.size.per.node
和mapred.min.split.size.per.rack
,含义是单节点和单机架上的最小 split 大小。如果发现有 split 大小小于这两个值(默认都是 100MB),则会进行合并。具体逻辑可以参看 Hive 源码中的对应类。
2、输出阶段合并
直接将
hive.merge.mapfiles
和hive.merge.mapredfiles
都设为true
即可,前者表示将 map-only 任务的输出合并,后者表示将 map-reduce 任务的输出合并,Hive 会额外启动一个 mr 作业将输出的小文件合并成大文件。另外,
hive.merge.size.per.task
可以指定每个 task 输出后合并文件大小的期望值,hive.merge.size.smallfiles.avgsize
可以指定所有输出文件大小的均值阈值,默认值都是 1GB。如果平均大小不足的话,就会另外启动一个任务来进行合并。
本文源自:“ 大数据与云原生技术分享”公众号
卡奥斯开源社区是为开发者提供便捷高效的开发服务和可持续分享、交流的 IT 前沿阵地,包含技术文章、群组、互动问答、在线学习、大赛活动、开发者平台、OpenAPI 平台、低代码平台、开源项目等服务,社区使命是让每一个知识工人成就不凡。
评论