Hadoop学习--第六篇:HDFS 原理

前言

本篇博文首先对HDFS的数据读写过程进行分析,之后对元数据管理以及NameNode、SecondaryNamenode的工作机制进行深入分析。


一. HDFS的读取过程

1. 概述
客户端将要读取的文件路径发送给namenode,namenode获取文件的元信息(主要是block的存放位置信息)返回给客户端,客户端根据返回的信息找到相应datanode逐个获取文件的block并在客户端本地进行数据追加合并从而获得整个文件。

2. HDFS 的读取文件步骤
在这里插入图片描述
HDFS的文件读取原理,详细解析如下:

  • 首先通过调用FileSystem对象的open方法,实际上获取的是一个DistributedFileSystem的实例。
  • DistributedFileSystem 通过 RPC(远程过程调用) 来调用 namenode,以确定文件的开头部分的 block 的 locations。同一 block,按照重复数会返回多个 locations, 这些 locations 按照 Hadoop 拓扑结构排序,距离客户端近的排在前面。 如果该 client 本身就是一个 datanode,便从本地 datanode 中读取。
  • DistributedFileSystem 返回一个 FSDataInputStream 对象,该对象会被封装成 DFSInputStream 对象。客户端调用 read 方 法,DFSInputStream 就会找出离客户端最近的 datanode 并连接 。
  • 通过在数据流中反复调用 read(),数据会从 datanode 返回 client。到达 block 的末端时,DFSInputStream 会关闭与 datanode 间的联系,接着读取下一个block块。
  • 如果第一批block都读完了,DFSInputStream就会去namenode拿下一批blocks的location,然后继续读,如果所有的 block 都读完,这时就会关闭掉所有的流。
  • 在读取的时候,如果 client 与 datanode 通信时遇到一个错误,或者发现损坏的块。它也会记住那个故障节点的datanode报告给namenode,然后尝试对这个 block 来说下一个最近的 block读取 。

注意:
这里HdfsDataInputStream是FSDataInputStream的子类,这里是通过子类创建父类对象。
在这里插入图片描述

比较通俗的讲就是:

  1. 客户端通过Distributed FileSystem向namenode请求下载文件,namenode通过查询元数据,找到文件块所在的datanode地址。
  2. 挑选一台datanode (就近原则,然后随机) 服务器,请求读取数据。
  3. datanode开始传输数据给客户端(从磁盘里面读取数据输入流,以packet为单位来做校验)。
  4. 客户端以packet为单位接收,先在本地缓存,然后写入目标文件。

二. HDFS的写入过程

1. 概述
客户端要向HDFS写数据,首先要跟namenode通信以确认可以写文件并获得接收文件block的datanode,然后客户端按顺序将文件逐个block传递给相应datanode,并由接收到block的datanode负责向其他datanode复制block的副本。

2. HDFS的写入文件步骤
在这里插入图片描述

HDFS的文件写入原理详细步骤解析:

  • 客户端通过调用 DistributedFileSystem 的create方法,创建一个新的文件。
  • DistributedFileSystem 通过 RPC(远程过程调用)调用 NameNode,在文件系统的命名空间创一个新的文件,没有块与之相联系。创建前,NameNode 会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过,NameNode 就会记录下新文件,否则,文件创建失败并向client抛出一个IOException异常。
  • 前两步结束后会返回 FSDataOutputStream 的对象,和读文件的时候相似,FSDataOutputStream 被封装成 DFSOutputStream ,DFSOutputStream 可以协调 NameNode和 DataNode。
  • 客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小packet,然后排成队列 data queue。
  • DataStreamer 会去处理接受 data queue,它先问询 NameNode 这个新的 block 最适合存储的在哪几个DataNode里,比如重复数是3,那么就找到3个最适合的 DataNode,把它们排成一个 pipeline。DataStreamer 把 packet 按队列输出到管道的第一个 DataNode 中,第一个 DataNode又把 packet 输出到第二个 DataNode 中,以此类推。
  • DFSOutputStream 还有一个队列叫 ack queue,也是由 packet 组成,等待DataNode的收到响应,当pipeline中的所有DataNode都表示已经收到的时候,这时akc queue才会把对应的packet包移除掉。
  • 如果在有数据写入期间,datanode发生故障,则会执行下面的操作,当然这对写入数据的client而言是透明的。
    • 首先管线被关闭,ack queue 中的数据块放入data queue的前面,为了防止防止丢包。
    • 当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,以便故障节点datanode在恢复后可以删除存储的部分数据块。
    • 从管线中删除故障数据节点并且把余下的数据块写入管线中的两个正常的datanode。namenode注意到块复本量不足时,会在另一个节点上创建一个新的复本。
  • 客户端完成写数据后,调用close方法关闭写入流。

比较通俗的讲就是:

  1. 客户端通过Distributed FileSystem模块向namenode请求上传文件,namenode检查目标文件是否已存在,父目录是否存在;
  2. namenode返回是否可以上传;
  3. 客户端请求第一个 block上传到哪几个datanode服务器上。
  4. namenode返回3个datanode节点,分别为dn1、dn2、dn3。
  5. 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
  6. dn1、dn2、dn3逐级应答客户端。
  7. 客户端开始往dn1上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位,dn1收到一个packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
  8. 当一个block传输完成之后,客户端再次请求namenode上传第二个block的服务器。(重复执行3-7步)。

3. HDFS副本存放
HDFS采用一种称为机架感知(rack-aware)的策略来改进数据的可靠性、可用性和网络带宽的利用率。目前在HDFS中现有的副本存放策略有两种:

  • 在 Hadoop 1.X的版本 和 Hadoop 2.8.2 的版本之后,都采用的下述方式,详见官方文档
    在这里插入图片描述
    例如:Hadoop 2.9.2版本描述如下:

    For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on the local machine if the writer is on a datanode, otherwise on a random datanode, another replica on a node in a different (remote) rack, and the last on a different node in the same remote rack.

    简要概况起来3点:

    • 1st replica. 如果写请求方所在机器是其中一个datanode,则直接存放在本地,否则随机在集群中选择一个datanode。
    • 2nd replica. 第二个副本存放于不同第一个副本的所在的机架。
    • 3rd replica. 第三个副本存放于第二个副本所在的机架,但是属于不同的节点。
  • 版本 2.X 采用的如下方式:
    在这里插入图片描述

    例如:Hadoop 2.7.2 版本描述如下:

    For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on one node in the local rack, another on a different node in the local rack, and the last on a different node in a different rack.

    简要概况起来3点:

    • 1st replica. 如果写请求方所在机器是其中一个datanode,则直接存放在本地,否则随机在集群中选择一个datanode。
    • 2nd replica. 第二个副本存放于第一个副本所在的机架,但不同的节点。
    • 3rd replica. 第三个副本存放于不同的机架。

三. NameNode工作机制

1. 概述
NameNode主要负责三个功能:(1) 管理元数据;(2) 维护目录树;(3)响应客户请求。

NameNode对元数据有三种存储方式:

  • 内存元数据(NameSystem);
  • 磁盘元数据镜像文件;
  • 数据操作日志文件(可通过日志运算出元数据)。

2. 元数据管理
首先介绍下,元数据格式:
在这里插入图片描述

如上图所示,是一条元数据,/test/a.log 是在hdfs文件系统中的路径,3是这个文件的副本数。文件被分成blk_1和blk_2两个块,每个块在实际的节点中有3个副本,比如blk_1的3个副本分别存储在h0,h1,h3中。

现在由此引出一个问题,namenode中的元数据是存储在哪里的?首先,我们做个假设,如果存储在namenode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断点,元数据丢失,整个集群就无法工作了!!!因此必须在磁盘中有备份,在磁盘中的备份就是fsimage,存放在namenode节点对应的磁盘中。这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新fsimage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦namenode节点断点,就会产生数据丢失。因此,引入edits.log文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到edits.log中。这样,一旦namenode节点断电,可以通过fsimage和edits.log的合并,合成元数据。但是,如果长时间添加数据到 edits.log中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行fsImage和edits.log的合并,如果这个操作有namenode节点完成,又会效率过低。因此,引入一个新的节点secondaryNamenode,专门用于fsImage和edits.log的合并。

3. Secondary NameNode 工作机制分析
secondarynamenode负责定期把editslog合并到fsimage,“定期”是namenode向secondarynamenode发送RPC请求的,是按时间(默认3600秒)或者日志记录条数(默认1百万)为“间隔”的。

每隔一段时间,会由secondary namenode将namenode上积累的所有edits和一个最新的fsimage下载到本地,并加载到内存进行merge(这个过程称为checkpoint)。

checkpoint处理过程的具体步骤如下:

在这里插入图片描述

  • namenode节点每隔一定时间向secondarynamenode发送RPC请求,请求合并log到fsImage;
  • namenode进行edits.log的滚动,这样新的编辑操作就能够进入新的文件中;
  • secondaryNamenode从namenode中读取(通过http服务)edits.log(多个,滚动日志文件)和fsImage文件;
  • secondaryNamenode进行fsImage和edits.log的合并,成为fsimage.checkpoint文件;
  • namenode下载合并后的fsImage.checkpoin文件 ;
  • 将fsimage.checkpoint和edits.new命名为原来的文件名。

关于checkpoint操作的配置:

dfs.namenode.checkpoint.check.period=60  #检查触发条件是否满足的频率,60秒

dfs.namenode.checkpoint.max-retries=3  #最大重试次数

dfs.namenode.checkpoint.period=3600  #两次checkpoint之间的时间间隔3600秒

dfs.namenode.checkpoint.txns=1000000 #两次checkpoint之间最大的操作记录

dfs.namenode.checkpoint.dir=file://${hadoop.tmp.dir}/dfs/namesecondary

dfs.namenode.checkpoint.edits.dir=${dfs.namenode.checkpoint.dir}

4. NameNode工作机制
NameNode工作分为两个阶段:

  • 第一阶段: namenode 启动
    • 第一次启动 namenode 格式化后, 创建 fsimage 和 edits 文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
    • 客户端对元数据进行增删改的请求。
    • namenode 记录操作日志,更新滚动日志。
    • namenode 在内存中对数据进行增删改查。
  • 第二阶段: Secondary NameNode 工作
    • namenode节点每隔一定时间向secondarynamenode发送RPC请求,请求合并log到fsImage;
    • namenode进行edits.log的滚动,这样新的编辑操作就能够进入新的文件中;
    • secondaryNamenode从namenode中读取(通过http服务)edits.log(多个,滚动日志文件)和fsImage文件;
    • secondaryNamenode进行fsImage和edits.log的合并,成为fsimage.checkpoint文件;
    • namenode下载合并后的fsImage.checkpoin文件 ;
    • 将fsimage.checkpoint和edits.new命名为原来的文件名。

四. NameNode的镜像文件和编辑日志文件

1. 概述
NameNode的镜像文件fsimage 和 编辑日志 editslog 存储 ${dfs.namenode.name.dir}/current目录下,这个目录可以在hdfs-site.xml中配置的。这个目录下的文件结构如下:
在这里插入图片描述
包括edits日志文件(滚动的多个文件),有一个是edits_inprogress_*是当前正在写的日志。fsimage文件以及md5校检文件。seen_txid是记录当前滚动序号,代表seen_txid之前的日志都已经合并完成。

2. 查看文件
使用 oiv 查看镜像fsimage文件:hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径

hdfs oiv -p XML -i fsimage_0000000000000000076 -o /opt/tools/hadoop/fsimage.xml

使用oev查看编辑日志edits文件:hdfs oev -p 文件类型 -i 编辑日志 -o 转换后文件输出路径

hdfs oev -p XML -i 
edits_0000000000000000003-0000000000000000013 -o /opt/tools/hadoop/edits.xml

$dfs.namenode.name.dir/current/seen_txid非常重要,是存放transactionId的文件,format之后是0,它代表的是namenode里面的edits_*文件的尾数,namenode重启的时候,会按照seen_txid的数字恢复。所以当你的hdfs发生异常重启的时候,一定要比对seen_txid内的数字是不是你edits最后的尾数,不然会发生重启namenode时metaData的资料有缺少,导致误删Datanode上多余Block的信息。


五. DataNode工作机制

1. 概述
Datanode主要负责两个功能

  • 存储管理用户的文件块数据;
  • 定期向 NameNode 汇报自身所持有的block信息(通过心跳信息上报)(这点很重要,因为,当集群中发生某些block副本失效时,集群如何恢复block初始副本数量的问题)。
<property>
    <name>dfs.blockreport.intervalMsec</name>
    <value>3600000</value>
    <description>Determines block reporting interval in milliseconds.</description>
</property>

DataNode 掉线判断时限参数:

DataNode 进程死亡或者网络故障造成 DataNode 无法与 NameNode 通信,NameNode 不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。
HDFS默认的超时时长为10分钟+30秒(默认的heartbeat.recheck.interval 大小为5分钟,dfs.heartbeat.interval默认为3秒)。如果定义超时时间为timeout,则超时时长的计算公式为:

timeout  = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval

需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。

<property>
    <name>dfs.namenode.heartbeat.recheck-interval</name>
    <value>300000</value>
</property>
<property>
    <name> dfs.heartbeat.interval </name>
    <value>3</value>
</property>

2. DataNode工作机制
在这里插入图片描述

  • 一个数据块在datanode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
  • DataNode启动后向namenode注册,通过后,周期性(1小时)的向namenode上报所有的块信息。
  • 心跳是每3秒一次,心跳返回结果带有namenode给该datanode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个datanode的心跳,则认为该节点不可用。
  • 集群运行中可以安全加入和退出一些机器。

3. 数据完整性

  • 当DataNode读取block的时候,它会计算checksum;
  • 如果计算后的checksum,与block创建时值不一样,说明block已经损坏;
  • client读取其他DataNode上的block;
  • datanode在其文件创建后周期验证checksum。

参考

苦水润喉 Hadoop(六)之HDFS的存储原理(运行原理)
克终:深入理解HDFS的架构和原理
Pickle:深刻理解HDFS工作机制
LJN:hadoop namenode的工作机制
JokerDa DataNode 工作机制
Android路上的人HDFS副本放置策略

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值