Hadoop-HDFS基础原理与操作


1、概述

    HDFS是Hadoop分布式文件系统,用来分布式存储海量数据,并具有高可靠、高性能、可伸缩的能力。

    HDFS屏蔽了分布式存储的细节,提供了标准的访问方式,能够以类似访问本地文件系统的方式访问HDFS中的文件。

    如下是HDFS的架构图:

    

hadoop hdfs的应用 hadoop hdfs原理_开发工具

    1.namenode 管理元数据

    2.datanode 存储文件块

    3.Block 文件块,BlockSize 128MB

    4.Replication 文件块的副本

    5.Rack 机架

    6.Client 通过API后指令操作的一端(比如上传或下载文件,操作文件)



2、HDFS的相关操作

    可以通过shell或JavaAPI方式操作HDFS中的数据。



1.shell命令

    hdfs中的数据,一次写入、多次读取、不支持行级别的增删改。2.0版本增加了在文件中追加的内容的功能。所以也没有对应的行级别的命令。

hadoop fs -ls /user #查看目录。
hadoop fs -mkdir /user/trunk #创建目录。
hadoop fs -lsr /user #递归查看目录。
hadoop fs -put test.txt /user/trunk #上传文件。
hadoop fs -put test.txt #复制到hdfs当前目录下,首先要创建当前目录。
hadoop fs -get /user/trunk/test.txt #复制到本地当前目录下,即下载到本地当前目录
hadoop fs -cat /user/trunk/test.txt #查看文件内容。
hadoop fs -tail /user/trunk/test.txt #监控,查看最后1000字节。
hadoop fs -rm /user/trunk/test.txt #删除文件。
hadoop fs -rmdir /user/trunk #删除目录。
hadoop fs -help ls #查看ls命令的帮助文档。



2.Eclipse中Hadoop插件的使用



1>安装单机模式

    在Windows环境下,解压一个Hadoop的安装包,作为Windows下的Hadoop单机模式使用。

    如果要使用远程的Hadoop需要配置Windows下的Hadoop的环境变量,以及用户名的环境变量。配置此项可能需要重启电脑。

    内容如下:

HADOOP_HOME=路径
PATH=%HADOOP_HOME%/bin;%HADOOP_HOME%/sbin
HADOOP_USER_NAME=root



2>添加插件

    将插件文件hadoop-eclipse-plugin-2.7.1.jar放入eclipse/plugins目录下,重启eclipse。



3>配置Eclipse

    在Window的preferences中找到Hadoop Map/Reduce,将单机模式的Hadoop路径填入,如下如所示:

hadoop hdfs的应用 hadoop hdfs原理_大数据_02

在Eclipse中找到如下界面,将Map/Reduce模式显示出来。

hadoop hdfs的应用 hadoop hdfs原理_数据_03

    在Hadoop的配置界面,填入如下数据:

    Location name:填写安装Hadoop服务器的主机名。

    Map/Reduce(V2)Master Host:填写安装Hadoop服务器的主机名。

    DFS Master Port:改为安装Hadoop服务器核心配置文件中配置的端口号,一般默认为9000。

    User name:安装Hadoop服务器的超级管理员,一般为root。

hadoop hdfs的应用 hadoop hdfs原理_hadoop hdfs的应用_04

    配置完成点击Finish。然后就可以使用了。



4>问题

    当遇到权限拒绝问题时,可以修改hdfs-site.xml中的配置dfs.permissions为false关闭hadoop的权限认证。

    也可以在windows的环境变量中配置HADOOP_USER_NAME指定连接hadoop时使用的名称,这种方式配置完要重启eclipse。



3.HDFS的Java API



1>导入jar

    hadoop/share/hadoop/common/*.jar

    hadoop/share/hadoop/common/lib/*.jar

    hadoop/share/hadoop/hdfs/*.jar



2>FileSystem

    文件系统类,HDFS API的主要类,所有相关操作基本都在这个类里。

重要方法

1)get(URI uri,Configuration conf);

    获取一个FileSystem对象。

2)open(Path path);

    打开连接。返回一个InputStream对象。

3)create(Path path);

    创建一个文件。返回一个OutputStream对象。

4)delete(Path path,boolean recursive);

    是否递归删除一个文件或路径。返回boolean值,删除成功返回true,删除失败返回false。

5)mkdirs(Path path);

    创建文件夹,可以创建多级目录。返回boolean值,创建成功返回true,创建失败返回false。



3>IOUtils

    HDFS相关操作的一个工具类。

重要方法

1)copyBytes(InputStream in,OutputStream out,int buffersize);

    对接数据,将输入输出流整合,直接将文件传输到目的地。



4>代码演示

@Test
	public void mkdir() throws Exception {
		FileSystem fs = FileSystem.get(new URI("hdfs://yun01:9000"), new Configuration());
		fs.mkdirs(new Path("/test2/xx/yy/zzz"));
		fs.close();
	}

	@Test
	public void delete() throws Exception {
		// 1.创建文件系统对象
		FileSystem fs = FileSystem.get(new URI("hdfs://yun01:9000"), new Configuration());
		// 2.删除文件
		// fs.delete(new Path("/test/3.txt"));
		fs.delete(new Path("/test/1.txt"), true);
		// 3.关闭连接
		fs.close();
	}

	@Test
	public void upload() throws Exception {
		// 1.创建文件系统对象
		FileSystem fs = FileSystem.get(new URI("hdfs://yun01:9000"), new Configuration());
		// 2.创建文件
		FSDataOutputStream out = fs.create(new Path("/test/3.txt"));
		// 3.创建输入流
		InputStream in = new FileInputStream("2.txt");
		// 4.对接流
		IOUtils.copyBytes(in, out, 1024);
		// 5.关闭流关闭文件系统
		in.close();
		out.close();
		fs.close();
	}

	@Test
	public void download() throws Exception {
		// 1.创建文件系统对象
		FileSystem fs = FileSystem.get(new URI("hdfs://yun01:9000"), new Configuration());
		// 2.获取连接文件的流
		FSDataInputStream in = fs.open(new Path("/test/jt-对象存储地址.txt"));
		// 3.创建输出流
		OutputStream out = new FileOutputStream("2.txt");
		// 对接流,传输数据
		IOUtils.copyBytes(in, out, 1024);
		// 5.关闭流,关闭连接
		out.close();
		in.close();
		fs.close();
	}



3、HDFS技术细节



1.HDFS的主要原理

    将数据进行切块后进行复制并存储在集群的多个节点中,从而实现了海量数据分布式存储,并通过block副本实现可靠性保证。

    其中切出的块称为Block。

    负责存放Block的节点称之为DataNode节点。

    负责存放元数据的节点称之为NameNode节点。

    另外还有一个独立进程称作SecondaryNameNode负责帮助NameNode进行元数据的合并操作。



2.Block

    Block是HDFS中存储的基本单位。

    当文件被存储到HDFS的过程中,会先将文件按照指定大小来切块即block,复制出指定数量的副本(默认是3个),分布式存储在集群中。2.0版本中Block默认的大小为128M,1.0版本中为64M。



1> 文件切块目的

    1.一个大文件切分为小的若干个Block方便分布式的存储在不同磁盘中。

    2.屏蔽了数据的区别,只需要面向Block操作,从而简化存储系统。

    3.有利于数据的复制。每次复制的是一个体积较小的Block,而不是一个大型文件,效率更高。

    如果切分过后,剩余数据不够128MB,则会将剩余数据单独作为一个Block存储,数据多大,Block就多大,128MB只是最大大小,不是固定大小。

    例如:

    一个256MB文件,共有256/128=2个Block。

    一个258MB文件,共有258/128=2余下2MB,则余下的2MB会独占一个Block大小为2MB,则且分出两个128MB的Block和一个2MB的Block。

    一个1MB文件,则单独占用一个Block,这个Block为1MB大小。



2>Block副本放置策略

    第一个副本:如果是集群内提交,就放置在上传文件的DataNode,如果是集群外就提交,随机选择一台磁盘不太满,cpu不太忙的节点,进行上传。

    第二个副本:放置在第一个副本不同机架的节点上。(利用机架感知策略)

    第三个副本:放置在与第二个副本相同机架的节点上。

    更多副本:随机节点。

    机架感知策略:

    其实就是在Hadoop的配置文件中添加一个记录ip和主机名映射机架的关系表,通过这张关系表来判断那个主机是不同机架。

 



3.DataNode

    DataNode在整个HDFS中主要是存储数据的功能。数据以Block的形式存放在DataNode中。

    DataNode节点会不断向NameNode节点发送心跳报告保持与其联系,心跳报告的频率是3秒一次,在心跳报告中向NameNode报告信息,从心跳响应中接受NameNode的指令,执行对块的复制、移动、删除等操作。

    NameNode如果10分钟都没收到DataNode的心跳,则认为该DataNode已经lost,并向其他DataNode发送备份block的指令,完成lost节点中的数据副本的复制,以保证数据副本数量在整个HDFS中是一致的。

    所有的DataNode都是主动联系NameNode,NameNode不会主动联系DataNode。



4.NameNode

    NameNode维护着HDFS中的元数据信息。同时还兼顾各种外部请求以及DataNode中数据存储的管理。

    元数据信息包括:文件信息、目录结构信息、副本数量信息、文件和Block之间关系的信息、Block和DataNode之间的关系信息。数据格式参照如下:

    FileName replicas block-Ids id2host

    例如:/test/a.log,3,{b1,b2},[{b1:[h0,h1,h3]},{b2:[h0,h2,h4]}]



1>元数据的存储

    NameNode中的元数据信息存储在内存和文件中,内存中为实时信息完整信息,文件中为数据镜像作为持久化存储使用,其中block和DataNode之间的关系信息不会在文件中存储。

内存中的元数据

    文件信息、目录结构信息、副本数量信息、文件和Block之间关系的信息、Block和DataNode之间的关系信息。

文件中的元数据

    文件信息、目录结构信息、副本数量信息、文件和Block之间关系的信息。

    可以发现文件中的元数据比起内存中缺失了block和DataNode之间的对应关系,这是因为,HDFS集群经常发生变动,DataNode增加或减少都是很正常情况,因此这些信息都是临时在内存中组织的,而不会存储在磁盘镜像文件中。



2> NameNode的文件

fsimage

    元数据镜像文件。存储某NameNode元数据信息,并不是实时同步内存中的数据。

edits

    记录NameNode对数据操作的日志文件。

fstime

    保存最近一次checkpoint的时间。即最后一次元数据合并的时间。



3>工作原理

    当有写请求时,NameNode会首先将请求操作写edit log到磁盘edits文件中,成功后才会修改内存,并向客户端返回操作结果。

    所以,fsimage中的数据并不是实时的数据,而是在达到条件时要和edits文件合并,合并过程由SecondaryNameNode完成。

    之所以不直接改fsimage而是要在edits中记录,是因为记录日志是一种连续的磁盘IO操作,可以节省时间。如果直接修改fsimage文件,会进行大量的不连续的磁盘IO操作,这样会大大降低效率。



5.SecondaryNameNode

    这个是为分布式才有的角色,在完全分布式中,由JournalNode代替。

    SecondaryNameNode并不是NameNode的热备份,而是协助者,帮助NameNode进行元数据的合并。

    从另外的角度来看可以提供一定的备份功能,但并不是热备,如果直接使用可能会丢失上一次合并后发生的数据!可以从SecondaryNameNode中恢复部分数据,但是无法恢复全部。



1>合并数据的条件

    何时出发数据合并?

    根据配置文件设置的时间间隔:fs.checkpoint.period默认3600秒。

    根据配置文件设置的edits log大小:fs.checkpoint.size默认64MB。



2>合并过程

hadoop hdfs的应用 hadoop hdfs原理_hadoop hdfs的应用_05

拷贝文件

    当达到合并数据的条件后,SecondrayNameNode会将NameNode中的fsimage和edits文件拷贝过来,同时NameNode中会创建一个新的edits.new文件,用于记录新的读写请求。

合并数据

    在SecondrayNameNode中将拷贝过来的fsimage和edits合并为一个新的fsimage.ckpt文件。

传回数据

    SecondrayNameNode将合并完成的fsimage.ckpt文件拷贝回NameNode中,然后删除之前的fsimage文件,将fsimage.ckpt文件更名为fsimage,NameNode将原来edtis文件删除,再将edtis.new改为edits,完成合并工作。

记录合并操作

    最后在fstime文件中添加这次合并的记录。

    由于NameNode实时数据都在内存中,此处的合并指的是磁盘中的持久化的数据的处理。



3>应用

    判断:snn可以对元数据做一定程度的备份,但是不是热备,对不对?

    思考:什么情况下可能造成NameNode元数据信息丢失?

    snn并不是nn的热备,但是能保存大部分备份数据。原因就在于edits.new中的数据丢失了就找不回来了

通常NameNode和SecondrayNameNode要放置到不同机器中以此提升性能,并提供一定的元数据安全性。

 



4、HDFS执行流程

    针对HDFS的不同操作,有不同的执行流程,具体介绍如下。



1.HDFS读流程

hadoop hdfs的应用 hadoop hdfs原理_运维_06



1>发送请求

    使用HDFS提供的客户端开发库Client,向远程的Namenode发起RPC请求;NameNode会检验当前文件是否存在以及当前客户端是否有权限读取该文件,两种检查只中有一种不符合条件,就会抛出异常,不再进行下一步操作。



2>响应资源元数据

    如果以上校验没有问题,Namenode会视情况返回文件的部分或者全部block列表,对于每个block,Namenode都会返回有该block副本的DataNode地址。



3>下载资源

    客户端开发库Client会选取离客户端最接近(并不是物理上的最近,而是延迟最低负载最低)的DataNode来读取block;如果客户端本身就是DataNode,那么将从本地直接获取数据。



4>资源校验

    读取完当前block的数据后,会进行checksum验证,如果读取datanode时出现错误,客户端会通知Namenode,然后再从下一个拥有该block拷贝的datanode继续读。

    当读取正确的block数据之后,关闭与当前的DataNode连接,并为读取下一个block寻找最佳的DataNode;当读完列表的block后,且文件读取还没有结束,客户端开发库会继续向Namenode获取下一批的block列表。



5>下载结束告知

    当文件最后一个块也都读取完成后,datanode会连接namenode告知关闭文件。

NameNode不参与读取真实数据传输的过程。



2.HDFS的写流程

hadoop hdfs的应用 hadoop hdfs原理_开发工具_07



1>发送请求

    使用HDFS提供的客户端开发库Client,向远程的Namenode发起RPC请求;Namenode会检查要创建的文件是否已经存在,创建者是否有权限进行操作,如果这两个条件有一个不符合就会让客户端抛出异常,终止操作。条件验证通过则会为文件创建一个记录。



2>数据切块

    当客户端开始写入文件的时候,开发库客户端会将文件切分成多个packets,并在内部以数据队列"data queue"的形式管理这些packets,然后向Namenode申请新的blocks,获取用来存储replicas的合适的datanodes列表,列表的大小根据在Namenode中对replication的设置而定。



3>上传数据

    根据DataNode列表连接DataNode节点,开始以pipeline(管道)的形式将packet写入所有的replicas中。客户端把packet以流的方式写入第一个datanode,该datanode把该packet存储之后,再将其传递给在此pipeline中的下一个datanode,直到最后一个datanode完成存储,这种写数据的方式呈流水线的形式。



4>响应上传结果

    最后一个datanode成功存储之后会返回一个ack packet,在pipeline里传递至客户端,在客户端的开发库内部维护着"ack queue",成功收到datanode返回的ack packet后会从"ack queue"移除相应的packet。

    如果传输过程中,有某个datanode出现了故障,那么当前的pipeline会被关闭,出现故障的datanode会从当前的pipeline中移除,剩余的block会继续剩下的datanode中继续以pipeline的形式传输,同时Namenode会分配一个新的datanode,保持replicas设定的数量。



5>上传结果告知

    当所有的packges都成功的上传后,客户端通知NameNoe文件上传完成,NameNode将该文件置为可用状态,并关闭该文件。

 NameNode不参与真实数据存储传输的过程。

 



3.HDFS的删除流程



1>发送请求

    客户端发起请求连接NameNode表示要删除文件,NameNode检查文件是否存在及是否有权限删除文件,如果条件验证不通过,那么抛出异常,终止操作。如果通过则进行下一步操作。



2>执行伪删除操作并响应

    NameNode执行元数据的删除,只是将该元数据置为已删除状态,然后向客户端表示文件删除成功。



3>发布删除指令

    当保存着这些数据块的DataNode节点向NameNode节点发送心跳时,在心跳响应中,NameNode节点会向DataNode发出指令,要求删除这些block。DataNode收到指令后删除对应的Block。所以在执行完delete方法后的一段时间内,数据块才能被真正的删除掉。



4>彻底删除

    当该文件对应的所有block及其副本都被删除后,NameNode中将之前标记为已删除的元数据删除。

 



4.HDFS的启动流程



1>导入元数据

    在HDFS启动时,NameNode先合并fsImage和edits文件,生成新的fsimage和空的edits文件,这个过程是NameNode自己进行的。然后再将fsimage中的数据恢复到内存中,但此时内存中的元数据并不够,还差block和datanode的映射关系,这个信息在fsimage中是不存在的,需要临时在内存中组织出来。



2>整合元数据

    此时NameNode等待DataNode的连接,DataNode在启动时会向NameNode发送心跳报告,其中携带自己具有的Block的编号信息,NameNode基于这些信息,在内存中组织元数据信息。



3>开启服务

    直到NameNode达到最小启动条件后,进行必要的block副本复制和删除,之后开始对外提供服务。整个这个过程中,HDFS无法正常工作,称之为处在安全模式中。

NameNode最小启动条件:每个Block都至少有了一个副本被找到。



5.安全模式

    在启动HDFS时,会立即进入安全模式,此时不能操作hdfs中的文件,只能查看目录文件名等,读写操作都不能进行。

    在HDFS正常运行过程中,如果因为意外情况,造成有block找不到任何副本,则HDFS进入安全模式。

org.apache.hadoop.dfs.SafeModeException: Cannot delete /user/hadoop/input. Name node is in safe mode

    安全模式其实是HDFS对元数据的一种保护机制,防止意外的操作损坏元数据。

    当遇到安全模式,最简单的办法就是等一会。

    如果很长时间都无法退出安全模式,则应检查进入安全模式的原因,找到问题的原因解决,则hadoop会自动退出安全模式。

    如果非要强制退出安全模式,可以使用如下命令,但是要慎用,一不小心损坏了元数据,hdsf中的数据就都无法使用了:

hadoop dfsadmin -safemode leave

  慎用!



5、HDFS的优缺点



1.HDFS优点



1> 支持超大文件

    支持超大文件。超大文件在这里指的是几百M,几百GB,甚至几TB大小的文件。一般来说hadoop的文件系统会存储TB级别或者PB级别的数据。所以在企业的应用中,数据节点有可能有上千个。



2>检测和快速应对硬件故障

    在集群的环境中,硬件故障是常见的问题。因为有上千台服务器连接在一起,这样会导致高故障率。因此故障检测和自动恢复是HDFS文件系统的一个设计目标。



3>流式数据访问

    HDFS的数据处理规模比较大,应用一次需要访问大量的数据,同时这些应用一般都是批量处理,而不是用户交互式处理。应用程序能以流的形式访问数据集。主要的是数据的吞吐量,而不是访问速度。



4>简化的一致性模型

    大部分HDFS操作文件时,需要一次写入,多次读取。在HDFS中,一个文件一旦经过创建、写入、关闭后,一般就不需要修改了。这样简单的一致性模型,有利于提高吞吐量。



5>高容错性

    数据自动保存多个副本,副本丢失后自动恢复。



6>可构建在廉价机器上

    构建在廉价机器上,可以轻松的通过扩展机器数量,来近乎线性的提高集群存储能力。

 



2.HDFS缺点



1>不能做到低延迟数据访问

    低延迟数据如:和用户进行交互的应用,需要数据在毫秒或秒的范围内得到响应。由于hadoop针对高数据吞吐量做了优化,牺牲了获取数据的延迟,所以对于低延迟来说,不适合用hadoop来做。



2>大量的小文件会影响性能

    HDFS支持超大的文件,是通过数据分布在数据节点,数据的元数据保存在名字节点上。名字节点的内存大小,决定了HDFS文件系统可保存的文件数量。虽然现在的系统内存都比较大,但大量的小文件还是会影响名字节点的性能。



3>不支持多用户写入文件、修改文件

    HDFS的文件只能有一次写入,不支持修改和追加写入(2.0版本支持追加),也不支持修改。只有这样数据的吞吐量才能大。



4>不支持超强的事务

    没有像关系型数据库那样,对事务有强有力的支持。