HDFS 全称是Hadoop Distributed File System hadoop分布式(cluser)文件存储系统。适合一次写入,多次读出的场景。
HDFS不需要单独安装,安装Hadoop的时候带了HDFS系统。
Hadoop安装可以参考:
- 有基础的,已经安装了虚拟机的 : Hadoop安装
- 没有基础, 也没有安装虚拟机的: Hadoop集群安装
HDFS的优缺点:
- 优点:高容错性,适合处理大数据,可构建在廉价机器上
- 缺点:不适合低延时数据访问;无法高效对大量小文件进行存储,不支持并发写入、数据修改。
HDFS文件块大小:
HDFS中的文件再物理上是分块存储,块的大小可以通过配置参数(dfs.blocksize)来规定,默认大小在Hadoop2.x/3.x版本中是128M,1.x版本中是64M
注:寻址时间为传输时间的1%时,为最佳状态
思考:为什么块的大小不能设置太小,也不能设置太大?
(1)HDFS的块设置太小,会增加寻址时间
(2)块太大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。导致程序处理块数据时,会非常慢。
总结:HDFS块的大小设置主要取决于磁盘的传输速率。
HDFS结构:
HDFS是一个主/从体系结构(经典的Master和Slave架构)。
HDFS由四部分组成,HDFS Client,NameNode,DataNode和Secondary NameNode。
每一个HDFS集群包括一个NameNode和多个DataNode
1、Client客户端
通过Client来访问文件系统,然后由Client与NameNode和DataNode进行通信。Client对外作为文件系统的接口
- 文件切分,文件上传HDFS的时候,将文件切分成一个一个的数据块(Block)进行存储
- 与NameNode交互,获取文件位置
- 与DataNode交互,读取或写入数据。存储实际的数据块,执行数据库的读写操作
- Client提供一些命令来管理HDFS,比如NameNode格式化
- Client可以通过一些命令来访问HDFS,比如对HDFS增删改查操作
2、NameNode ( nn )
相当于一个Master,管理者。 用于存储和管理文件元数据、维护文件系统的目录结构树,记录写入的每个数据块(Block)与其归属文件的对应关系。
- 管理HDFS的名称空间
- 配置副本策略
- 管理数据块的映射信息
- 处理客户端的读写请求
3.dataNode
DataNode会通过心跳和NameNode保持通信。DataNode负责存储文件的数据(block块),并提供block的读写,并且定期的向NameNode汇报该DataNode存储的数据块信息
4、Secondary NameNode
Secondary NameNode的作用是消费EditsLog,定期地合并FsImage和EditsLog,生成新的FsImage文件,并推送给NameNode,降低了NameNode的压力。 在紧急情况下,可辅助恢复NameNode
注:
1、FsImage(文件系统镜像二进制)
存储某一个时间点(checkPoint)的NameNode镜像数据
默认存储位置 : /opt/install/hadoop-2.5.2/data/tmp/dfs/name
dfs.namenode.name.dir
2、EditsLog
可编辑日志二进制 记录(检查点以后的所有写操作)
默认存储位置 :dfs.namenode.edits.dir
HDFS高可用设计:
数据存储故障容错:
磁盘在存储数据可能会出现错乱。HDFS对于存储在DataNode上的数据块,计算并存储校验和(CkeckSum)。在读取数据的时候,重新计算读取出来的数据的校验和,如果校验不正确就抛出异常,应用程序捕获异常后就到其他DataNode上读取备份数据。
磁盘故障容错:
如果DataNode检测到本机的磁盘损坏,就将磁盘上存储的BlockID报告给NameNode, NameNode检查这些数据块的备份,通知相应的DataNode服务,将对应的数据恢复到其他服务器上,以保证数据块备份数满足要求。
DataNode故障容错:
DataNode会通过心跳和NameNode保持通信,偌DataNode超时未发送心跳,NameNode就认为该DataNode已经宕机,并立即查找DataNode上的数据块,以及这些数据块所在的服务器,随后通知这些服务器再复制一份数据到其他服务器上,以保证HDFS存储的数据块备份数符合要求。
NameNode故障容错:
NameNode是整个HDFS的核心, 记录这所有文件的分配信息,以及所有文件路径和数据块存储信息。如果NameNode故障, 整个HDFS系统集群都无法使用,如果NameNode的数据丢失,整个集群的所有DataNode数据也就无用了。所以NameNode采用主从热备的方式提供高可用服务。如下图:
HDFS读写过程:
写流程:
- 请求上传:client向namenode通信,请求上传文件
- namenode判断是否可上传: namenode检查用户是否有上传的权限、目标文件是否已存在、父目录是否存在
- 文件切分:client将文件切分成0~128M大小的block块(逻辑切分)
- client请求block块的存储位置
- namenode返回datanode地址dn1、dn2、dn3
- client通过FSDataOutputStream模块请求dn1上传数据,建立连接管道(本质上是一个 RPC 调用,建立 pipeline)
- 当dn1收到请求后会继续调用dn2, dn2调用dn3,将整个通信管道建立完成,然后逐级返回client,即图中的ack校验
- client开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位(默认64k),dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答
- 当一个Block传输完成之后,client再次请求NameNode上传第二个Block的服务器(重复执行4-8步)
- 传输完毕之后,客户端关闭流资源,并且会告诉hdfs数据传输完毕,然后hdfs收到传输完毕就恢复元数据
读流程:
- Client 向 NameNode 发起 RPC 请求,来确定请求文件 block 所在的位置;
- NameNode 会视情况返回文件的部分或者全部 block 列表,对于每个 block,NameNode 都会返回含有该 block 副本的 DataNode 地址;
- 这些返回的 DataNode 地址,会按照集群拓扑结构得出 DataNode 与客户端的距离,然后进行排序,排序两个规则:网络拓扑结构中距离Client近的排靠前;心跳机制中超时汇报的 DataNode 状态为 STALE,这样的排靠后;
- Client 选取排序靠前的 DataNode 来读取 block,如果客户端本身就是 DataNode,那么将从本地直接获取数据;底层上本质是建立 Socket Stream(FSDataInputStream),重复的调用父类 DataInputStream 的 read 方法,直到这个块上的数据读取完毕;
- 当读完列表的 block 后,若文件读取还没有结束,客户端会继续向 NameNode 获取下一批的 block 列表;
- 读取完一个 block 都会进行 checksum 验证,如果读取 DataNode 时出现错误,客户端会通知 NameNode,然后再从下一个拥有该 block 副本的 DataNode 继续读。
- read 方法是并行的读取 block 信息,不是一块一块的读取;NameNode 只是返回 Client 请求包含块的 DataNode 地址,并不是返回请求块的数据;
- 最终读取来所有的 block 会合并成一个完整的最终文件。
HDFS存储模型:
-
文件按字节线性切割成block块, 具有offset、id
-
一个文件除了最后一个block, 其它block大小一致
-
block大小依据硬件的I/O 特性调整
-
block被分散在集群的节点中,具有location
-
block具有副本(replication), 没有主从概念,副本不能出现在同一个节点
-
副本是满足可靠性和性能的关键
-
文件上传可以指定block大小和副本数,上传后只能修改副本数
-
一次写入多次读取,不支持修改,只支持追加数据