2025年4月11日 星期五 乙巳(蛇)年 正月十二 夜 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 服务器 > 网络服务

HDFS 的概念名词解释

时间:12-14来源:作者:点击数:4

数据块

每个磁盘都有默认的数据块大小,这是磁盘进行数据读/写的最小单位。构建于单个磁盘之上的文件系统通过磁盘块来管理该文件系统中的块,该文件系统块的大小可以是磁盘块的整数倍。文件系统块一般为几千字节,而磁盘块一般为 512 字节。但这些对于需要读/写文件的文件系统用户来说是透明的。

HDFS 同样也有块(block)的概念,但是大得多,默认为 128MB。与单一磁盘上的文件系统相似,HDFS上的文件也被划分为块大小的多个分块,作为独立的存储单元。但与面向单一磁盘的文件系统不同的是,HDFS中小于一个块大小的文件不会占据整个块的空间,例如当一个1MB的文件存储在一个128MB的块中时,文件只使用1MB的磁盘空间,而不是128MB。

HDFS 中的块为什么这么大?HDFS的块比磁盘的块大,其目的是为了最小化寻址开销。如果块足够大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。因为,传输一个由多个块组成的大文件的时间取决于磁盘传输速率。但是块大小这个参数也不会设置得过大,MapReduce中map任务通常一次只处理一个块中的数据,因此如果任务数太少(少于集群中的节点数量),作业的运行速度就会比较慢。

对分布式文件系统中的块进行抽象会带来很多好处。

  • 第一好处是一个文件的大小可以大于网络中任意一个磁盘的容量。
  • 第二个好处是使用抽象块而非整个文件作为存储单元,大大简化了存储子系统的设计。
  • 第三个好处是块还非常适合用于数据备份进而提供数据容错能力和提高可用性。   HDFS将每个块复制到少数几个物理上相互独立的机器上(默认为3个),可以确保在块、磁盘或机器发生故障后数据不会丢失。如果发现一个块不可用,系统会从其他地方读取另一个复本,而这个过程对用户是透明的。一个因损坏或机器故障而丢失的块可以从其他候选地点复制到另一台可以正常运行的机器上,以保证复本的数量回到正常水平。同样,有些应用程序可能选择为一些常用的文件块设置更高的复本数量进而分散集群中的读取负载。

在 HDFS 中显示块信息:

  • hdfs fsck / -files -blocks

可以执行命令修改HDFS的数据块大小以及复本数量:

  • vim $HADOOP_HOME/etc/hadoop/hdfs-site.xml

NameNode(管理节点)

NameNode 目录结构

运行中的 NameNode 有如下所示的目录结构:

VERSION文件 :是一个 Java 属性文件,其中包含正在运行的HDFS的版本信息。该文件一般包含以下内容:

  • #Mon Sep 29 09:54:36 BST 2014 namespaceID=1342387246 clusterID=CID-01b5c398-959c-4ea8-aae6-1e0d9bd8b142 cTime=0 storageType=NAME_NODE blockpoolID=BP-526805057-127.0.0.1-1411980876842 layoutVersion=-57
  • layoutVersion :这是一个负整数,描述HDFS持久性数据结构(也称布局)的版本,但是该版本号与Hadoop发布包的版本号无关。只要布局变更,版本号将会递减,此时HDFS也要升级。否则,新版本的NameNode(或DataNode)就无法正常工作。
  • namespaceID :文件系统命名空间的唯一标识符,是在NameNode首次格式化时创建的。
  • clusterID : 在HDFS集群上作为一个整体赋予的唯一标识符,这对于联邦HDFS非常重要。
  • blockpoolID :数据块池的唯一标识符,数据块池中包含了由一个NameNode管理的命名空间中的所有文件。
  • cTime :标记了NameNode存储系统的创建时间。刚格式化的存储系统,值为0,但升级后,该值会更新到新的时间戳。
  • storageType :该存储目录包含的时NameNode的数据结构。

编辑日志(edits log)

文件系统客户端执行写操作时,这些事务首先被记录到 edits 中。NameNode 在内存中维护文件系统的元数据;当被修改时,相关元数据信息也同步更新。内存中的元数据可支持客户端的读请求。我们可以使用 OEV 查看 edits 文件:

选项解析:

  • -i,--inputFile :要处理的编辑文件
  • -o,--outputFile :输出文件的名称;如果指定的文件存在,它将被覆盖
  • -p,--processor :选择要应用于编辑文件的处理器类型 (XML|FileDistribution|Web|Delimited)

oev 中的 e 指定了镜像文件

命令如下:

  • <?xml version="1.0" encoding="UTF-8"?>
  • <EDITS>
  • <EDITS_VERSION>-63</EDITS_VERSION>
  • <RECORD>
  • <!-- 开始日志段-->
  • <OPCODE>OP_START_LOG_SEGMENT</OPCODE>
  • <DATA>
  • <!-- 事务id-->
  • <TXID>1</TXID>
  • </DATA>
  • </RECORD>
  • <RECORD>
  • <!-- 结束日志段-->
  • <OPCODE>OP_END_LOG_SEGMENT</OPCODE>
  • <DATA>
  • <TXID>2</TXID>
  • </DATA>
  • </RECORD>
  • </EDITS>

命名空间镜像文件(fsimage)

文件系统元数据的持久检查点,每个fsimage文件包含文件系统中的所有目录和文件inode的序列化信息(从Hadoop-2.4.0起,FSImage开始采用Google Protobuf编码格式),每个inodes表征一个文件或目录的元数据信息以及文件的副本数、修改和访问时间等信息。数据块存储在DataNode中,但fsimage文件并不描述DataNode。我们可以使用OIV查看fsimage文件 :

选项解析:

  • -i,--inputFile :要处理的镜像文件
  • -o,--outputFile :输出文件的名称;如果指定的文件存在,它将被覆盖
  • -p,--processor :选择要应用于镜像文件的处理器类型 (XML|FileDistribution|Web|Delimited)

oiv中的i指定了image文件

命令如下:

  • # hdfs oiv -p XML -i fsimage_0000000000000014026 -o fsimage.xml
  • <?xml version="1.0"?>
  • <fsimage>
  • <NameSection>
  • <!-- 默认的开启编号-->
  • <genstampV1>1000</genstampV1>
  • <!-- 最后一个块的编号-->
  • <genstampV2>2215</genstampV2>
  • <genstampV1Limit>0</genstampV1Limit>
  • <!-- 最后一个分配的块的块id-->
  • <lastAllocatedBlockId>1073743027</lastAllocatedBlockId>
  • <!-- 开始的事务id号-->
  • <txid>14026</txid>
  • </NameSection>
  • <INodeSection>
  • <!-- 最后一个文件(目录)的inode号-->
  • <lastInodeId>18763</lastInodeId>
  • <!--当前文件系统中只有根目录,以下为根目录的相关信息-->
  • <inode>
  • <id>16385</id>
  • <type>DIRECTORY</type>
  • <name></name>
  • <mtime>1560256204322</mtime>
  • <permission>root:root:rwxrwxrwx</permission>
  • <nsquota>9223372036854775807</nsquota>
  • <dsquota>-1</dsquota>
  • </inode>
  • <inode>
  • <id>16417</id>
  • <type>DIRECTORY</type>
  • <name>myInfo</name>
  • <mtime>1552974220469</mtime>
  • <permission>root:root:rwxrwxrwx</permission>
  • <nsquota>-1</nsquota>
  • <dsquota>-1</dsquota>
  • </inode>
  • <inode>
  • <id>16418</id>
  • <type>FILE</type>
  • <name>myInfo.txt</name>
  • <replication>1</replication>
  • <mtime>1552830434241</mtime>
  • <atime>1552974031814</atime>
  • <perferredBlockSize>134217728</perferredBlockSize>
  • <permission>root:root:rwxrwxrwx</permission>
  • <blocks>
  • <block>
  • <id>1073741855</id>
  • <genstamp>1031</genstamp>
  • <numBytes>147</numBytes>
  • </block>
  • </blocks>
  • </inode>
  • ......... // inode文件太多,省略
  • </INodeSection>
  • <INodeReferenceSection></INodeReferenceSection>
  • <SnapshotSection>
  • <snapshotCounter>0</snapshotCounter>
  • </SnapshotSection>
  • <INodeDirectorySection>
  • <directory>
  • <parent>16385</parent>
  • <inode>18543</inode>
  • <inode>16474</inode>
  • <inode>16419</inode>
  • <inode>16417</inode>
  • <inode>16427</inode>
  • <inode>17544</inode>
  • <inode>17561</inode>
  • </directory>
  • <directory>
  • <parent>16417</parent>
  • <inode>16420</inode>
  • </directory>
  • <directory>
  • <parent>16419</parent>
  • <inode>17399</inode>
  • <inode>17258</inode>
  • <inode>16418</inode>
  • <inode>17294</inode>
  • </directory>
  • ...... // 省略其他<directory>标签
  • </INodeDirectorySection>
  • <FileUnderConstructionSection>
  • </FileUnderConstructionSection>
  • <SecretManagerSection>
  • <currentId>0</currentId>
  • <tokenSequenceNumber>0</tokenSequenceNumber>
  • </SecretManagerSection>
  • <CacheManagerSection>
  • <nextDirectiveId>1</nextDirectiveId>
  • </CacheManagerSection>
  • </fsimage>

seen_txid 文件

该文件对于NameNode非常重要,它是存放 transactionId 的文件,format 之后是0,它代表的是 NameNode 里面的 edits_ 文件的尾数,NameNode 重启的时候,会按照seen_txid 的数字,循序从头跑 edits_00001~ 到 seen_txid 的数字。当 hdfs 发生异常重启的时候,一定要比对 seen_txid 内的数字是不是你edits最后的尾数,不然会发生建置 NameNode 时元数据信息缺失,导致误删 DataNode 上多余 block。

in_use.lock 文件

是一个锁文件,NameNode 使用该文件为存储目录加锁。可以避免其他 NameNode 实例同时使用(可能会破坏)同一个存储目录的情况。

NameNode 的工作原理

NameNode管理文件系统的命名空间。它维护着文件系统树及整棵树内所有的文件和目录。这些信息以两个文件形式永久保存在本地磁盘上:命名空间镜像文件(fsimage)和编辑日志文件(edits log)。它也记录着每个文件中各个块所在的数据节点信息,但它并不永久保存块的位置信息,因为这些信息会在系统启动时根据DataNode节点信息重建,块信息存储在内存中。

可以看得出来NameNode的正常运行是非常重要的,如果运行的NameNode服务的机器毁坏,文件系统上所有的文件将会丢失,因为我们不知道如何根据DataNode的块重建文件。因此,Hadoop为此提供两种实现NameNode容错机制:

  • 备份组成文件系统元数据持久状态的文件。一般是将持久状态写入本地磁盘的同时,写入一个远程挂载的网络文件系统(NFS),HDFS与NFS安装配置可以参考该文章
  • 运行一个辅助NameNode。但它不能作为主NameNode,这个辅助NameNode的重要作用是定期合并编辑日志(edits)与命名空间镜像文件(fsimage),以防止编辑日志过大。一般来说辅助NameNode在一个单独的机器上运行,因为它需要占用大量CPU时间并且一样多的内存来执行合并操作。设计成这样的好处在于,一旦主NameNode发生故障,辅助NameNode立刻就可以接替它的工作,但是由于保存数据是定时进行的,所以难免会有损失的数据,此时就可以把保存在其他地方(NFS)的数据复制到辅助NameNode,然后辅助NameNode作为新的主NameNode运行(注意,也可以运行热备份NameNode代替运行辅助NameNode)。

SecondaryNamenode(辅助 NameNode)

Hadoop SecondaryNameNode并不是Hadoop的第二个namanode,它不提供NameNode服务,而仅仅是NameNode的一个工具,这个工具帮助NameNode管理元数据信息。可能是由于SecondaryNameNode这个名字给人带来的混淆,Hadoop后面的版本(1.0.4)建议不要使用,而使用CheckPoint Node。但在这小节中,小编还是使用SecondaryNamenode。

运行中的SecondaryNamenode(辅助NameNode)的目录结构与主NameNode的目录结构几乎一样,但有部分时间不相同,它为主NameNode内存中的文件系统元数据创建检查点(后面解释)尚未成功时两者不相同。运行中的SecondaryNamenode有如下所示的目录结构:

当 NameNode 启动时,需要合并 fsimage 和 edits 文件,按照edits文件内容将fsimage进行事务处理,从而得到HDFS的最新状态。实际应用中,NameNode很少重新启动。假如存在一个庞大的集群,且关于HDFS的操作相当频繁与复杂,那么就会产生一个非常大的edits文件用于记录操作,这就带来了以下问题:

  • edits文件过大会带来管理问题;
  • 一旦需要重启HDFS时,就需要花费很长一段时间对edits和fsimage进行合并,这就导致HDFS长时间内无法启动;
  • 如果NameNode挂掉了,会丢失部分操作记录(这部分记录存储在内存中,还未写入edits);

此时,Secondary NameNode就要发挥它的作用了:合并edits文件,防止edits文件持续增长。该辅助NameNode会为主NameNode内存中的文件系统元数据创建检查点(fsimage文件),创建检查点前HDFS会自动进入安全模式(safe mode),当NameNode处在安全模式,管理员也可手动调用hdfs dfsadmin -saveNameSpace命令来创建检查点。创建检查点的步骤如下所示(如图中也简单地描述)。

  • 辅助NameNode请求主NameNode停止使用正在进行中的edits文件,这样新的编辑操作记录到一个新文件中。主NameNode还会更新所有存储目录中的seen_txid文件。
  • 辅助NameNode从主NameNode获取最近的fsimage和edits文件(采用HTTP GET)。
  • 辅助NameNode将fsimage文件载入内存,逐一执行edits文件中的事务,创建新的合并后的fsimage文件。
  • 辅助NameNode将新的fsimage文件发送回主NameNode(使用HTTP PUT),主NameNode将其保存为临时的.ckpt文件。
  • 主NameNode重新命名临时的fsimage文件,便于日后使用。

创建检查点的步骤图

最终,主NameNode拥有最新的fsimage文件和一个更小的正在进行中的edits文件(edits文件可能非空,因为在创建检查点过程中主NameNode还可能收到一些编辑请求)。这个过程清晰解释了辅助NameNode和主NameNode拥有相近内存需求的原因(因为辅助NameNode也把fsimage文件载入内存)。因此,在大型集群中,辅助NameNode需要运行在一台专用机器上。

在hdfs-site.xml中可以配置与检查点触发点有关的属性:

  • <property>
  • <name>dfs.namenode.checkpoint.period</name>
  • <value>3600</value>
  • <description>两个定期检查点之间的秒数
  • </description>
  • </property>
  • <property>
  • <name>dfs.namenode.checkpoint.txns</name>
  • <value>1000000</value>
  • <description>secondarynamenode或检查点节点将创建检查点
  • 每个“dfs.namenode.checkpoint.txns”事务的名称空间
  • 判断“dfs.namenode.checkpoint.period”是否已过期
  • </description>
  • </property>
  • <property>
  • <name>dfs.namenode.checkpoint.check.period</name>
  • <value>60</value>
  • <description>SecondaryNameNode和CheckpointNode将轮询NameNode
  • 每隔'dfs.namenode.checkpoint.check.period'秒查询一次
  • 未存入检查点事务
  • </description>
  • </property>

默认情况下,辅助NameNode每隔一个小时创建检查点;此外,如果从上一个检查点开始编辑日志的大小已经达到100万个事务时,即使不到一小时,也会创建检查点,检查频率为每分钟一次。

这个过程namesecondary目录发生了更新;secondaryNameNode的检查点目录的布局与NameNode的是相同的,这种设计的好处是NameNode发生故障时,可以从secondaryNameNode恢复数据;有两种实现方法:一是将相关存储目录复制到新的NameNode中;二是使用-importCheckpoint选项启动NameNode守护进程,从而将secondaryNameNode用作新的NameNode

与第一次开启hdfs过程不同的是此次有30多秒的安全模式:

在安全模式中在等待块报告,这也关系到DataNode的运行过程。

DataNode(工作节点)

DataNode是文件系统的工作节点。它们根据需要存储并检索数据块(受客户端或NameNode调度),并且定期向NameNode发送它们所存储的块的列表。

DataNode 目录结构

和NameNode不同的是,DataNode的存储目录是初始阶段自动创建的,不需要额外格式化。DataNode的关键文件和目录如下所示:

分析:从上图可以看出,dataNode的文件结构主要由blk_前缀文件、BP-random integer-NameNode-IP address-creation time和VERSION构成。

  • BP-random integer-NameNode-IP address-creation time :
    • BP代表BlockPool的,就是Namenode的VERSION中的集群唯一blockpoolID
    • 从上图可以看出我的DataNode是一个BP,也就是说只有一个NameNode管理全部的文件系统命名空间,如果有两个以上的BP,该HDFS是Federation HDFS,所以该目录下有两个BP开头的目录,IP部分和时间戳代表创建该BP的NameNode的IP地址和创建时间戳。
  • finalized/rbw :
    • 这两个目录都是用于实际存储HDFS BLOCK的数据,里面包含许多block_xx文件以及相应的.meta后缀的元数据文件,.meta文件包含了checksum信息。
    • rbw是“replica being written”的意思,该目录用于存储用户当前正在写入的数据。
  • blk_前缀文件 :
    • HDFS中的文件块,存储的是原始文件内容。
    • 块的元数据信息,每一个块有一个相关联的.meta文件,一个文件块由存储的原始文件字节组成。
    • .meta文件包括头部(含版本和类型信息)和该块各区段的一系列的校验和。
    • 每个块属于一个数据块池(在本篇文章中,只有一个数据块池),每个数据块池都有自己的存储目录,目录根据数据块池ID形成(和NameNode的VERSION文件中的数据块池ID相同)

注 :当目录中数据块的数量增加到一定规模时,DataNode会创建一个子目录来存放新的数据块及其元数据信息。如果当前目录已经存储了64个(通过dfs.datanode.numblocks属性设置)数据块时,就创建一个子目录。终极目标是设计一棵高扇出的目录树,即使文件系统中的块数量非常多,目录树的层数也不多。通过这种方式,DataNode可以有效管理各个目录中的文件,避免大多数操作系统遇到的管理难题,即很多(成千上万个)文件放在同一个目录之中。

  • VERSION :
    • #Mon Sep 29 09:54:36 BST 2014storageID=DS-c478e76c-fe1b-44c8-ba45-4e4d6d266547 clusterID=CID-01b5c398-959c-4ea8-aae6-1e0d9bd8b142 cTime=0 datanodeUuid=75ffabf0-813c-4798-9a91-e7b1a26ee6f1 storageType=DATA_NODE layoutVersion=-57
    • storageID :相对于 DataNode 来说是唯一的,用于在NameNode处标识DataNode
    • clusterID :是系统生成或手动指定的集群ID
    • cTime :表示NameNode存储时间的创建时间
    • datanodeUuid :表示DataNode的ID号
    • storageType :将这个目录标志位DataNode数据存储目录。
    • layoutVersion :是一个负整数,保存了HDFS的持续化在硬盘上的数据结构的格式版本号。
  • in_use.lock:是一个锁文件,NameNode使用该文件为存储目录加锁。可以避免其他NameNode实例同时使用(可能会破坏)同一个存储目录的情况。 

块缓存

通常DataNode从磁盘中读取块,但对于访问频繁的文件,其对应的块可能被显式地缓存在DataNode内存中,以堆外块缓存(off-heap block cache)的形式存在。默认情况下,一个块仅缓存在一个DataNode的内存中,当然可以对每个文件配置DataNode的数量。作业调度器(用于MapReduce、Spark和其他框架的)通过在缓存块的DataNode上运行任务,可以利用块缓存的优势提高读操作的性能。

用户或应用通过在缓存池(cache pool)中增加一个 cache directive来告诉NameNode需要缓存哪些文件及存多久。缓存池是一个用于管理缓存权限和资源使用的管理性分组。

本小节只简单描述,有关HDFS的缓存管理请查阅官方文档或者其他等相关资料。

联邦 HDFS

NameNode在内存中保存文件系统中每个文件和每个数据块的引用关系,这意味着对于一个拥有大量文件的超大集群来说,内存将成为限制系统横向扩展的瓶颈。在2.X发行版本系列中引入的联邦HDFS允许系统通过添加NameNode实现扩展,其中每个NameNode管理文件系统命名空间中的一部分。

在联邦环境中,每个NameNode维护一个命名空间卷(namespace volume),由命名空间的元数据和一个数据块池(block pool)组成,数据块池包含该命名空间下文件的所有数据块。命名空间卷之间是相互独立的,两两之间并不相互通信,甚至其中一个NameNode的失效也不会影响由其他NameNode维护的命名空间的可用性。

集群中的DataNode还需要注册到每个NameNode,并且存储着来自多个数据块池中的数据块。

联邦HDFS的架构图如下图所示:

联邦HDFS更详细的请查阅官方文档

HDFS 读数据

  • HDFS客户端通过调用FileSystem对象的open()方法来打开希望读取的文件,对于HDFS来说,这个对象是DistributedFileSystem的一个实例。
  • DistributedFileSystem通过使用远程过程调用(RPC)来调用NameNode,以确定文件起始块的位置。对于每个块,NameNode返回具有该块副本的DataNode地址。此外,这些DataNode根据它们与客户端的距离来排序(根据集群的网络拓扑),如果该客户端本身就是一个DataNode,便从本地读取数据。接着DistributedFileSystem类返回一个FSDataInputStream对象(一个支持文件定位的输入流)给客户端以便读取数据。FSDataInputStream类转而封装DFSInputStream对象,该对象管理着DataNode和NameNode的 I/O。
  • 客户端对这个输入流调用read()方法,存储着文件起始几个块的DataNode地址的DFSInputStream随即连接距离最近的文件中第一个块所在的DataNode。
  • 通过对数据流反复调用read()方法,可以将数据从DataNode传输到HDFS 客户端。
  • 读取数据到块的末端时,DFSInputStream关闭与该DataNode的连接,然后寻找下一个块的最佳DataNode。在HDFS客户端所看来它一直在读取一个连续的流,这些对于客户端来说是透明的。
  • 客户端从流中读取数据时,块是按照打开DFSInputStream与DataNode新建连接的顺序读取的,它也会根据需要询问NameNode来检索下一批数据块的DataNode的位置,一旦客户端读取完毕,就会调用close()方法。但在读取时,DFSInputStream与DataNode通信时遇到错误,会尝试从这个块的另外一个最邻近DataNode读取数据,它也会记住那个故障DataNode,以保证以后不会反复读取该节点上后续的块。DFSInputStream也会通过校验和确认从DataNode发来的数据是否完整。如果发现有损坏的块,DFSInputStream会试图从其他DataNode读取其复本,也会将被损坏的块通知给NameNode。

HDFS读数据过程这一设计的一个重点是:客户端可以直接连接到DataNode检索数据,且NameNode告知客户端每个块所在的最佳DataNode,由于数据流分散在集群中的所有DataNode,所以这种设计能使HDFS扩展到大量的并发客户端。同时,NameNode只需要响应块位置的请求(这些信息存储在内存中,因而非常高效),无需响应数据请求,否则随着客户端数量的增长,NameNode会很快称为瓶颈。

这里 HdfsDataInputStream 是 FSDataInputStream 的子类,这里是通过子类创建父类对象。

HDFS 写数据

  • 客户端通过对 DistributedFileSystem 对象调用 create() 来新建对象。
  • DistributedFileSystem 对 NameNode 创建一个 RPC 调用,在文件系统的命名空间中新建一个文件,此时该文件中还没有响应的数据块。NameNode执行各种不同的检查以确保这个文件不存在以及客户端有新建该文件的权限。
    • 如果这些检查均通过,NameNode就会为创建新文件记录一条记录;DistributedFileStream向客户端返回一个FSDataOutputStream对象,由此客户端可以开始写入数据。就像读取事件一样,文件系统数据输出流控制一个DFSOutputStream,负责处理datanode和namenode之间的通信。
    • 否则,文件创建失败并向客户端抛出一个IOException异常。
  • 在客户端写入数据时,DFSOutputStream将它分成一个个的数据包,并写入内部队列,称为“数据队列”(data queue)。DataStreamer处理数据队列,它的责任是挑选出适合存储数据复本的一组DataNode,并据此来要求NameNode分配新的数据块。这一组DataNode构成一个管线——我们假设复本数为3,所以管线中有3个节点。
  • DataStream将数据包流式传输到管线中第1个DataNode,该DataNode存储数据包并将它发送到管线中的第2个DataNode。同样,第2个DataNode存储该数据包并且发送给管线中的第3个(也是最后一个)DataNode。
  • DFSOutputStream也维护着一个内部数据包队列来等待DataNode的收到确认回执,称为“确认队列”(ack queue)。收到管道中所有DataNode确认信息后,该数据包才会从确认队列删除。如果有DataNode在数据写入期间发生故障,则执行以下操作(对写入数据的客户端是透明的)。
    • 首先关闭管线,确认把队列中的所有数据包都添加回数据队列的最前端,以确保故障节点下游的DataNode不会漏掉任何一个数据包。
    • 为存储在另一正常DataNode的当前数据块指定一个新的标识,并将该标识传送给NameNode,以便故障DataNode在恢复后可以删除存储的部分数据块。
    • 从管线中删除故障DataNode,基于两个正常DataNode构建一条新管线。
    • 余下的数据块写入管线中正常的DataNode。
    • NameNode注意到块复本量不足时,会在另一个节点上创建一个新的复本。后续的数据块继续正常接受处理。
  • 客户端完成数据的写入后,对数据流调用close()。
  • 在联系到NameNode告知其文件写入完成之前,此操作会将剩余的所有数据包写入DataNode管线并等待确认。NameNode已经直到文件由哪些块组成(因为Datastreamer请求分配数据块),所以它在返回成功前只需要等待数据块进行最小量的复制。
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐