hadoop HDFS读写文件

本文详细介绍了HDFS的文件读写过程。在读文件时,客户端通过FileSystem的open()函数获取文件数据块信息,由NameNode提供元数据,接着通过DFSInputStream逐个数据节点读取;在写文件时,文件会被分成多个数据块,依次写入DataNode。过程中,客户端对故障节点有重试和绕过机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、HDFS读文件过程

    1.1 实例代码:

      

package com.liangjya.hadoop.demo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.junit.Before;

public class HDFSDemo {
	
	FileSystem fSystem =null;
	@Before
	public void init() throws IOException, URISyntaxException{
		 fSystem = FileSystem.get(new URI("hdfs://simulate:9000"), new Configuration());
	}
	
	
	public static void main(String args[]){
		
		try {
			FileSystem fSystem = FileSystem.get(new URI("hdfs://simulate:9000"), new Configuration());
			FSDataInputStream in=fSystem.open(new Path("/words"));
			FileOutputStream out = new FileOutputStream(new File("/usr/cloud/hadoop-words"));
			IOUtils.copyBytes(in, out, 2048, true);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
		
	}
}
1.2 读取过程图:

    

       1.初始化FileSystem,然后客户端(client)用FileSystem的open()函数打开文件
       2.FileSystem用RPC调用元数据节点NameNode,得到文件的数据块信息,对于每一个数据块,元数据节点返回保存数据块的  元数据信息(地址、块数等)。
       3.FileSystem返回FSDataInputStream给客户端,用来读取数据,客户端调用stream的read()函数开始读取数据。
       4.DFSInputStream连接保存此文件第一个数据块DataNode的最近的数据节点,data从数据节点读到客户端(client)
       5.当此数据块读取完毕时,DFSInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。
       6.当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。
       7.在读取数据的过程中,如果客户端在与数据节点通信出现错误,则尝试连接包含此数据块的下一个数据节点。
       8. 失败的数据节点将被记录,以后不再连接。


Hadoop中的网络拓扑

在Hadoop集群中如何衡量两个节点的远近呢?要知道,在高速处理数据时,数据处理速率的唯一限制因素就是数据在不同节点间的传输速度:这是由带宽的可怕匮乏引起的。所以我们把带宽作为衡量两个节点距离大小的标准。
但是计算两个节点之间的带宽是比较复杂的,而且它需要在一个静态的集群下才能衡量,但Hadoop集群一般是随着数据处理的规模动态变化的(且两两节点直接相连的连接数是节点数的平方)。于是Hadoop使用了一个简单的方法来衡量距离,它把集群内的网络表示成一个树结构,两个节点之间的距离就是他们离共同祖先节点的距离之和。树一般按数据中心(datacenter),机架(rack),计算节点(datanode)的结构组织。计算节点上的本地运算速度最快,跨数据中心的计算速度最慢(现在跨数据中心的Hadoop集群用的还很少,一般都是在一个数据中心内做运算的)。
假如有个计算节点n1处在数据中心c1的机架r1上,它可以表示为/c1/r1/n1,下面是不同情况下两个节点的距离:
• distance(/c1/r1/n1, /c1/r1/n1) = 0 (processes on the same node)
• distance(/c1/r1/n1, /c1/r1/n2) = 2 (different nodes on the same rack)
• distance(/c1/r1/n1, /c1/r2/n3) = 4 (nodes on different racks in the same data center)
• distance(/c1/r1/n1, /c2/r3/n4) = 6 (nodes in different data centers)

如下图所示:





二、HDFS写文件过程

        

package com.liangjya.hadoop.demo;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.junit.Before;
import org.junit.Test;

public class HDFSDemo {
	
	FileSystem fSystem =null;
	@Before
	public void init() throws IOException, URISyntaxException{
		 fSystem = FileSystem.get(new URI("hdfs://simulate:9000"), new Configuration());
	}
	
	@Test
	public void testUpload(){
		try {
			InputStream inputStream = new FileInputStream("/usr/cloud/hadoop-words");
			OutputStream outputStream = fSystem.create(new Path("/uploda-words"));
			IOUtils.copyBytes(inputStream, outputStream, 4096, true);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

}

HDFS写文件过程:



       1.初始化FileSystem,客户端调用create()来创建文件
       2.FileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件,元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。
       3.FileSystem返回DFSOutputStream,客户端用于写数据,客户端开始写入数据。
       4.DFSOutputStream将数据分成块,写入data queue。data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。
       5.DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。
       6.当客户端结束写入数据,则调用stream的close函数。此操作将所有的数据块写入pipeline中的数据节点,并等待ack queue返回成功。最后通知元数据节点写入完毕。
       7.如果数据节点在写入的过程中失败,关闭pipeline,将ack queue中的数据块放入data queue的开始,当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后能够察觉其数据块是过时的,会被删除。失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。元数据节点则被通知此数据块是复制块数不足,将来会再创建第三份备份。

replica是如何分布的

Hadoop在创建新文件时是如何选择block的位置的呢,综合来说,要考虑以下因素:带宽(包括写带宽和读带宽)和数据安全性。如果我们把三个备份全部放在一个datanode上,虽然可以避免了写带宽的消耗,但几乎没有提供数据冗余带来的安全性,因为如果这个datanode当机,那么这个文件的所有数据就全部丢失了。另一个极端情况是,如果把三个冗余备份全部放在不同的机架,甚至数据中心里面,虽然这样数据会安全,但写数据会消耗很多的带宽。Hadoop 0.17.0给我们提供了一个默认replica分配策略(Hadoop 1.X以后允许replica策略是可插拔的,也就是你可以自己制定自己需要的replica分配策略)。replica的默认分配策略是把第一个备份放在与客户端相同的datanode上(如果客户端在集群外运行,就随机选取一个datanode来存放第一个replica),第二个replica放在与第一个replica不同机架的一个随机datanode上,第三个replica放在与第二个replica相同机架的随机datanode上。如果replica数大于三,则随后的replica在集群中随机存放,Hadoop会尽量避免过多的replica存放在同一个机架上。选取replica的放置位置后,管道线的网络拓扑结构如下所示:





 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值