前文分析了 NameNode,本文进一步解析 DataNode 的设计和实现要点。

文件存储

DataNode 正如其名是负责存储文件数据的节点。HDFS 中文件的存储方式是将文件按块(block)切分,默认一个 block 64MB(该大小可配置)。若文件大小超过一个 block 的容量可能会被切分为多个 block,并存储在不同的 DataNode 上。若文件大小小于一个 block 的容量,则文件只有一个 block,实际占用的存储空间为文件大小容量加上一点额外的校验数据。也可以这么说一个文件至少由一个或多个 block 组成,而一个 block 仅属于一个文件。

block 是一个逻辑概念对象,由 DataNode 基于本地文件系统来实现。每个 block 在本地文件系统中由两个文件组成,第一个文件包含文件数据本身,第二个文件则记录 block 的元信息(metadata)如:数据校验和(checksum)。所以每一个 block 对象实际物理对应两个文件,但 DataNode 不会将文件创建在同一个目录下。因为本机文件系统可能不能高效的支持单目录下的大量文件,DataNode 会使用启发式方法决定单个目录下存放多少文件合适并在适当时候创建子目录。

文件数据存储的可靠性依赖多副本保障,对于单一 DataNode 节点而言只需保证自己存储的 block 是完整且无损坏的。DataNode 会主动周期性的运行一个 block 扫描器(scanner)通过比对 checksum 来检查 block 是否损坏。另外还有一种被动的检查方式,就是当读取时检查。

文件操作

HDFS 支持的文件操作包括写入(新增、追加)、读取和删除。HDFS 定义了一种 multi-reader, single-writer 的文件访问语义。而访问标准依然参照大家熟悉的依据 POSIX(Portable Operating System Interface)为单机文件系统定义的 API。

  • Open 打开文件
  • Read/Write 读写文件
  • Close 关闭文件

下面我们分别讲述文件操作的设计实现要点。

写文件

写文件流程如图示,在分布式环境下,Client 请求 NameNode 获得一个针对指定文件的租约(lease,本质上是一种分布式锁,详细请自行维基百科下)。只有持有该租约的 Client 可以向该文件写入,以这种机制来确保写文件的 single-writer 的语义。获得写入租约后 NameNode 向 Client 分配一组用于存放文件数据的 DataNodes,若配置的副本数为 3,则会返回 3 个 DataNode。这一组 DataNodes 被组成一条流水线来写入,有效提升写入性能降低写入延迟。Client 将文件组织成一个个 packet 发送给流水线上第一个 DataNode,第一个 DataNode 存储下该 packet 后再转发给第二个 DataNode,依此类推。然后 DataNodes 再按流水线反方向发回确认 packet 给 Client。当所有文件 block 写入完成后,DataNodes 会向 NameNode 报告文件的 block 接收完毕,NameNode 相应去改变文件元数据的状态。

写文件的主体流程如上所述,如果过程中一切正常那么多么简单美好。但实际在分布式环境下,写文件过程涉及 Client、NameNode 和一组 DataNodes,这其中任何一个环节都有可能产生异常。按照分布式设计第一原则:Design for failure,我们需要考这个流程中的所有参与者都有可能出现失败异常的情况。这里先提出这个问题,考虑每种失败异常的场景下,软件设计实现要怎么去处理?本文先不在这里展开论述,后面会专门撰文深入分析。

读文件

读文件流程如图示,Client 首先请求 NameNode 定位文件 block 所在的 DataNodes。然后按顺序请求对应的 DataNodes 读取其上存储的 block。关于读取顺序,HDFS 有一个就近读取的优化策略,DataNodes 的读取排序会按照它们离 Client 的距离来确定。距离的概念主要区分以下几种场景:

  • 距离 0,表示在同一个节点上
  • 距离 2,表示同一个机架下的不同节点
  • 距离 4,表示同一个数据中心的不同机架下
  • 距离 8,表示不同的数据中心

删文件

文件删除的处理首先将文件重命名后放进 /trash 目录。文件会在 /trash 目录中存放一段时间(可配置),在时间到期后再自动清理。所以实际上文件删除操作非常轻量级,仅仅是 NameNode 的内存数据结构的变动,真正的物理删除在后续的自动清理时才做。

可见性

在文件写入过程中,HDFS 不保证文件对其他 Client Reader 可见。只有文件的 block 已经写入 DataNode,并报告给了 NameNode 更新到正确的状态才对其他 Reader 可见。简单说,如果一个文件有多个 block,写入总是发生在最后一个 block 上,那么前面的 block 对其他 Reader 是可见的,但最后一个 block 则不可见,这涉及 block 的状态变化,这里先不展开,后面会专门撰文深入分析。

生命周期

DataNode 启动后首先连接到 NameNode 完成握手,握手的目的是验证 DataNode 的软件版本和 namespace ID。namespace ID 是整个 HDFS 集群的唯一标识,如果 DataNode namespace ID 或 软件版本与 NameNode 不匹配,DataNode 将无法加入集群并自动关闭。若是一个全新的 DataNode 启动时没有 namespace ID,则在握手时由 NameNode 分配并加入集群。此外,NameNode 还会分配一个集群全局唯一的 storage ID 给 DataNode 用于唯一标记,之后不再改变。

完成握手后,DataNode 会立刻向 NameNode 发送 block report 信息,block report 就是 DataNode 上存储了哪些文件 block 的列表。之后会定期(默认 1 小时)向 NameNode 报告。此外,DataNode 将定时向 NameNode 发送心跳(默认 3 秒)来报告自身的存活性。一段时间(默认 10 分钟)收不到 DataNode 最近的心跳,NameNode 会认定其死亡,并不会再将 I/O 请求转发到其上。心跳除了用于 DataNode 报告其存活性,NameNode 也通过心跳回复来捎带控制命令要求 DataNode 执行,因为 NameNode 设计上不直接调用 DataNode 其控制命令都是通过心跳回复来执行,所以心跳的默认间隔比较短。

除了 DataNode 的非正常死亡外,DataNode 还可以正常退休,可以通过管理端标记一个 DataNode 进入退休中(decommissioning)状态。处于退休中状态的 DataNode 不再服务于写请求(包括从 Client 写入或从其他 DataNode 复制),但它可以继续服务读请求。进入退休中状态的 DataNode 将被安排将其上存储的所有 block 复制到其他节点,完成这个过程后 NameNode 将其标记为已退休(decommissioned)状态,然后就可以安全下线了。

总结

本文重点描述了,DataNode 生命周期对 HDFS 集群整体的影响以及文件访问操作的流程。对于异常处理部分没有详细展开讲述,这个系列的后续文章还会进一步深入剖析。

参考

[1] Hadoop Documentation. HDFS Architecture.
[2] Robert Chansler, Hairong Kuang, Sanjay Radia, Konstantin Shvachko, and Suresh Srinivas. The Hadoop Distributed File System
[3] Tom White. Hadoop: The Definitive Guide. O’Reilly Media(2012-05), pp 94-96


下面是我自己开的一个微信公众号 [瞬息之间],除了写技术的文章、还有产品的、行业和人生的思考,希望能和更多走在这条路上同行者交流,有兴趣可关注一下,谢谢。

版权声明:本文为博主原创文章,未经博主允许不得转载。

HDFS DataNode 设计实现解析的更多相关文章

  1. 后端分布式系列:分布式存储-HDFS DataNode 设计实现解析

    前文分析了 NameNode,本文进一步解析 DataNode 的设计和实现要点. 文件存储 DataNode 正如其名是负责存储文件数据的节点.HDFS 中文件的存储方式是将文件按块(block)切 ...

  2. HDFS Client 设计实现解析

    前面对 HDFS NameNode 和 DataNode 的架构设计实现要点做了介绍,本文对 HDFS 最后一个主要构成组件 Client 做进一步解析. 流式读取 HDFS Client 为客户端应 ...

  3. HDFS NameNode 设计实现解析

    接前文 分布式存储-HDFS 架构解析,我们总体分析了 HDFS 架构的主要构成组件包括:NameNode.DataNode 和 Client.本文首先进一步解析 HDFS NameNode 的设计和 ...

  4. 后端分布式系列:分布式存储-HDFS Client 设计实现解析

    前面对 HDFS NameNode 和 DataNode 的架构设计实现要点做了介绍,本文对 HDFS 最后一个主要构成组件 Client 做进一步解析. 流式读取 HDFS Client 为客户端应 ...

  5. 后端分布式系列:分布式存储-HDFS NameNode 设计实现解析

    接前文 分布式存储-HDFS 架构解析,我们总体分析了 HDFS 架构的主要构成组件包括:NameNode.DataNode 和 Client.本文首先进一步解析 HDFS NameNode 的设计和 ...

  6. 2本Hadoop技术内幕电子书百度网盘下载:深入理解MapReduce架构设计与实现原理、深入解析Hadoop Common和HDFS架构设计与实现原理

    这是我收集的两本关于Hadoop的书,高清PDF版,在此和大家分享: 1.<Hadoop技术内幕:深入理解MapReduce架构设计与实现原理>董西成 著  机械工业出版社2013年5月出 ...

  7. Hadoop分布式文件系统(HDFS)设计

    Hadoop分布式文件系统是设计初衷是可靠的存储大数据集,并且使应用程序高带宽的流式处理存储的大数据集.在一个成千个server的大集群中,每个server不仅要管理存储的这些数据,而且可以执行应用程 ...

  8. 大数据技术 - 分布式文件系统 HDFS 的设计

    本章内容介绍下 Hadoop 自带的分布式文件系统,HDFS 即 Hadoop Distributed Filesystem.HDFS 能够存储超大文件,可以部署在廉价的服务器上,适合一次写入多次读取 ...

  9. HDFS核心设计

    一.HDFS核心设计 数据块(block) 数据块是HDFS上最基本的存储单位 HDFS块默认大小为128M         对块进行抽象会带来的好处 一个小文件的大小可以大于网络中任意一个磁盘的容量 ...

随机推荐

  1. url地址的图片路径

    url地址的图片路径: (./images/1.jpg) 中的./指根路径,有或没有都可以: (../images/1.jpg) 中的../指相对路径: (../../images/1.jpg) 中的 ...

  2. Android功能点

    1.获取屏幕尺寸.密度等信息. 1)最常用的方法: WindowManager windowManager = getWindowManager(); Display display = window ...

  3. 继承映射关系 TPH、TPT、TPC<EntityFramework6.0>

    每个类型一张表[TPT] 声明方式 public class Business { [Key] public int BusinessId { get; protected set; } public ...

  4. AOJ 0121: Seven Puzzle【BFS】

    From: AOJ 0121 思路:与前几题的bfs不同,这次的bfs没有明确的移动对象,看似任意一个数都可以当成对象移动.这时我们只需要抓住一个格子就行,比如我们把0作为移动对象,那么0在地图中漫游 ...

  5. Unity引擎下最快的Xml读取器:UnityRapidXml

    近期发现无论是系统的System.Xml还是Mono.Xml,其实都有这样或者那样的问题,所以决定自己搞一个快一点的xml parse.以前在C++里用过rapidxml,这个确实是神一般的存在,速度 ...

  6. 基于Docker快速搭建多节点Hadoop集群--已验证

    Docker最核心的特性之一,就是能够将任何应用包括Hadoop打包到Docker镜像中.这篇教程介绍了利用Docker在单机上快速搭建多节点 Hadoop集群的详细步骤.作者在发现目前的Hadoop ...

  7. centos 6.5 yum安装 mysql 5.6

    1. 查看系统里面有没有mysql 的repo   yum repolist all | grep mysql 2. 如果没有发现,则需要配置repo 注意,如果要使用5.7 或者其他任何版本,只能有 ...

  8. 6种方法实现asp.net返回上一页

    其实要实现返回上一页的功能,主要还是要用到JavaScript. 一: 在ASP.net的aspx里面的源代码中 <input type="button onclick="J ...

  9. Angular内置指令(二)

    目录: $rootScope,ng-app,.run(),ng-include,ng-repeat,ng-if,ng-switch,ng-init ng-show/ng-hide,ng-model,n ...

  10. 动作手游实时PVP帧同步方案(客户端)

    1.概述 1.1.基于UDP的帧同步方案 在技术选型方面,之所以选择帧同步方案,在Kevin的一篇介绍PVP帧同步后台实现的文章中已经做了详细叙述,这里简单摘要如下: 高一致性.如果每一帧的输入都同步 ...