这是我参与「第四届青训营 」笔记创作活动的的第11天
HDFS架构原理
架构组件
HDFS架构主要由3个组件组成:
- Clinet/SDK:如命令行,用于用户操作,或者是程序通过SDK访问HDFS
- NameNode:中枢节点,负责存储元数据信息,多节点副本之间的统一等,HDFS的核心
- DataNode:真正存储文件的节点
Client写流程
一个要注意的点是,Client首先要向NameNode获取可以存储数据的DataNode(dn08,dn01,dn06),写入3个副本。
另一个要注意的是写数据块这一步,在写的过程中是通过Pipeline方式写入。
Client读流程
Client端并不知道哪些DataNode存储了目标文件,要向NameNode获取,NameNode返回了3个DataNode,一般直接从返回的第一个DataNode读取数据。
NameNode
NameNode作为整个架构的核心,其包含的任务繁多且复杂,我们这里先列举比较重要的几个作用
- 维护目录树
- 我们对目录树的增删改查操作,如删除一个目录或者修改目录下的文件,这些任务都是在NameNode中执行的,它要保证所有修改都能持久化。
- 维护文件和数据块的关系
- 存入文件时会将它切分成多个块,这些块又被存储在多个副本,NameNode需要存储它们之间的对应关系
- 维护文件块存放节点信息
- 通过接收DataNode的心跳汇报信息,维护集群节点的拓扑结构和每个文件块所有副本所在的DataNode类表。
- 分配新文件存放节点
- Client端需要写文件的时候,由NameNode分配该文件存储的DataNode,如上面介绍到的Client写流程。
DataNode
DataNode在主要负责文件的存储,需要负责的任务比较简单:
- 数据块存取
- DataNode与硬盘接轨,需要高效的实现读和写文件。
- 心跳汇报
- 定时把本机所存储的数据块信息发送给NameNode,同时让NameNodeque确认节点的状态。
- 副本复制
- 机械故障时补全副本,在写入时以Pipeline方式输入,并输出给下一个DataNode。
HDFS关键设计
NameNode 目录树维护
- fsimage
- NameNode运行时负责维护目录树的结构
运行时存放在内存,修改时只会修改内存中的目录树,同时定期将内存中的目录树快照(snapshot)并保存在硬盘上,fsimage作为日常目录树的保存维护,在这个节点遇到故障挂掉之后,目录的修改不会保存在硬盘上,就引入了Editlog这一概念。
- Editlog
- 相当于增删改操作的日志,对目录树的更改都会有一条记录,在fsimage故障恢复之后,就通过Editlog同步目录树的更改。在HDFS高可用中也起着重要的作用。
NameNode 数据放置
需要知道的是,NameNode并不会持久化DataNode上数据块的信息,而是根据DataNode传来的心跳包动态维护位置信息。
NameNode放置数据通常要将文件存储到不同的机器上,避免一个机器挂掉了备份的副本也全没了这种情况。
- 数据均衡怎么合理搬迁数据?
- 通过旁路系统,Balancer以及Mover等完成。
DataNode
- 数据块硬盘存放
- 文件在NameNode时已经被分割成Block块,DataNode则以Block为单位存取数据。
- 启动扫盘
- DataNode需要向NameNode汇报Block块信息,它也不会持久化这些信息,而通过启动时扫盘获取块信息并加载到内存中。
HDFS写异常处理
Lease Recovery
Client在写文件到DataNode的过程中,NameNode会给这些DataNode加锁(租约),防止被其他操作所调用,但如果Client在这时挂掉了,这个锁就可能无法释放,同时文件副本也可能存在不一致的状态,为了解决这些问题,就使用了Lease Recovery(租约恢复)
- 副本不一致
- Lease Recovery会比对三个DataNode中副本的大小,如果不一致则以较小的副本为准。
- 租约无法释放
- NameNode会和Client定时续租,如果Client长时间不续租,NameNode就会抛弃掉这个租约,允许其他客户端调用DataNode。
Pipeline Recovery
Pipeline Recovery适用于另一种异常场景。
- 异常场景
- 创建连接
- 数据传输
- Complete阶段
对应的解决方法:
- 创建连接时
- 重新建立一个新的连接即可
- 数据传输 / Complete阶段
- Pipeline会将故障的节点排除,进行Pipeline重新构建
HDFS读异常处理
相比写异常处理,读异常处理就比较简单,如果读异常时如果节点出现故障,由于同一个文件存放了多个副本,我们就切换到其他副本的DataNode读取。