好程序员大数据学习路线分享 分布式文件系统HDFS,设计目标:
1 、存储量大
2 、自动快速检测应对硬件错误
3 、流式访问数据
4 、移动计算比移动数据本身更划算
5 、简单一致性模型
6 、异构平台可移植
特点
优点:
- 高可靠性:Hadoop 按位存储和处理数据的能力强
- 高扩展性:hadoop 是在可用的计算机集簇间分配数据并完成计算任务的,这些集簇可以方便地扩展到数以千计的节点中
- 高效性:hadoop 能够在节点之间动态地移动数据,并保证各个节点的动态平衡,因此处理速度非常快
- 高容错性:hadoop 能够自动保存数据的多个副本,并且能够自动将失败的任务重新分配。
缺点:
- 不适合低延迟数据访问
- 无法高效存储大量小文件(每个文件存储都有属于自己的索引, 元数据庞大就不高效)
- 不支持多用户写入及任意修改文件(可以删除以及追加,只是不能修改文件中某处的数据)
重要特性:
- 文件在物理上是分块存储,块的大小可以通过配置参数(dfs.blocksize) 来规定, 默认 2.x 版本之后是 128M ,老版本是64M
- HDFS 会给哭护短提供一个统一的 抽象目录树 ,客户端通过路径来访问文件, 刑辱: hdfs://namenode:port/dir-a/dir-b/dir-c/file.data
- 目录结构及文件分块信息( 元数据 ) 的管理由namenode 承担—namenode 是 HDFS 集群主节点,负责维护整个 hdfs 文件系统的目录树,以及每一个路径(文件)所对应的 block 块信息( block 的 id 以及所在 datanode 服务器)
- 文件的各个block 的存储管理由 datanode 承担—datanode 是 HDFS 集群从节点,每一个 block 都可以在多个 datanode 上存储多个副本(副本参数设置 dfs.replication)
- HDFS 是设计成适应一次写入, 多次读出的场景, 且不支持文件的修改
- 管理文件系统的命名空间( 元数据<metadata>:包含文件名称、大小、所属人、地址)
- 规定客户端访问文件规则
三个服务
Namenode
任务清单
a) 文件大小是否已经超载( 超过集群的负载)
b) 是否已经存在相同的文件
c) 是否具有创建该文件的权限
- 对文件执行命令,关闭,打开文件或者打开路径等操作
- 所有的数据节点发送心跳给NameNode ,他需要确保数据节点 DataNode 是否在线,一个数据块报告包含所有这个数据节点上的所有 block 的状况
- 首先将fsimage(镜像) 载入内存,并读取执行日志editlog 的各项操作
- 一旦在内存中建立文件系统元数据映射,则创建一个新的fsimage 文件(这个过程不需要 secondaryNamenode )和一个空的 editlog
- 在安全模式下,各个datanode 会向 namenode 发送块列表的最新情况
- 此刻namenode 运行在安全模式。即 NameNode 的文件系统对于客户端来说是只读
- NameNode 开始监听 RPC 和 HTTP 请求
启动过程
RPC:Remote Procedure Call Protocol---远程过程通过协议
它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议
- 系统中数据块的位置并不是由namenode 维护的 , 而是以块列表形式存储在 datanode 中
- 在系统的正常操作期间,namenode 会在内存中保留所有块信息的映射信息
- fsimage:元数据镜像文件(保存文件系统的目录树)
- edit.log: 元数据操作日志( 针对目录树的修改操作)
两个重要文件
元数据镜像
a) 内存中保存一份最新的
b) 内存中镜像=fsimage+edits
SecondaryNamenode
工作任务
定期合并fsimage 与 edits
c) Edits 文件过大将导致 NamenNode 重启速度缓慢
d) SecondaryNameNode 负责定期合并他们
Datanode
hdfs 的写过程
写过程语言Description :
- Client 通过调用 FileSystem 的 get 方法与 namenode 进程建立通道进行通信,然后调用 create 方法来请求创建文件。
- FileSystem 通过对 namenode 发出远程请求,在 namenode 里面创建一个新的文件,但此时并不关联任何的块。 NameNode 进行很多检查来保证不存在要创建的文件已经存在文件系统中,同时检查是否有相应的权限来创建文件。如果这些检查完了, nameNameNode 将这个新文件的嘻嘻记录下来,然后 FileSystem 返回一个 DFSOutputStream 给客户端用来写入数据。和读的情形一样, FSDataOutputStream 将包装一个 DFSOutputStream 用于和 DataNode 及 NameNode 通信。而一旦文件创建失败,客户端会受到一个 IOException,标识文件创建失败,停止后续任务。
- 客户端开始写数。FSDataOutputStream 把要写入的数据分成块打成包的形式,将其写入到 DFSOutputStream 对象的中间队列中。其中的数据由 Datastreamer 来读取。DataStreamer 的职责是让NameNode 分配新的块— 找出合适的DataNode 来存储作为备份而复制的数据。
- FSDataOutputStream 维护了一个内部关于 packets 的队列,里面存放等待被 DataNode 确认无误的 packets 的信息。这个队列被称为等待队列,一个 packet 的信息被移出本队列当且仅当 packet 被所有节点都确认无误。
- 当完成数据写入之后客户端调用流的close 方法,再通知 NameNode 完成写入之前,这个方法将 flush 残留的 packets ,并等待确认信息。 NameNode 已经知道文件由哪些块组成,所以在返回成功前只需要等待数据块进行最小复制。
Write API :
1 . 从本地系统上传到hdfs
Configuration hdfsConf = new Configuration();// 创建一个hdfs 的环境变量
String namenodeURI=”hdfs://hadoop001:8020”;//namenode的统一资源定位符
String username=”root”;// 访问指定用户的hdfs
FileSystem hdfs = FileSystem.get(new URI(namenodeURI),hdfsConf,username);// 创建一个hdfs 的文件系统对象
FileSystem local = FileSystem.getLocal(new Configuration());//创建一个本地的文件系统对象
hdfs.copyFromLocalFile(new Path(localPath),new Path(hdfsPath));
2. 在hdfs 上创建文件并直接给定文件的内容
FSDateOutputStream out = hdfs.create(new Path(hdfsPath));
out.write(fileContent.getBytes());
out.close();
hdfs 的读过程
读过程语言Description :
- 客户端或者用户通过调用FileSystem 对象的 open 方法打开需要读取的文件,这对 HDFS 来说是常见一个分布式文件系统的一个读取实例。
- FileSystem 通过远程协议调用 NameNode 确定文件的前几个 Block 的位置。对于每一个 Block , Namenode 返回含有那个Block 的“元数据”,即文件基本信息;接下来, DataNode 按照上文定义的距离来进行排序,如果Client 本身就是一个 DataNode 优先从本地 DataNode 读物数据。 HDFS 实例完成以上工作后,返回一个 FSDataInputStream 给客户端,让其从 FSDataInputStream 中读取数据。 FSDataInputStream 接着包装一个 DFSInputStream 用来管理 DataNode 和 NameNode 的 I/O 。
- NameNode 向客户端返回一个包含数据信息的地址,客户端格努诋毁创建一个 FSDataInputStream 开始对数据进行读取。
- FSDataInputStream 根据开始存放的前几个 Blocks 的 DataNode 的地址,连接到最近的 DataNode 上对数据开始从头读取。客户端反复调用 read() 方法,以流式方式从DataNode 读取数据
- 当读到Block 的结尾的时候, FSDataInputStream 会关闭当前 DataNode 的地址,然后查找能够读取下一个Block 的最好的 DataNode 。这些操作对客户端是透明的,客户端感觉到的是连续的流,也就是说读取的时候就开始查找下一个块所在的地址。
- 读取完成调用close() 方法,关闭FSDataInputStream 。
Read API :
1 . 从h dfs 上下载文件到本地
Configuration hdfsConf = new Configuration();// 创建一个hdfs 的环境变量
String namenodeURI=”hdfs://hadoop001:8020”;//namenode的统一资源定位符
String username=”root”;// 访问指定用户的hdfs
FileSystem hdfs = FileSystem.get(new URI(namenodeURI),hdfsConf,username);// 创建一个hdfs 的文件系统对象
FileSystem local = FileSystem.getLocal(new Configuration());//创建一个本地的文件系统对象
hdfs.copyToLocalFile(new Path(hdfsPath),new Path(localPath));
3. 在hdfs 上读取给定文件的内容
Path path = new Path(hdfsFilePath);//文件路径
FSDataInputStream in = hdfs.open(path);//获取文件输入流
FileStatus status = hdfs.getFileStatus(path);//获取文件的元数据信息
//获取文件元数据中的文件大小
byte[] bytes = new byte[Integer.pareInt(String.valueOf(status.getLen()))];
//将输入流中的全部内容一次性读取出来
in.readFully(0,bytes);
System.out.println(new String(bytes));//将读取的文件打印输出
in.close();
hdfs 的整体过程
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69913892/viewspace-2654618/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/69913892/viewspace-2654618/