Hadoop分布式文件系统
HDFS的设计
HDFS以流式数据访问模式来存储超大文件。
流式数据访问
HDFS的构建思路是这样的:一次写入,多次读取是最高效的。数据集通常是由数据源生成或复制而来,接着长时间在此数据集上进行分析,每次分析都设计数据集的大部分或全部数据。
不适合使用HDFS的场景
1.低时间延迟的访问
HDFS是为高数据吞吐量应用优化的,这可能以高延迟作为代价,对于低延迟访问需求可以使用HBase
2.大量的小文件
由于namenode将文件系统的元数据存储在内存中,因此该文件系统所能存储的文件综述受限于内存大小
3.多用户写入,任意修改
HDFS中可能只有一个writer,而且每次写入数据都是追加在文件末尾,不支持多用户写入,也不支持在文件任意文职的修改。
HDFS的概念
数据块
默认64MB,HDFS上的文件被划分为块大小的多个分块,与普通文件系统不同的是,小于一个块大小的文件不会占据整个块空间。
namenode和datanode
HDFS集群有两类节点,并以管理者-工作者模式运行,即一个管理者(namenode)和多个工作者(datanode),namenode管理文件系统的命名空间,它维护这个文件系统树以及整个树内的文件以及目录,这些信息以两种文件形式永久保存在本地磁盘上,命名空间镜像文件和编辑日志文件。
Client代表用户通过namenode和datanode来访问文件系统,客户端通过接口提供访问文件系统的功能。
datanode是文件系统的工作节点,根据需要存储或检索数据块(受client或namenode调度)。
没有namenode文件系统将无法使用,因此需要对其实现容错,hadoop提供两种机制:
1.备份组成文件系统元数据持久状态的文件。
2.辅助namenode
命令行接口
可以使用命令执行常用的文件系统操作
hadoop fs -help可以查看帮助
Hadoop文件系统
hadoop有一个抽象的文件系统概念,HDFS只是其中一种实现。
Java的抽象类org.apache.hadoop.fs.FileSystem定义了Hadoop的一个文件系统接口,并且该类有几个具体实现。
见下图:
Hadoop对文件系统提供了很多接口,一般使用URI选择不同的文件系统进行交互,比如要想列出本地文件系统根目录下的文件,可使用如下命令:
hadoop fs -ls file:///
接口
Hadoop是用Java写的,通过Java API可以调用所有Hadoop文件系统的交互操作。
Java 接口
通过FileSystem API读取数据
hadoop中使用Path代表一个文件,FileSytem是一个通用的文件系统API,所以第一步是检索需要使用的文件系统实例,如HDFS。获取FileSystem实例有两个方法:
public static FileSystem get(Configuraion conf) throws IOException;
public static FileSystem get(URI uri,Configuraion conf) throws IOException;
Configuration对象封装了客户端或服务器的配置。
通过设置配置文件来加载类路径,第一个方法返回的是默认文件系统(在core-site.xml中设置的),如果没有设置则返回本地文件系统。
第二个方法返回通过URI和权限指定的文件系统。如果给定URI中没有猴子腚方案则返回默认文件系统。
有了FileSystem实例后,就可以调用open方法获取文件输入流:
public FSDataInputStream open(Path path)throws IOEXception;
public abstract FSDataInputStream open(Path path,int bufferSize)throws IOException;
第一个方法使用默认缓冲区大小4KB
数据流
文件读取数据流
客户端通过调用FileSystem对象的open方法来打开需要读取的文件,对于HDFS而言,这是一个分布式文件系统对象的一个实例。DistributedFileSystem
通过RPC与namenode通信,以确认文件起始块的位置。对于每一个块,namenode返回拥有该块副本的datanode的地址,datanode根据距离客户端的
位置远近进行排序。DistributedFileSystem类给客户端返回一个FSDataInputStream对象,客户端使用它读取数据。FSDataInputStream封装DFSInputStream
对象,管理datanode和namenode的I/O.接着客户端通过输入流的read方法,从距离客户端最近的datanode处获取数据,到达块的末尾后,DFSInputStream
会断开datanode的连接,并寻找下一个最佳datanode。一旦读取完成则调用close方法。
写入文件数据流
客户端通过调用DistributedFileSystem对象的create()方法创建一个文件,DistributedFileSystem通过RPC通知namenode在namespace中
创建一个新文件,此时该文件还没有相应的数据块。namenode会做一系列的检查确保这个文件还不存在,以及客户端有权限创建。如果通过,
namenode会创建一个新文件,否则抛出IOException.DistributedFileSystem返回一个FSDataOutputStream对象让客户端开始写入数据。与读文件类似,
FSDataOutputStream封装了DFSOuputStream对象,处理与datanode和namenode通信。
写入数据时,DFSOutputStream将数据分成若干packet,写入内部队列。DataStreamer处理内部队列,它负责请求namenode通过列举合适的datanode分配新块
以存储数据副本。列出的datanode构成一个管线,这里假设副本为3个,所以管线包括三个datanode。DataStreamer将packets送至管线中第一个datanode,
该datanode存储packet并将其送至第二个,以此类推。
DFSOutputStream也维护者一个确认队列,以等待datanode的确认回应,当收到所有datanode的确认后,packet才会被从队列中移除。
客户端完成数据写入后调用close()方法。