HDFS 内部工作机制

  • HDFS集群分为两大角色:NameNode、DataNode (Secondary Namenode)

  • NameNode 负责管理整个文件系统的元数据

  • DataNode 负责管理用户的文件块(Block)

  • 文件会按照固定的大小(默认 128 M)切成若干文件块(Block)后分布式存储在若干台 DataNode 服务器上

  • 每一个文件块可以有多个副本,并存放在不同的 DataNode 服务器上

  • DataNode 会定期向 NameNode 汇报自身所保存的文件块(Block)信息,而 NameNode 则会负责保持文件的副本数量

HDFS 的内部工作机制对客户端保持透明,客户端通过向 NameNode 发送请求来访问 HDFS 存放的文件

HDFS 写数据流程

# 上传 file.data 到 HDFS (300M)
hadoop fs -put file.data /data/file.data
流程图

详细步骤
  1. 使用客户端命令行向 HDFS 上传 file.data(300M)文件时,客户端会向集群中的 NameNode 通信请求上传文件到 HDFS 目录树的 /data/file.data 路径
  2. NameNode 收到客户端请求后会检查 /data 目录 和 /data/file.data 文件是否存在,如果不存在则向客户端返回可以进行上传文件
  3. 由于上传的 file.data 文件是 300M(默认文件数据块 128M),文件需要被切分成三个文件数据库(Block)依次进行上传。客户端先向 NameNode 请求上传第一个文件数据块(Block)以及告诉 NameNode 存放文件数据块的副本数量(默认 3 个),NameNode 则会返回 3 个可以上传的 DataNode(假设是 DataNode1、DataNode2、DataNode4)
  4. 客户端选择与 DataNode1 建立网络连接,而 DataNode1 接着与 DataNode2 建立网络连接,DataNode2 与DataNode4 建立网络连接,(本质就是 RPC 远程调用形成 pipeline 网络连接链路通路)。通道建立完毕后,DataNode1 会向客户端作出应答,告诉客户端可以上传第一个文件数据块(Block)
  5. 客户端收到 DataNode1 的应答后,以 packet 包为单位向 DataNode1 上传数据流,上传的数据流是先存放到 DataNode1 的一个缓冲区,再缓冲区同时向其他 DataNode 缓冲区传,缓冲区再写到磁盘
  6. 上传过程中,DataNode 会进行校验,校验失败则传输失败,但是只要有一个 DataNode 传输成功即可。因为 NameNode 会判断成功的数量与备份要求的是否一致,不一致的话则会对数据进行同步使得一致。
  7. 第一个文件数据块(Block)上传完成后,会再重新与 NameNode 建立网络连接,请求上传第二个文件数据块(Block),即重复第3步流程,直到所有文件数据快(Block)全部上传为止。
副本放置策略 - 就近原则

挑选 DataNode 主要考虑空间与距离因素

  • 第一个副本考虑选择与客户端距离最近的 DataNode(同机架)
  • 第二个副本考虑跨机架选择一个 DataNode(增加副本的可靠性)
  • 第三个副本挑选与第一个 DataNode 同机架的 DataNode(配置机架感知)

为了最小化全局带宽消耗和读取延迟,HDFS 试图满足来自离客户端最近的副本的读取请求。如果在与客户端相同的机架上存在一个副本,则首选该副本来满足读请求。如果 HDFS 集群跨越多个数据中心,那么驻留在本地数据中心的副本优于任何远程副本。

NameNode 安全模式(SafeMode)

  • 在启动 NameNode 时,NameNode 进入一个称为 安全模式(SafeMode)的特殊状态。当 NameNode 处于该状态,不会发生文件数据块的复制。
  • NameNode 从数据节点接收心跳和 BlockReport 消息。Blockreport包含DataNode托管的数据块列表。每个块都有一个指定的最小副本数量。当该数据块的最小副本数量(dfs.namenode.replication.min =1)已与

    NameNode 签入时,就认为该块是安全复制的。当安全复制的数据块的可配置百分比(

    dfs.namenode.safemode.threshold-pct =0.999f)通过NameNode(加上额外的30秒)检查后,

    NameNode将退出安全模式状态。然后,它确定仍然少于指定副本数量的数据块列表(如果有的话)。然后

    NameNode将这些块复制到其他数据节点。

安全模式(Safemode )开启时不能有写操作

安全模式(SafeMode)命令:

客户端写数据 DataNode 故障处理
  • 客户端在写入文件数据块到 DataNode 发生故障时,客户端会关闭与 DataNode 之间的网络通信 pipeline 管线,以确保故障节点 pipeline 管线下游的 DataNode 不会漏掉 packet 数据包
  • 客户端将故障 DataNode 通知给 NameNode,以便故障的 DataNode 在恢复后可以删除存储的部分数据块
  • 客户端基于另外两个正常的 DataNode 构建一条新的 pipeline 管线,将剩下的文件数据块写入 pipeline 管线中正常的 DataNode
  • 当 NameNode 注意到文件数据块副本数量不足的时候,就会在另一个 DataNode 节点上创建一个新的副本,后续的数据块则继续正常处理

HDFS 读数据流程

# 从 HDFS 下载 /data/file.data(300M) 文件到本地系统
hadoop fs -get /data/file.data ./

详细步骤
  1. 使用客户端命令行从 HDFS 下载 /data/file.data(300M)文件时,客户端与 NameNode 建立网络连接,并请求要下载的文件;NameNode 查看元数据,找到下载文件被切割的 3 个文件数据块(Block)所存放的 DataNode 信息,并返回给客户端
  2. 客户端首先下载第一个文件数据块(Block),而第一个文件数据块(Block)在 3 个 DataNode 上都有其副本,客户端根据就近原则去挑选一个 DataNode 建立网络连接,并请求读取文件数据块(Block);DataNode 读取磁盘数据流,向客户端发送数据流
  3. 客户端接收 DataNode 发送的数据流并暂存缓存中,然后写入到本地文件中,接着客户端重复步骤1、2 来下载第二个文件数据块(Block)(和第三个文件数据块(Block),然后数据以追加的形式写入到文件中,最终合并成一个完成的文件
客户端读数据 DataNode 故障处理
  • 客户端在 DataNode 上读取文件数据块(Block)时发生故障(即客户端 与 DataNode 无法正常通信),客户端会试图从故障 DataNode 最邻近的一个保存副本的 DataNode 读取文件数据块(Block)
  • 客户端会记录故障的 DataNode,以确保以后不会反复读取该故障 DataNode 节点上后续的文件数据块(Block)
  • 客户端会通过校验和确认从 DataNode 读取的数据是否完整,如果发现有损坏的文件数据块(Block),客户端会试图从其他保存有副本的 DataNode 读取数据,并将被损坏的块通知给 NameNode
  • NameNode 记录有损坏的文件数据块的 DataNode,通知其删除数据,并创建新的文件数据块的副本,以确保副本数量的一致

NameNode 工作机制

NameNode 职责

  • 负责客户端请求的响应
  • 管理元数据(即 HDFS 的目录结构及每一个文件的文件数据块(Block)信息(如 block id、block 副本数量,block 的存放位置等)
  • 容错处理

NameNode 管理元数据

元数据的存储
  • 内存元数据

    NameNode 在内存(meta data)中保存着一份实时、完整的元数据

  • 磁盘元数据镜像文件

    NameNode 在磁盘中保存着某个时间点元数据在内存中的镜像 fsimage 文件(类似 redis 的 RDB)

    • fsimage 包含 Hadoop 文件系统中的所有目录和文件 idnode 的序列化信息(具体而言,文件包含的信息有修改时间、访问时间、块大小和组成一个文件块信息等,目录包含的信息有修改时间、访问控制权限等)
    • fsimage 并不包含 DataNode 的信息,而是包含 DataNode 上文件数据块(Block)的映射信息。
    • 当一个新的 DataNode 加入到集群中,DataNode 会向 NameNode 提供文件数据块(Block)的信息,而 NameNode 会定期向 DataNode 的索取文件数据块的信息,以使得 NameNode 拥有最新的文件数据块(Block)映射信息
    • 由于 fsimage 包含 Hadoop 文件系统中的所有目录和文件 idnode 的序列化信息,所以如果 fsimage 文件丢失或损坏,那么即使 DataNode 上有文件数据块(Block),也无法从 DataNode 上的获取数据
  • 数据操作日志文件

    NameNode 会把引起元数据变化的客户端操作记录在 edits 日志文件中(类似 redis 的 AOF)

元数据目录
  • 在第一次部署好 Hadoop 集群的时候,需要在 NameNode 节点上格式化磁盘

    [root@node-01 etc]# hadoop namenode -format
  • 格式化完成之后,将会在 NameNode 存储路径的 current 目录下创建元数据目录

    current/
    |-- VERSION
    |-- edits_*
    |-- fsimage_*
    |-- fsimage_*.md5
    |-- seen_txid
    • VERSION

      namespaceID=1064465530
      clusterID=CID-a1afedaf-49ed-4219-bae3-7b7268fca624
      cTime=1616685687133
      storageType=NAME_NODE
      blockpoolID=BP-593175008-192.168.229.21-1616685687133
      layoutVersion=-65
      • namespaceID:是文件系统的唯一标识符,在文件系统首次格式化之后生成的
      • clusterID:是系统生成或手动指定的集群 ID
      • cTime:NameNode 存储时间的创建时间
      • storageType:说明这个文件存储的是什么进程的数据结构信息
      • layoutVersion:HDFS 永久性数据结构的版本信息
      • blockpoolID:针对每一个 Namespace 所对应的 blockpool 的 ID(DataNode Block 目录名)
    • seen_txid

      该文件中记录的是 edits 日志滚动的序号,每次重启NameNode时,NameNode就知道要将会执行edits_0000001~ edits_seen_txid 的 edits 日志文件,已更新内存元数据

    • edits_* 查看器(OEV)

      oev 是 offline edits viewer(离线 edits 查看器)的缩写,该工具可以使用 oev 工具查看 edits 日志文件和 fsimage 镜像文件内容

      命令格式:hdfs oev -p 文件类型 -i 编辑日志 -o 转换后文件输出路径

      • -p –processor 指定输出处理器: binary (二进制格式), xml (默认,XML格式),stats
      • -i –inputFile 输入edits文件(如果是xml后缀,表示XML格式,其他表示二进制)
      • -o –outputFile 输出文件,如果存在,则会覆盖
      [root@node-01 current]# hdfs oev -i edits_inprogress_0000000000000000081 -o edits.xml
    • images_* 查看器(OIV)

      oiv 是 offline image viewer 的缩写,用于将 fsimage 文件的内容转储到指定文件里以便于阅读。OIV 在处理很大的 fsimage 文件时是相当快。

      命令格式:hdfs oiv -p 文件类型 -i 编辑日志 -o 转换后文件输出路径

      • -p –processor 指定输出处理器: LS、XML、FileDistribution
      • -i –inputFile 输入 fsimage 文件(如果是xml后缀,表示XML格式,其他表示二进制)
      • -o –outputFile 输出文件(如果存在,则会覆盖)
      [root@node-01 current]# hdfs oiv -i fsimage_0000000000000000080 -p XML -o fsimage.xml
元数据的内存加载
  1. NameNode 启动时,会将磁盘中 fsimage 文件中的内容加载到内存中,之后再执行数据操作日志 edits 文件,使得内存获得一份最新最完整的元数据
  2. NameNode 启动后,客户端的所有更新数据操作会同步写入到 edits 日志中(fsimage 文件一般很大,直接写入会导致系统运行缓慢)

元数据的 CheckPoint(检查点)机制

  • Secondary NameNode 会定期从 NameNode 上下载 fsimage 镜像和新生成的 edits 日志,然后加载 fsimage 镜像到内存中,接着顺序解析 edits 文件,对内存中的元数据对象进行修改整合

  • 整合完成后,将内存元数据序列化成一个新的 fsimage 镜像文件,并将这个 fsimage 镜像文件上传给 NameNode

  • NameNode 接收到 Secondary NameNode 发送的新 fsimage 镜像文件后,即可将旧的 fsimage 镜像文件和 edist 日志替换掉

    注1:Secondary NameNode 每次做 CheckPoint 操作时,第一次 CheckPoint 需要下载 fsimage 镜像文件,以后就不用下载,因为之前已经下载过了

    注2:Namenode 和 Secondary NameNode 的工作目录存储结构完全相同,当 NameNode 故障退出需要重新恢复时,可以从 Secondary NameNode 的工作目录中将 fsimage 拷贝到 NameNode 的工作目录,以恢复NameNode 的元数据

CheckPoint(检查点)操作触发条件相关配置

CheckPoint(检查点)相关配置 hdfs-size.xml 如下:

  • Secondary NameNode 检查触发条件是否满足的频率配置(默认 60 s)

    <property>
    <name>dfs.namenode.checkpoint.check.period</name>
    <value>60</value>
    </property>
  • Secondary NameNode 进程启动位置的配置

    <property>
    <name>dfs.namenode.secondary.http-address</name>
    <value>node-02:9868</value>
    </property>
  • Secondary NameNode 保存元数据文件的目录配置

    <property>
    <name>dfs.namenode.checkpoint.dir</name>
    <value> /root/apps/hadoop-3.2.1/data/namesecondary</value>
    </property>
  • Secondary NameNode 最多重试次数(默认3次)

    <property>
    <name>dfs.namenode.checkpoint.max-retries</name>
    <value>3</value>
    </property>
  • Secondary NameNode 两次 CheckPoint 之间间隔时长(默认 1 小时)

    <property>
    <name>dfs.namenode.checkpoint.period</name>
    <value>3600</value>
    </property>

DataNode 工作机制

  • DataNode 存储管理用户的文件数据块(Block),一个文件数据块(Block)在 DataNode 上以文件形式存储在磁盘上
  • DataNode 定期向 NameNode 汇报自身所持有的所有文件数据块(Block)信息(汇报间隔时间由配置项 dfs.blockreport.intervalMsec 决定)
  • 心跳检测默认每 3 秒检测一次(检测间隔时间由配置项 dfs.heartbeat.interval 决定),心跳检测返回结果带有 NameNode 给 DataNode 的命令(如复制文件数据块副本到另一个 DataNode 或删除某个损坏的文件数据块)
  • 如果超过限定时间没有收到某个 DataNode 的心跳,NameNode 则认为该 DataNode 不可用
  • DataNode 掉线后会触发副本检查机制,NameNode 会在集群内通知正常的 DataNode 进行副本复制
  • Hadoop 集群运行中可以安全加入和退出一些 DataNode 节点
DataNode 职责
  • 存储管理用户的文件数据块(Block)

    • 数据:用户的文件数据块(Block)

    • 元数据:文件数据块(Block)长度、文件数据块校验和、时间戳等

  • 定期向 NameNode 汇报自身所持有的文件数据块(Block)信息(通过心跳信息上报)

    <!-- 设置 datanode 向 namenode 报告 block 信息的时间间隔(默认6小时)
    <property>
    <name>dfs.blockreport.intervalMsec</name>
    <value>21600000</value>
    <description>Determines block reporting interval in milliseconds.</description>
    </property>
DataNode 掉线时限参数设置

DateNode 以固定周期向 NameNode 发送心跳,NameNode 如果一段时间内没有收到心跳,就会标记 DateNode 为故障宕机,这段时间叫做 DataNode 超时时长。

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

  • DataNode 核查心跳间隔时长(默认 5 分钟)
<property>
<name>dfs.namenode.heartbeat.recheck-interval</name>
<value>300000</value>
<description>This time decides the interval to check for expired datanodes. With this value and dfs.heartbeat.interval, the interval of deciding the datanode is stale or not is also
calculated.The unit of this configuration is millisecond.
</description>
</property>
  • DataNode 心跳检测间隔时长(默认 3 秒)
<property>
<name>dfs.heartbeat.interval</name>
<value>3</value>
<description>Determines datanode heartbeat interval in seconds. Can use the following suffix (case insensitive): ms(millis), s(sec), m(min), h(hour), d(day) to specify the time (such as 2s, 2m, 1h, etc.). Or provide complete number in seconds (such as 30 for 30 seconds).
</description>
</property>
DataNode 目录结构

与 NameNode 不同,DataNode 存储目录是初始阶段自动创建的,不需要额外的格式化

  • VERSION(datanode/current/)

    [root@node-01 data]# cat datanode/current/VERSION
    storageID=DS-89dfa113-a168-4eed-87c5-c25d024e49e0
    clusterID=CID-a1afedaf-49ed-4219-bae3-7b7268fca624
    cTime=0
    datanodeUuid=a39bf511-8b1f-4da8-8c1f-3c4201be87cd
    storageType=DATA_NODE
    layoutVersion=-57
    • storageID:磁盘存储 ID
    • clusterID:集群 ID (全局唯一)
    • cTime:标记 DataNode 存储系统的创建时间,对于刚格式化的存储系统属性值为 0
    • datanodeUuid:datanode 的唯一识别码
    • storageType:存储类型
    • layoutVersion:是一个负数(通常只有 HDFS 增加新特性才会更新这个版本号)
  • VERSION(datanode/current/BP-593175008-192.168.229.21-1616685687133/current)

    [root@node-01 data]# cat datanode/current/BP-593175008-192.168.229.21-1616685687133/current/VERSION
    namespaceID=1064465530
    cTime=1616685687133
    blockpoolID=BP-593175008-192.168.229.21-1616685687133
    layoutVersion=-57
    • namespaceID:DataNode 首次访问 NameNode 时从 NameNode 获取的 storageID(对每个 DataNode 是唯一的,但对单个 DataNode 中所有存储目录则是相同的),NameNode 可用这个属性来区别不同的 DataNode
    • cTime:标记 DataNode 存储系统的创建时间
    • blockpoolID:一个 block pool id 用于标识一个 block pool,并且是跨集群的全局唯一
    • layoutVersion:一个负整数,通常只有 HDFS 增加新特性才会更新版本号

HDFS 内部工作机制的更多相关文章

  1. spring 内部工作机制(二)

    本章节讲Spring容器从加载配置文件到创建出一个完整Bean的作业流程及参与的角色. Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表, ...

  2. Spring容器技术内幕之内部工作机制

    引言 Spring容器就像一台构造精妙的机器,我们通过配置文件向机器传达控制信息,机器就能够按照设定的模式工作.如果将Spring容器比作一辆车,那么可以将BeanFactory看成汽车的发动机,而A ...

  3. 【转】Java学习---HashMap和HashSet的内部工作机制

    [原文]https://www.toutiao.com/i6593863882484220430/ HashMap和HashSet的内部工作机制 HashMap 和 HashSet 内部是如何工作的? ...

  4. 图文详解 HDFS 的工作机制及其原理

    大家好,我是大D. 今天开始给大家分享关于大数据入门技术栈--Hadoop的学习内容. 初识 Hadoop 为了解决大数据中海量数据的存储与计算问题,Hadoop 提供了一套分布式系统基础架构,核心内 ...

  5. 大数据学习之HDFS的工作机制07

    1:namenode+secondaryNameNode工作机制 2:datanode工作机制 3:HDFS中的通信(代理对象RPC) 下面用代码来实现基本的原理 1:服务端代码 package it ...

  6. (spring-第5回【IoC基础篇】)spring容器从加载配置文件到实例化bean的内部工作机制

    前面讲过,spring的生命周期为:实例化前奏-->实例化-->实例化后期-->初始化前期-->初始化-->初始化后期-->bean的具体调用-->销毁前-- ...

  7. spring 内部工作机制(一)

    Spring内部机制的内容较多,所以打算多分几个阶段来写. 本章仅探索Spring容器启动做了哪些事: 前言: 都说Spring容器就像一台构造精妙的机器,此话一点不假,我们通过配置文件向机器传达控制 ...

  8. Hadoop HDFS NameNode工作机制

    Secondary namenode 首先,我们假设如果存储在Namenode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低.因此,元数据需要存放在内存中.但如果只存在内存中 ...

  9. 实例说明C++的virtual function的作用以及内部工作机制初探

    C++为何要引入virtual function? 来看一个基类的实现: 1 class CBase 2 { 3 public: 4 CBase(int id) : m_nId(id), m_pBas ...

  10. 浏览器详谈及其内部工作机制 —— web开发必读

    浏览器介绍 如今,浏览器格局基本上是五分天下,分别是:IE.Firefox.Safari.Chrome.Opera,而浏览器引擎就更加集中了,主要是四大巨头:IE的浏览器排版引擎Trident,目前随 ...

随机推荐

  1. Python 切片/列表/字符串之间装换

    1. 怎么实现字符串变为list 使用split(),把字符串拆分再存入数组: 例子 input="ni si shi" output=input.split(" &qu ...

  2. Drift Programming | 漂移编程 | 哲学编程 | 架构设计 | TDD |DDD |Microservice

  3. svn 中如何checkout出单个文件

    A 通过命令行操作 1.检出目录images svn co --depth=empty http://www.iusesvn.com/project1/images images_work_dir 这 ...

  4. Qt 字符串相等判断问题

    QString str = "0"; if (QString(param.value.data()) == QStringLiteral("空")) { str ...

  5. 关于Salesforce存在至于项目的选择List的取值问题

    概要: 我们在做项目的时候,经常会遇到一个问题: 一个选择List字段的可选项被另一个选择List制约,这种情况如何在后台取得这两者的对应关系. 原文在这里(侵删): Apexで連動項目の選択肢を取得 ...

  6. C# 两个list集合合并成一个,及升序降序

    C# List集合合并   在开发过程中.数组和集合的处理是最让我们担心.一般会用for or foreach 来处理一些操作.这里介绍一些常用的集合跟数组的操作函数.  首先举例2个集合A,B. L ...

  7. ts(typescript)讲解for , for...in..., for...of..., while, every, some, map, filter

    for  一般用于已知循环次数 var num:number = 5; var i:number; var factorial = 1; for(i = num;i>=1;i--) { fact ...

  8. EXPORT_SYMBOL的正常使用

    1.EXPORT_SYMBOL的作用是什么? EXPORT_SYMBOL标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以 ...

  9. Docker学习笔记-03 容器数据卷

    1.宿主 vs容器直接映射数据容器卷 docker run -it  --privileged=true  -v  /宿主机绝对路径目录 :/ 容器内目录   镜像名 eg:  docker run  ...

  10. 如何理解JavaScript中常用的4种排序算法?

      如何理解JavaScript中常用的4种排序算法? 冒泡排序 冒泡排序是我们在编程算法中,算是比较常用的排序算法之一,在学习阶段,也是最需要接触理解的算法,所以我们放在第一个来学习. 算法介绍: ...