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

前文分析了 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



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

时间: 2024-11-29 06:21:11

后端分布式系列:分布式存储-HDFS DataNode 设计实现解析的相关文章

后端分布式系列:分布式存储-HDFS 与 GFS 的设计差异

「后端分布式系列」前面关于 HDFS 的一些文章介绍了它的整体架构和一些关键部件的设计实现要点. 我们知道 HDFS 最早是根据 GFS(Google File System)的论文概念模型来设计实现的. 然后呢,我就去把 GFS 的原始论文找出来仔细看了遍,GFS 的整体架构图如下: HDFS 参照了它所以大部分架构设计概念是类似的,比如 HDFS NameNode 相当于 GFS Master,HDFS DataNode 相当于 GFS chunkserver. 但还有些细节不同的地方,所以

后端分布式系列:分布式存储-HDFS 架构解析

本文以 Hadoop 提供的分布式文件系统(HDFS)为例来进一步展开解析分布式存储服务架构设计的要点. 架构目标 任何一种软件框架或服务都是为了解决特定问题而产生的.还记得我们在 <分布式存储 - 概述>一文中描述的几个关注方面么?分布式文件系统属于分布式存储中的一种面向文件的数据模型,它需要解决单机文件系统面临的容量扩展和容错问题. 所以 HDFS 的架构设计目标就呼之欲出了: 面向超大文件或大量的文件数据集 自动检测局部的硬件错误并快速恢复 基于此目标,考虑应用场景出于简化设计和实现的目

后端分布式系列:分布式存储-概述

分布式存储是相对于单机存储而言,之所以要分布自然是因为互联网时代信息数据大爆炸,单机已经难以满足大型应用的数据存储需求. 存储系统的关注点 关于存储系统,一般我们关注下面几个方面: 数据分布与负载均衡 数据存储的可靠性与一致性 数据访问性能 系统容错能力 系统扩展能力 在单机存储系统中有一种独立磁盘冗余阵列(RAID,redundant array of independent disks)技术, 是把相同的数据存储在多个硬盘不同地方的方法.通过把数据放在多个硬盘上,输入输出操作能以平衡的方式交

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

Hadoop分布式文件系统是设计初衷是可靠的存储大数据集,并且使应用程序高带宽的流式处理存储的大数据集.在一个成千个server的大集群中,每个server不仅要管理存储的这些数据,而且可以执行应用程序任务.通过分布式存储和在各个server间交叉运算,集群和存储可以按需动态经济增长.以下的设计原则和经验是根据yahoo通过HDFS管理的40PB得来的. 1. HDFS简介 HDFS是一个分布式文件系统,并且为MapReduce分布式算法提供了一分析和传输大数据的框架.HDFS使用java编写,

后端分布式系列:分布式存储-MySQL 数据库双向同步复制

MySQL 复制问题的最后一篇,关于双向同步复制架构设计的一些设计要点与制约. 问题和制约 数据库的双主双写并双向同步场景,主要考虑数据完整性.一致性和避免冲突.对于同一个库,同一张表,同一个记录中的同一字段的两地变更,会引发数据一致性判断冲突,尽可能通过业务场景设计规避.双主双写并同步复制可能引发主键冲突,需避免使用数据库自增类主键方案.另外,双向同步潜在可能引发循环同步的问题,需要做回环控制. 如上图所示,复制程序写入时也会产生 binlog,如何识别由复制程序产生的 binlog 并将其过

Hadoop系列之hdfs(分布式文件系统)安装配置

Hadoop系列之hdfs(分布式文件系统)安装配置环境介绍:     ip                        节点192.168.3.10      hdfs-master192.168.3.11      hdfs-slave1192.168.3.12      hdfs-slave21.在所有机器添加hosts192.168.3.10      hdfs-master192.168.3.11      hdfs-slave1192.168.3.12      hdfs-slav

【HDFS】Hadoop分布式文件系统:架构和设计

引言 前提和设计目标 硬件错误 流式数据访问 大规模数据集 简单的一致性模型 "移动计算比移动数据更划算" 异构软硬件平台间的可移植性 Namenode 和 Datanode 文件系统的名字空间 (namespace) 数据复制 副本存放: 最最开始的一步 副本选择 安全模式 文件系统元数据的持久化 通讯协议 健壮性 磁盘数据错误,心跳检测和重新复制 集群均衡 数据完整性 元数据磁盘错误 快照 数据组织 数据块 Staging 流水线复制 可访问性 DFSShell DFSAdmin

Hadoop学习笔记_7_分布式文件系统HDFS --DataNode体系结构

分布式文件系统HDFS --DataNode体系结构 1.概述 DataNode作用:提供真实文件数据的存储服务. 文件块(block):最基本的存储单位[沿用的Linux操作系统地概念].对于文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block. 与Linux操作系统不同的是,一旦上传了一个小于Block大小的文件,则该文件会占用实际文件大小的空间. 2.进入hdfs-default.xml <prope

Hadoop分布式文件系统:架构和设计

引言 前提和设计目标 硬件错误 流式数据访问 大规模数据集 简单的一致性模型 “移动计算比移动数据更划算” 异构软硬件平台间的可移植性 Namenode 和 Datanode 文件系统的名字空间 (namespace) 数据复制 副本存放: 最最开始的一步 副本选择 安全模式 文件系统元数据的持久化 通讯协议 健壮性 磁盘数据错误,心跳检测和重新复制 集群均衡 数据完整性 元数据磁盘错误 快照 数据组织 数据块 Staging 流水线复制 可访问性 DFSShell DFSAdmin 浏览器接口