架构师训练营 week12 - 学习总结
HDFS
HDFS 架构图
![](https://static001.geekbang.org/infoq/c5/c501ed9176d1f2e171827ebe3ab35956.png)
HDFS 的设计目标
HDFS以流式数据访问模式存储超大文件,运行于商用硬件集群上。
流式数据访问
一次写入多次读取
不适合 HDFS 的场景
低延迟的数据访问, 大量小文件, 多用户随机写入修改文件
HDFS 为了做到可靠性 (reliability) 创建了多份数据块 (data blocks) 的复制 (replicas), 并将它们放置在服务器群的计算节点中 (compute nodes), MapReduce 就可以在它们所在的节点上处理这些数据了。
![](https://static001.geekbang.org/infoq/81/8116169ceb032bd105693a4dcfc7c6cb.png)
HDFS 的设计目标
假设: 节点失效是常态
理想:
任何一个节点失效, 不影响 HDFS 服务
HDFS 可以自动完成副本的复制
文件
文件切分成块(默认大小64M), 以块为单位,每个块有多个副本存储在不同的机器上, 副本数可在文件生成时指定(默认3)
NameNode是主节点,存储文件的元数据如文件名, 文件目录结构, 文件属性(生成时间, 副本数, 文件权限), 以及每个文件的块列表以及块所在的 DataNode 等等。
DataNode 在本地文件系统存储文件块数据,以及块数据的校验和,可以创建、删除、移动或重命名文件,当文件创建、写入和关闭之后不能修改文件内容。
NameNode
NameNode 是一个中心服务器, 负责管理文件系统的名字空间 (namespace) 以及客户端对文件的访问。
NameNode 负责文件元数据的操作,DataNode 负责处理文件内容的读写请求, 跟文件内容相关的数据流不经过 NameNode, 只会询问它跟那个 DataNode 联系,否则 NameNode 会成为系统的瓶颈。
副本存放在那些 DataNode 上由 NameNode 来控制, 根据全局情况做出块放置决定, 读取文件时NameNode 尽量让用户先读取最近的副本来降低带块消耗和读取时延。
NameNode 全权管理数据块的复制,它周期性地从集群中的每个 DataNode 接收心跳信号和块状态报告(Blockreport)。接收到心跳信号意味着该 DataNode 节点工作正常。块状态报告包含了一个该 DataNode 上所有数据块的列表。
一个数据块在 DataNode 以文件存储在磁盘上, 包括两个文件:一个是数据本身, 一个是元数据包括数据块的长度, 块数据的校验和, 以及时间戳。
DataNode 启动后向 NameNode 注册,通过后, 周期性(1小时)的向 NameNode 上报所有的块信息。
心跳是每 3 秒一次,心跳返回结果带有 NameNode 给该 DataNode 的命令如复制块数据到另一台机器或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。
集群运行中可以安全加入和退出一些机器。
HDFS 关键运行机制 - 高可用
HDFS —个名字节点(NameNode) 和多个数据节点(DateNode)
数据复制(冗余机制)
存放的位置(机架感知策略)
故障检测
数据节点
心跳包(检测是否宕机)
块报告(安全模式下检测)
数据完整性检测(校验和比较)
名字节点(日志文件, 镜像文件)
空间回收机制
![](https://static001.geekbang.org/infoq/05/052bbd55efb4ec0e9ff5b08002a37cad.png)
HDFS 如何写文件
![](https://static001.geekbang.org/infoq/e6/e6d404024b92d70c315349ea086373bc.png)
写一个数据块
![](https://static001.geekbang.org/infoq/3c/3c34082ab2b02ca64309c804cfa8e275.png)
使用 HDFS 提供的客户端开发库 Client, 向远程的 NameNode 发起 RPC 请求
NameNode 会检查要创建的文件是否已经存在, 创建者是否有权限进行操作,成功则会为文件创建一个记录,否则会让客户端抛出异常
当客户端开始写入文件的时候,开发库会将文件切分成多个 packets, 并在内部以数据队列 "data queue" 的形式管理这些 packets, 并向 NameNode 申请新的 blocks, 获取用来存储 replicas 的合适的datanodes 列表, 列表的大小根据在 NameNode 中对 replication 的设置而定
开始以 pipeline(管道)的形式将 packet 写入所有的 replicas 中。开发库把 packet 以流的方式写入第一个 datanode, 该 datanode 把该 packet 存储之后,再将其传递给在此 pipeline 中的下一个datanode, 直到最后一个 datanode,这种写数据的方式呈流水线的形式。
最后一个 datanode 成功存储之后会返回一个 ack packet, 在 pipeline 里传递至客户端, 在客户端的开发库内部维护 "ack queue",成功收到 datanode 返回的 ack packet 后会从 "ack queue" 移除相应的packet。
如果传输过程中,有某个 datanode 出现了故障,那么当前的 pipeline 会被关闭, 出现故障的 datanode 会从当前的 pipeline 中移除, 剩余的 block 会继续剩下的 datanode 中继续以 pipeline 的形式传输, 同时 NameNode 会分配新的 datanode, 保持 replicas 设定的数量。
HDFS 如何读文件
![](https://static001.geekbang.org/infoq/58/581d888301defd94a0faf3aca1bfe9ca.png)
使用 HDFS 提供的客户端开发库 Client, 向远程的 NameNode 发起 RPC 请求
NameNode 会视情况返回文件的部分或者全部 block 列表, 对于每个 block, NameNode 都会返回有该block 拷贝的 DataNode 地址
客户端开发库 Client 会选取离客户端最接近的 DataNode 来读取 block。如果客户端本身就是DataNode,那么将从本地直接获取数据。
读取完当前 block 的数据后,关闭与当前的 DataNode 连接,并为读取下一个 block 寻找最佳的DataNode;
当读完列表的 block 后,且文件读取还没有结束,客户端开发库会继续向 NameNode 获取下一批的block 列表。
读取完一个 block 都会进行 checksum 验证, 如果读取 DataNode 时出现错误,客户端会通知 NameNode,然后再从下一个拥有该 block 拷贝的 DataNode 继续读。
HDFS 中的高可用设计
DataNode 中的磁盘挂了怎么办?
DataNode 正常服务
坏掉的磁盘上的数据尽快通知 NameNode
DateNode 所在机器挂了怎么办?
NameNode 是如何知道 DataNode 挂掉了? DataNode 每3秒钟向 NameNode 发送心跳,如果 10 分钟 DataNode 没有向 NameNode 发送心跳,则 NameNode 认为该 DataNode 已经 dead, NameNode 将取出该 DataNode 上对应的 block, 对其进行复制。
NameNode 挂了怎么办?
持久化元数据: 使用操作日志(edit log)记录文件创建,删除,修改文件属性等操作
Fsimage: 包含完整的命名空间, File -> Block的映射关系, 文件的属性(ACL, quota,修改时间等)
![](https://static001.geekbang.org/infoq/62/62b22b377650472b5b714d4abae085df.png)
Client 挂了怎么办?
Client 所在机器挂了会产生一致性问题。
![](https://static001.geekbang.org/infoq/05/0562bfab4ab865c9bd413043cd58e8bd.png)
HDFS 的一致性模型
文件创建以后,不保证在 NameNode 立即可见,即使文件刷新并存储,文件长度依然可能为 0
当写入数据超过一个块后,新的 reader 可以看见第一个块,reader 不能看见当前正在写入的块
HDFS 提供 sync() 方法强制缓存与数据节点同步,sync() 调用成功后, 当前写入数据对所有 reader 可见且一致;
调用 sync() 会导致额外的开销
评论 (1 条评论)