写在前面: 本文详细介绍了HDFS的存储模型、架构设计以及读写流程,作为Hadoop计算层分治和并行计算的核心,为后续介绍MapRedcue打下了基础。
存储模型
- 文件线性按字节切割成块(
block),block具有offset和id - 文件与文件的
block大小可以不一样 - 一个文件除了最后一个
block,其他block大小一致 block的大小一句硬件的I/O特性调整block被分散存放再集群的节点中,具有locationblock具有副本(replication),没有主从概念,副本不能出现在同一个节点- 副本是满足可靠性和性能的关键
- 文件上传可以指定
block大小和副本数,上传后只能修改副本数 - 一次写入多次读取,不支持修改(因为修改了其中的一个
block,后续的block都要进行调整,并且还要重新分发至副本,会降低性能) - 支持追加数据
架构设计
HDFS是一个主从(Master/Slaves)架构- 由一个
NameNode(主)和一些DataNode(从)组成,均为进程 - 面向文件,包括文件数据(
data)和文件元数据(metadata) NameNode负责存储和管理文件元数据,并维护了一个层次型的文件目录树(虚拟目录结构)DataNode负责存储文件数据(block块),并提供block的读写DataNode与NameNode维持心跳,并汇报自己持有的block信息Client和NameNode交互文件元数据和DataNode交互文件block数据
上图中,在NameNode维护的元数据中保存了两个文件的文件名、副本数和blockid。文件part-0副本数为2,block id分别为1和3.文件part-1副本数为3,block id分别为2、4和5.在DataNode可以看到id为1和3的block会出现在2个DataNode中,id为2、4和5的block会出现在3个DataNode中
角色功能
NameNode
- 完全基于内存存储文件元数据、目录结构、文件
block的映射(基于内存可以快速对外提供服务) - 需要持久化方案保证数据的可靠性(内存掉电易失、大小也有限制)
- 提供副本防止策略
DataNode
- 基于本地磁盘来存储
block,并且会以文件的形式来存储(即,HDFS没有帮我们存数据,只做了管理映射的功能) - 并保存
block的校验和(checksum),保证block的可靠性 - 与
NameNode保持心跳,汇报block列表状态
元数据持久化
- 任何对文件系统元数据产生修改的操作,
NameNode都会使用一种称为EditLog的事务日志记录下来 - 使用
FsImage存储内存所有的元数据状态 - 使用本地磁盘保存
EditLog和FsImage EditLog具有完整性,数据丢失少,但回复速度慢,并由体积膨胀风险(记录实时发生的增删改操作,体积小并且记录少时优势最大)FsImage具有恢复速度快,体积与内存数据相当,但不能实时保存,数据丢失多(按照时间间隔将内存全量数据基于某一个时间点向磁盘溢写,更快地滚动更新时点时优势最大)NameNode使用了FsImage + EditLog整合方案:- 滚动将增量的
EditLog更新到FsImage,以保证更近时点的FsImage和更小的EditLog体积(和Redis的持久化也很类似) - 具体的方案可以是:假设
NameNode在8点第一次开机的时候,只写一次FsImage,到9点的时候EditLog记录8-9点的日志,然后将8-9点的日志更新到9点的FsImage中,FsImage的数据时点就变成了9点。但是此时对于正常运行的NameNode来说没有任何作用,如果要达到持久化的好处,可以寻求另外一台机器来做。也就是SecondaryNameNode,后续会说。
- 滚动将增量的
HDFS启动时EditLog和FsImage加载流程
- HDFS搭建时会格式化,格式化操作会产生一个空的
FsImage - 当
NameNode启动时,从硬盘中读取EditLog和FsImage - 将所有
EditLog中的事务作用在内存中的FsImage - 并将这个新版本的
FsImage从内存中保存到本地磁盘上 - 然后删除旧的
EditLog,因为这个旧的EditLog的事务已经作用在FsImage上了
安全模式
NameNode启动后会进入一个称为安全模式的特殊状态,处于安全模式的NameNode不会进行数据块的操作NameNode从所有的DataNode接收心跳信号和数据块状态的报告- 每当
NameNode检测确认某个数据块的副本数目达到最小值,那么该数据块会被认为时副本安全的(safekt reokucated) - 在一定百分比(可配置)的数据块被
NameNode检测确认时安全后,并且等待额外的30s后,NameNode将会推出安全模式 - 接下来它会确定还有哪些数据块的副本没有达到指定数目,并将这些数据块复制到其他
DataNode
SecondaryNameNode(SNN)
- 在非
HA模式下,SNN一般时独立的节点,周期完成对NameNode的EditLog向FsImage合并,减少EditLog大小,减少NameNode启动时间 - 根据配置文件中的
fs.checkpoint.period设置时间间隔,默认3600秒 - 根据配置文件中的
fs.checkpoint.size设置EditLog大小,规定EditLog文件最大值默认为64M
Block副本防止策略
- 第一个副本:放置在上传文件的
DataNode,如果是集群外提交,则随机挑选一台磁盘不太满、CPU不太忙的节点 - 第二个副本:放置在与第一个副本不同的机架节点上
- 第三个副本:与第二个副本相同机架的节点
- 更多副本:随机节点
HDFS写流程
- 客户端找与
NameNode建立连接,并创建元数据。NameNode判断元数据是否邮箱,触发副本放置策略告诉客户端一个有序的DataNode列表 - 客户端与最近的
DataNode建立tcp连接,第一个DataNode和DataNode建立tcp连接,后面以此类推。(pipeline of datanodes) - 客户端将
block切成64k的packet(并用512b的chrunk+4b的chunksum和,即共516b的数据来填充)传给第一个DataNode,第一个DataNode内存存一份磁盘存一份,第一个DataNode再将数据传给第二个DataNode,同时客户端将第二个block传给第一个DataNode,以此类推。流式也是变种的并行。 - 当一个
block传输完成,则客户端继续向NameNode申请传输第二个block。 - HDFS使用这种传输方式,副本数对于客户端时透明的。当
block传输完成,DataNode各自向NameNode进行汇报,同时客户端继续传输下一个block。所以客户端的传输和block的汇报也是并行的
HDFS读流程
- 客户端找与
NameNode建立连接,获取block信息 - 从距离客户端近的
DataNode建立连接(本机、本机架、其他机架副本),DataNode读取block并进行返回 - 客户端尝试下载
block并校验数据完整性
HDFS支持客户端给出文件的offset自定义连接哪些block的DataNode,自定义获取数据。这是支持计算层的分治、并行计算的核心。