Hadoop小文件问题及解决方案

1.概述

小文件是指文件size小于HDFS上block大小的文件。这样的文件会给hadoop的扩展性和性能带来严重问题。首先,在HDFS中,任何block,文件或者目录在内存中均以对象的形式存储,每个对象约占150byte,如果有1千万个小文件,每个文件占用一个block,则NameNode大约需要2G空间。如果存储一亿个文件,则NameNode需要20G空间。这样NameNode内存容量严重制约了集群的扩展。其次,访问大量小文件速度远远小于访问几个大文件。HDFS最初是为流式访问大文件开发的,如果访问大量小文件,需要不断的从一个DataNode跳到另外一个DataNode,严重影响性能。最后,处理大量小文件速度远远小于处理同等大小的大文件的速度。每一个小文件要占用一个slot,而task启动将耗费大量时间甚至大部分时间都耗费在启动task和释放task上。


2.HDFS文件读写流程

在正式介绍HDFS小文件存储方案之前,我们先介绍一下当前HDFS上文件存取的基本流程。

2.1 读文件流程

A.client端发送读文件请求给NameNode,如果文件不存在,返回错误信息,否则,将该文件对应的block机器所在DataNode位置发送给client。

B.client收到文件位置信息后,与不同DataNode建立socket连接并行获取数据。

2.2 写文件流程

A.client端发送写文件请求,NameNode检查文件是否存在,如果已经存在,直接返回错误信息,否则,发送给client一些可用节点。

B.client将文件分块,并行存储到不同DataNode节点上,发送完成以后,client同时发送信息给NameNode和DataNode。

C.NameNode收到client的信息后,发送信息给DataNode。

D.DataNode同时收到NameNode和DataNode的确认信息后,提交写操作。


3 解决小文件的方案

3.1 编写应用程序实现

public class AppForSmallFile {

	//定义文件读取的路径
	private static final String OUTPATH = "hdfs://liaozhongmin:9000";
		
	public static void main(String[] args) {
		
		//定义FSDataOutputStream对象
		FSDataOutputStream fsDataoutputStream = null;
		//定义输入流读文件
		InputStreamReader inputStreamReader = null;
		try {
			//创建合并后文件存储的的路径
			Path path = new Path(OUTPATH + "/combinedFile");
			
			//创建FSDataOutputStream对象
			fsDataoutputStream =  FileSystem.get(path.toUri(), new Configuration()).create(path);
			
			//创建要合并的小文件路径
			File sourceDir = new File("C:\\Windows\\System32\\drivers\\etc");
			
			//遍历小文件
			for (File fileName : sourceDir.listFiles()){
				
				//创建输入流
				//fileInputStream = new FileInputStream(fileName.getAbsolutePath());
				//只有这样才可以制定字符编码(没办法,Window是默认GBK的,Hadoop是默认UTF-8的,所以读的时候就会乱码)
				inputStreamReader = new InputStreamReader(new FileInputStream(fileName), "gbk");
				//一行一行的读取
				List<String> readLines = IOUtils.readLines(inputStreamReader);
				
				//然后再写出去
				for (String line : readLines){
					//写入一行
					fsDataoutputStream.write(line.getBytes());
					//写入一个换行符
					fsDataoutputStream.write("\n".getBytes());
				}
				
			}
			
			System.out.println("合并成功");
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			try {
				inputStreamReader.close();
				fsDataoutputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
		
	}
}
注:这种方案是使用java文件相关操作,将众多的小文件写到一个文件中。


3

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值