Hadoop分布式文件系统(hadoopdistributed filesystem,HDFS)。HDFS是一个高度容错性的系统,适合部署在廉价的机器上。HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。HDFS可以实现流的形式访问(streaming access)文件系统中的数据。
它是基于流数据模式的访问和处理超大文件。(分布式最大的好处就是其通透性,虽然分布存在不同的datanode上面,但是感觉在一台电脑的本地进行操作)。
特点:
错误检测和快速、自动的恢复是 HDFS的核心架构目标
HDFS 以支持大数据集合为目标,一个存储在上面的典型文件大小一般都在千兆至 T字节,一个单一 HDFS实例应该能支撑数以千万计的文件。
主从架构。
文件采用write-one-read-many访问模型(
一次写,多次读
,不可更新已有内容,但如果需要追加,需要将hdfs-site.xml中的dfs.support.append属性设置为true)跑在 HDFS上的应用与一般的应用不同,它们主要是以流式读为主,做批量处理;比之关注数据访问的低延迟问题,更关键的在于数据访问的高吞吐量。
HDFS的限制:
适用于一次写入、多次查询的情况,不支持并发写情况,小文件不合适。因为小文件也占用一个块,小文件越多(如100000个1k文件)块越 多,NameNode压力越大。
如果要处理一些用户要求时间比较短的低延迟应用请求,则HDFS不适合。HDFS是为了处理大型数据集分析任务的,主要是为达到高的数据吞吐量而设计的,这就可能要求以高延迟作为代价。
HDFS架构
一个HDFS集群是有一个 Namenode和一定数目的 Datanode组成。 Namenode是一个中心服务器,负责管理文件系统的 namespace和客户端对文件的访问。 Datanode在集群中一般是一个节点一个,负责管理节点上它们附带的存储。在内部,一个文件其实分成一个或多个 block,这些 block存储在 Datanode集合里。 Namenode执行文件系统的 namespace操作,例如打开、关闭、重命名文件和目录,同时决定 block到具体 Datanode节点的映射。 Datanode在 Namenode的指挥下进行 block的创建、删除和复制。
namenode用来管理文件系统的命名空间,其将所有的文件和文件夹的元数据保存在一个文件系统树中。这些信息也会在硬盘上保存成以下文件:命名空间镜像 (namespace image)及修改日志 (edit log)
。其还保存了一个文件包括哪些数据块,分布在哪些数据节点上。
1、NameNode 是master节点,NameNode的作用是 管理文件目录结构,接受用户的操作请求,是管理数据节点的。名字节点维护两套数据, 一套 是文件 目录与数据块之间的关系 , 另一套 是 数据块与节点之间的关系 。 前一套 数据是 静态的 ,是存放在磁盘上的, 通过fsimage和edits文件来维护 ; 后一套 数据是 动态的 ,不持久放到到磁盘的,每当集群启动的时候,会自动建立这些信息,所以一般都放在内存中。
fsimage (文件系统镜像):元数据镜像文件。存储某一时段NameNode内存 元数据信息。
edits: 操作日志文件。
fstime: 保存最近一次checkpoint的时间
2、SecondaryNameNode
HA的一个解决方案。但不支持热备。由于数据操作越多edits文件膨胀越大,但不能让他无限的膨胀下去,所以要把日志过程转换出来 放到fsimage中。由于NameNode要接受用户的操作请求,必须能够快速响应用户请求,为了保证NameNode的快速响应给用户,所以将此项工 作交给了 SecondaryNode ,它从NameNode上 下载元数据信息(fsimage,edits),然后把二者合并,生成新的fsimage,在本地保存,并将其推送到NameNode,同时重置NameNode的edits
3、DataNode 是HDFS中真正存储数据的。按Block存储(每个block大小64M)。
客户端(client)或者元数据信息(namenode)可以向数据节点请求写入或者读出数据块。
其周期性的向元数据节点回报其存储的数据块信息。
数据流
1、读数据
客户端(client)用 FileSystem的 open()函数打开文件,DistributedFileSystem用RPC调namenode,得到文件的数据块信息。
对于每一个数据块,namenode返回保存数据块的数据节点的地址。DistributedFileSystem返回FSDataInputStream 给客户端,用来读取数据。客户端调用 stream的 read()函数开始读取数据。DFSInputStream连接保存此文件第一个数据块的最近的数据节点。Data从数据节点读到客户端 (client),当此数据块读取完毕时, DFSInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。
当客户端读取完毕数据的时候,调用 FSDataInputStream的 close函数。在读取数据的过程中,如果客户端在与数据节点通信出现错误,则尝试连接包含此数据块的下一个数据节点。失败的数据节点将被记录,以后不再连接。
2、写数据
客户端调用 create()来创建文件,DistributedFileSystem 用RPC 调用namenode,在文件系统的命名空间中创建一个新的文件。
namenode首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。DistributedFileSystem 返回DFSOutputStream ,客户端用于写数据。客户端开始写入数据, DFSOutputStream将数据分成块,写入 data queue。Data queue 由Data Streamer读取,并通知namenode分配数据节点,用来存储数据块 (每块默认复制 3份,也就是说1T数据需要3T存储空间 )。
分配的数据节点放在一个 pipeline里。 Data Streamer 将数据块写入pipeline 中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。DFSOutputStream 为发出去的数据块保存了 ack queue,等待 pipeline中的数据节点告知数据已经写入成功。当客户端结束写入数据,则调用 stream的 close函数。此操作将所有的数据块写入 pipeline中的数据节点,并等待 ack queue返回成功。最后通知namenode写入完毕。 如下图:
3、文件复制
副本的存放是 HDFS可靠性和性能的关键。 HDFS采用一种称为 rack-aware的策略来改进数据的可靠性、有效性和网络带宽的利用。
数据传输
1、数据在HDFS上存储的基本单位是Block,
默认大小64M
;2、数据在Client和DataNode之间传输数据的基本单位是Packet,默认最大为65557B;
3、数据传输Pipeline,宏观上看是Block Pipeline,但是微观上其实是Packet Pipeline。
HDFS命令行:
支持的操作:
创建 复制 移动 和删除文件.
实现管理职责 - chmod, chown, chgrp.
设置复制文件的比率
使用Head, tail, cat查看文件
支持的全部命令说明见:http://hadoop.apache.org/docs...
DFSShell
HDFS允许用户数据组织成文件和文件夹的方式,它提供一个叫DFSShell的接口,使用户可以和HDFS中的数据交互。
hadoop fs|dfs -<cmd> [args]
例如:列出HDFS指定目录下的文件:
hadoop fs -ls <path>
HDFS路径(称为资源)使用URI格式来表示:scheme://authority/path scheme协议名:file或hdfs;authority:NameNode主机名+端口号;path:文件路径
hadoop fs -ls hdfs://winstar:9000/user/root
如果在core-site.xml中有如下配置,则直接使用/user/root(路径)即可。即hadoop fs -ls /user/root
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://winstar:9000</value>
</property>
</configuration>
HDFS默认工作目录为/user/$USER,$USER表示当前账户的用户名。
常用的命令示例
在user/目录下创建trunk子目录:
hadoop fs -mkdir /user/trunk
列出user/目录下所有文件和子目录:
hadoop fs -ls /user
递归列出user/目录下所有文件和子目录
hadoop fs -lsr /user
将本地目录下test.txt文件上传至HDFS当前目录
hadoop fs -put test.txt .
将HDFS/user/root/test.txt文件下载至本地当前目录
hadoop fs -get /user/root/test.txt
查看/user/root/test.txt文件内容
hadoop fs -cat /user/root/test.txt
查看/user/root/test.txt文件的尾部内容(最后1K)
hadoop fs -tail /user/root/test.txt
删除/user/root/test.txt文件
hadoop fs -rm /user/root/test.txt
查看ls命令的帮助文档
hadoop fs -help ls
使用Java API访问HDFS
APIDOC: http://hadoop.apache.org/docs...
Configuration类:该类的对象封装了配置信息,这些配置信息来自core-*.xml;
FileSystem类:文件系统类,可使用该类的方法对文件/目录进行操作。一般通过FileSystem的静态方法get获得一个文件系统对象;
FSDataInputStream和FSDataOutputStream类:HDFS中的输入输出流。分别通过FileSystem的open方法和create方法获得。
操作文件程序的基本步骤
得到Configuration对象
得到FileSystem对象
进行文件操作
将本地文件上传到HDFS
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
public class CopyFromLocal {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://localhost:9001");
FileSystem fs = FileSystem.get(conf);
Path src = new Path("/usr/local/hadoop-2.7.2/README.txt");
Path dst = new Path("hdfs://localhost:9001/home/");
fs.copyFromLocalFile(src, dst);
System.out.println("upload to "+conf.get("fs.default.name"));
fs.close();
}
}
将HDFS上的文件传回到本地
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://localhost:9001");
FileSystem fs = FileSystem.get(conf);
Path src = new Path("hdfs://localhost:9001/home/README.txt");
Path dst = new Path("/home/hadoop/Desktop/");
fs.copyToLocalFile(src, dst);
fs.close();
删除文件/目录, 当删除对象为目录时,将第二个参数设为true否则将产生异常
Path dfs = new Path("hdfs://localhost:9001/home/test.txt");
System.out.println(fs.delete(dfs,true));
fs.close();
创建目录
Path dfs = new Path("hdfs://localhost:9001/home1/");
System.out.println(fs.mkdirs(dfs));
fs.close();
在HDFS上创建文件,并写入
Path dfs = new Path("hdfs://localhost:9001/home/test.txt");
FSDataOutputStream outputStream = fs.create(dfs);
byte[] buff = "hello world!".getBytes();
outputStream.write(buff,0, buff.length);
outputStream.close();
fs.close();
读取文件
Path dst = new Path("hdfs://localhost:9001/home/test.txt");
if(fs.exists(dst) && !fs.isDirectory(dst)) {
FSDataInputStream is = fs.open(dst);
FileStatus stat = fs.getFileStatus(dst);
byte[] buffer = new byte[(int) stat.getLen()];
is.read(buffer);
System.out.println(new String(buffer));
is.close();
fs.close();
} else {
throw new Exception("fail to read file "+dst.toString());
}
追加文件内容,注:需要将hdfs-site.xml中的dfs.support.append属性设置为true
<property>
<name>dfs.support.append</name>
<value>true</value>
</property>
Configuration conf = new Configuration();
//conf.setBoolean( "dfs.support.append", true );
FileSystem fs = FileSystem.get(conf);
Path dfs = new Path("hdfs://localhost:9001/home/test.txt");
FSDataOutputStream outputStream = fs.append(dfs);
byte[] buff = "test".getBytes();
outputStream.write(buff);
outputStream.close();
fs.close();
参考:
http://hadoop.apache.org/docs...
http://blog.csdn.net/xman_200...
http://www.jdon.com/bigdata/h...
http://www.cnblogs.com/davidw...
http://www.cnblogs.com/laov/p...
https://my.oschina.net/crxy/b...
http://blog.csdn.net/fanxiaob...
http://www.cnblogs.com/finalb...
http://blog.csdn.net/yew1eb/a...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。