分布式文件系统HDFS
参考书目:人民邮电出版社《大数据技术》
一、概述
1.什么是分布式文件系统
分布式文件系统(Distributed File System)是一种通过网络连接多台主机并在这些主机上进行分布式文件存储的文件系统,目前被广泛应用的有GFS和HDFS
2.什么是计算机集群结构
若干主机放在机架上,若干机架通过交换机相连共同构成的一个计算机集群通常可用于分布式文件系统。
3.分布式文件系统的结构
在windows或者Linux操作系统中,文件系统会把磁盘空间划分为固定大小的一块,被称为“磁盘块”,文件系统中“块”的大小通常是磁盘块大小的整数倍,以便于读写。当一个文件小于数据块,他也会完整占用整个数据块。
分布式文件系统也有块的概念,只是在普通操作系统中,一个块通常比较小,是以字节为单位的,但是对于分布式文件系统,比如HDFS,一个块默认为64MB,而且如果一个文件大小小鱼一个数据块时,他也不单独完全占用一个数据块。
分布式文件系统在物理层面上由一个个节点组成,这些节点分为两类,一类叫做“主节点”/“名称节点”,另外一种叫做“从节点”/“数据节点”。主节点会负责一些重要的关乎大局的事务,比如文件和目录的创建删除重命名等,以及存储了数据节点和文件之间的映射关系,数据节点负责数据的存储,其他概不负责。
在数据的读写过程中,流程往往是这样的:
- 客户端向名称节点发送访问请求
- 名称节点接受该请求并查找映射关系,寻找对应需要的数据节点
- 名称节点把客户端需要访问的数据节点的地址发给客户端
- 客户端直接访问名称节点进行读写
为了保证数据存储的完整,分布式文件系统通常会采用多副本的存储方式,同样的一个文件块会复制出多个副本存储在不同节点上,并且不同节点还会分布在不同的机架上,这样就最大程度的减少了节点故障甚至机架故障给整个系统带来的破坏。
由于这些特性,分布式文件系统处理小文件不仅无法发挥其优势,甚至会影响系统的性能。
4.分布式文件系统的设计需求
透明性、并发控制、文件复制、硬件和操作系统的异构性、可伸缩性、容错、安全需求
二、HDFS简介
HDFS原来是Apache Nutch搜索引擎的一部分,后来独立成为一个子项目,并和MapReduce一起成为Hadoop的核心组成部分。HDFS支持流数据读取和处理超大规模文件,并且可以在廉价的普通机器组成的集群上部署和使用,其被要求实现以下目标:(特点)
- 兼容廉价的硬件设备
- 流数据读写
- 大数据集
- 简单的文件模型
- 强大的跨平台兼容性
- 不适合低延迟数据访问
- 无法高效存储大量小文件
- 不支持多用户写入以及任意修改文件
三、HDFS的相关概念
1. 块
传统的文件系统中,为了提高磁盘读写利用率,通常会把按照一定的大小把需要读写的文件分成一个一个的块,每次读写一个数据块,这样做可以避免每次数据读写大小不一致造成的资源浪费。
HDFS默认的一个块为64MB,明显大于传统文件系统,这是因为HDFS定位是处理大数据,采用较大的数据块可以减少磁盘寻道开销。具有以下好处:
- 支持大规模文件存储
- 简化系统设计
- 适合数据备份
2. 名称节点和数据节点
名称节点负责管理分布式文件系统的命名空间,保存了FsImage和EditLog两个数据结构:
- FsImage用于维护文件系统树以及文件树中所有的文件和文件夹的元数据。
- EditLog操作日志文件中记录了所有针对文件的创建、删除、重命名等操作。
名称节点记录了每个文件中各个块所在数据节点的信息,但是它并不本身存储这些信息,而是每次启动系统时回扫描所有数据节点并记录,关机后就会消失。
名称节点启动时,会把FsImage内容加载到内存中,然后执行EditLog中的操作,使其更新到最新状态,在随后的运行过程中,更改并不直接作用于FsImage,而是登记到EditLog中。(原因是大数据FsImage通常都是很大的,直接更改会拖慢系统效率。
名称节点在启动时会处于安全模式,只对外提供读操作,不提供写操作。
数据节点负责数据的实际存储和读取,会定期向名称节点发送自己存储的列表信息,每个数据节点的数据会被保存在各自节点本地的Linux文件系统中。
3. 第二名称节点
当EditLog记录过多操作之后,会导致EditLog文件也变大,进而影响到系统效率,于是产生了第二名称节点,可以完成EditLog和FsImage的合并操作,形成新的FsImage文件。具体过程如下:
- 每隔一段时间,会停止使用原先的EditLog文件,把新的操作写入EditLog.new文件。
- 第二名称节点把原先的FsImage和原先的EditLog进行合并,形成新的FsImage.ckpt。
- 第二名称节点把FsImage.ckpt发送给名称节点,替换掉原先的FsImage文件,同时把EditLog.new替换EditLog文件
第二名称节点是名称节点的检查点,会定期和名称节点通信,周期性的备份名称节点中的元数据信息,当名称节点出现故障时,可以用上一次备份的元数据信息进行系统恢复
四、HDFS体系结构
1. 概述
HDFS采用了主从结构模型,包含一个名称节点和若干个数据节点,每个数据节点会周期性的向名称节点发送“心跳”信号报告自己的状态,如果没有按时发送报告信息,则这个数据节点会被标记为“死机”不会再给这个数据节点分配IO请求。
对用户来说,HDFS可以使用文件名去存储和访问文件,虽然一个文件会被分为若干份分布存储到若干个数据节点上。
客户端访问文件前,把文件名发送给名称节点,名称节点会根据文件名查询数据对应存储的数据块,并把数据节点的位置发送给客户端,客户端直接访问数据节点获取数据,在此过程中,数据节点不参与数据的传输,这样可以让数据节点并发访问,提高数据访问速度。用户数据不会经过名称节点,这样大大减轻了中心服务器的负担,方便数据管理。
2. 命名空间管理
HDFS的命名空间包含目录、文件和块,命名空间管理是指命名空间支持对HDFS中的目录、文件和块做类似文件系统的创建、修改、删除等基本操作。
3. 通信协议
客户端与名称节点直接使用TCP/IP协议连接,名称节点和数据节点之间使用数据节点协议进行交互,客户端与数据节点之间使用远程调用RPC实现。
4. 客户端
客户端不算HDFS的一部分
5.HDFS体系结构的局限性
HDFS通过设置一个名称节点的方式,简化了系统设计,但是也造成了以下明显的局限性:
- 命名空间的限制,名称节点能容纳对象的个数受内存大小的限制(所以不适合存储大量小文件)
- 性能瓶颈,整个分布式文件系统的吞吐量取决于名称节点的处理速度
- 隔离问题,集群只有一个名称节点一个命名空间,无法对不同的应用程序进行隔离
- 可用性,一旦这个唯一的名称节点发生故障,整个集群都不变的不可用
五、HDFS的存储原理
1. 数据的冗余存储
HDFS采用了多副本方式对数据进行冗余存储,一个数据块的多个副本会被放置在不同机架的不同的数据节点上,一般是三个,他有以下优点:
- 加快数据传输速度,多个客户端访问统一文件时,不需要排队或者拥挤,同时访问不同的副本,加快了数据传输速度
- 容易检查数据错误,数据节点之间通过网络传输数据,容易出错,多副本可以检查是否出错
- 保证数据的可靠性,即使某个数据节点出现故障,也不会导致数据丢失。
2. 数据存取策略
- 数据存放
HDFS采用以机架为基础的数据存放策略,实现了网络带宽的充分利用,同一个机架上的数据节点之间可以直接通信,不同机架上的数据节点则需要通过路由器或者交换机。
HDFS默认每个数据节点都在不同的机架上,但这样做会导致写入数据的时候,不能成分利用同一机架内部的贷款,不过带来了很显著的优点:
- 获得了很高的数据可靠性
- 可以在多个机架上并行读取数据
- 数据读取
HDFS提供了一个API可以确定一个数据节点所属的机架ID,客户端也可以调用API获取自己当前所属机架ID,同时在读取数据时,可以通过查看数据块副本所属ID的位置是否与当前ID相同来决定是否优先选用某副本读取,因为读取同一个机架上的数据块副本有利于充分利用网络带宽 - 数据复制
HDFS存储文件时,一个数据块被名称节点分配好冗余存储的副本位置之后,会把这个位置列表和数据一同发送给第一个数据节点,当传输完第一个4KB的数据后,第一个数据节点会按照列表指示,把刚才收到的4KB传输给第二个数据节点,以此类推,当文件写完的同时,几乎数据复制也同时完成,大大提高了数据复制过程的效率。
3. 数据错误与恢复
名称节点出错:
- Hadoop把名称节点上的元数据信息同步存储到其他文件系统,比如网络文件系统NFS
- 运行第二个名称节点,并把第二名称节点当作名称节点使用
数据节点出错: - 没有收到“心跳”信息的话,将其标记为死机,节点上的数据标记为不可读,不再给它发送任何IO请求,名称节点会定期检查数据块的副本数量是否少于冗余因子(一般是3),如果小于的话就启动数据冗余复制,生成新的副本。
数据出错: - 网络传输和磁盘问题都会造成数据错误,用户读取数据后会采用MD5和SHA-1对数据块进行校验,确保正确读取,如果校验失败,会客户端会请求读取另外一个数据节点,冰箱名称节点报告这个文件块有问题,名称节点会定期检查并重新复制这个块
六、HDFS的数据读写过程
FileSystem是一个通用文件系统的抽象类,可以被分布式文件系统继承,所有可能使用Hadoop文件系统的代码都要使用这个类(java语言)。
DistributedFileSystem时FileSystem在HDFS中的实现。
FileSystem中的open()方法返回的是一个输入流FSDataInputStream对象,在HDFS中具体的输入流就是DFSInputStream。
FileSystem中的create()方法返回的是一个输出流FSDataOutputStream对象,在HDFS中具体的输出流就是DFSOutputStream。
1. 读数据的过程
- 客户端FileSystem.open()打开文件,DistributedFileSystem会创建DFSInputStream输入流
- 输入流通过ClientProtocol.getBlockLocation()远程调用名称节点,获得文件开始部分数据块的保存位置。名称节点返回保存该数据块的所有数据节点,通过远近对数据节点进行排序,DistributedFileSystem会利用DFSInputStream来实例化FSDataInputStream,并返回给客户端,同时返回数据块的数据节点地址。
- 获得输入流FSDataInputStream后,客户端调用read()方法读取数据,输入流根据排序结果选择最近的数据节点建立连接并读取数据。
- 数据块读取完毕时,FSDataInputStream关闭和这个数据节点的连接
- 输入流通过getBlockLocation()方法查找下一个数据块,同样的方法找到最佳数据块所处的最佳数据节点,建立连接,读取数据
- 读取完数据后,再用FSDataInputStream的close()方法,关闭输入流。
2. 写数据的过程
简单来说吧
- 客户端通过FileSystem.create()创造文件,DistributedFileSystem具体实现了FileSystem,DistributedFileSystem创建输出流FSDataOutputStream,具体HDFS输出流是DFSOutputStream
- DistributedFileSystem通过RPC远程调用名称节点,在文件系统的命名空间中创建一个新的文件,调用结束后DistributedFileSystem会实例化FSDataOutputStream,并返回给客户端
- 客户端调用输出端的write()方法写入数据
- 写入的数据被分为一个个的分包,放入DFSOutputStream对象的内部队列,输出流FSDataOutputStream向名称节点申请保存文件和副本块(流水线复制)
- 接收到数据的数据节点向发送者发送ACK确认包
- 客户端调用close()方法关闭输出流,当DFSOutputStream对象内部队列的分包都收到应答以后,使用ClientProtocol.complete()方法通知名称节点关闭文件,完成写入。