Namenode中主要存储fsimage和editlog文件,Datanode中主要存储数据块blk文件。下面分别介绍Namenode和Datanode中的文件存储结构。

文章目录

  • 1 Namenode
    • 1.1 文件所在位置
    • 1.2 文件目录结构
    • 1.3 文件目录解析
      • 1.3.1 VERSION文件
      • 1.3.2 edits_*文件
      • 1.3.3 fsimage_*文件
      • 1.3.4 fsimage_*.md5文件
      • 1.3.5 seen_txid文件
      • 1.3.6 in_use.lock文件
  • 2 Datanode
    • 2.1 文件所在位置
    • 2.2 文件目录结构
    • 2.3 文件目录解析
      • 2.3.1 BP-`*`-`*`-`*`文件夹
      • 2.3.2 外层VERSION文件
      • 2.3.3 内层VERSION文件
      • 2.3.4 finalized/rbw/tmp文件夹
      • 2.3.5 finalized特殊目录结构解析
      • 2.3.6 in_use.lock文件
      • 2.3.7 scanner.cursor文件
      • 2.3.8 blk_*文件
      • TODO

1 Namenode

1.1 文件所在位置

文件所在位置由hdfs-site.xml中的配置项dfs.namenode.name.dir配置。这些文件都存于${dfs.namenode.name.dir}/current文件夹下,在dfs.namenode.name.dir配置项中可以配置多个目录,各个目录存储的文件结构和内容都完全一样,配置多个目录只是起到冗余备份的作用。

<property><name>dfs.namenode.name.dir</name><value>file://${hadoop.tmp.dir}/dfs/name</value>
</property>

dfs.namenode.name.dir在hdfs-site.xml中定义的默认值为file://${hadoop.tmp.dir}/dfs/name,其中hadoop.tmp.dir是core-site.xml中的配置项,hadoop.tmp.dir的默认值为/tmp/hadoop-${user.name}。因此文件默认都是存放在/tmp/hadoop-${user.name}/dfs/name/current路径下的。

<property><name>hadoop.tmp.dir</name><value>/tmp/hadoop-${user.name}</value><description>A base for other temporary directories.</description>
</property>

具体到我的服务器,dfs.namenode.name.dir用了配置的/cloud/data/hadoop/dfs/nn,因此我的服务器上的文件的路径就直接为:/cloud/data/hadoop/dfs/nn/current。

<property><name>dfs.namenode.name.dir</name><value>/cloud/data/hadoop/dfs/nn/</value>
</property>

1.2 文件目录结构

nn文件夹下的内容有(之所以从nn文件夹而不是current文件夹下开始是因为要讲解和current同级的in_user.lock文件):

nn
├── current
│ ├── edits_0000000001362702459-0000000001363401818
│ ├── edits_0000000001363401819-0000000001363931603
│ ├── edits_0000000001363931604-0000000001364566627
│ ├── edits_0000000001364566628-0000000001365069009
│ ├── edits_0000000001365069010-0000000001365209404
│ ├── edits_0000000001365209405-0000000001365211445
│ ├── edits_0000000001365211446-0000000001365211447
│ ├── edits_0000000001365211448-0000000001365211451
│ ├── edits_0000000001365211452-0000000001365211453
│ ├── edits_0000000001365211454-0000000001365211625
│ ├── edits_0000000001365211626-0000000001365213635
│ ├── edits_inprogress_0000000001365213636
│ ├── fsimage_0000000001365431029
│ ├── fsimage_0000000001365431029.md5
│ ├── fsimage_0000000001365431090
│ ├── fsimage_0000000001365431090.md5
│ ├── seen_txid
│ └── VERSION
└── in_use.lock

1.3 文件目录解析

从上面的目录树中可以发现,主要有6类文件:

1.3.1 VERSION文件

VERSION是java属性文件,内容大致如下:

namespaceID=644097999
clusterID=CID-da027b7b-4e9f-4287-be7a-03735d895bc2
cTime=1603347772521
storageType=NAME_NODE
blockpoolID=BP-1345407316-192.168.100.148-1603347772521
layoutVersion=-63

namespaceID是文件系统唯一标识符,在文件系统首次格式化之后生成,在引入Federation特性后,可能会有多个namespace。

clusterID是系统生成或手动指定的集群ID,在-clusterID选项中可以使用它。

cTime表示Namenode存储的创建时间。

storageType表示这个文件存储的是什么进程的数据结构信息(如果是Datanode,则为DATA_NODE)。

blockpoolID表示每一个Namespace对应的块池id,这个id包括了其对应的Namenode节点的ip地址。

layoutVersion表示HDFS永久性数据结构的版本信息,只要数据结构变更,版本号也要递减,此时的HDFS也需要升级,否则磁盘仍旧使用旧版本的数据结构,这会导致新版本的Namenode无法使用。

1.3.2 edits_*文件

edits文件中存放的是客户端执行的所有更新命名空间的操作。

这里我们首先了解一下transactionId的概念。transactionId与客户端每次发起的RPC操作相关,当客户端发起一次RPC请求对Namenode的命名空间修改后,Namenode就会在editlog中发起一个新的transaction用于记录这次操作,每个transaction会用一个唯一的transactionId标识。

edits_*分为两类文件,一类是edits_startTransactionId-endTransactionId,另一类是edits_inprogress_startTransactionId。对于第一类文件,每个edits文件都包含了文件名中从startTransactionId开始到endTransactionId之间的所有事务。

第二类文件表示正在进行处理的editlog,所有从startTransactionId开始的新的修改操作都会记录在这个文件中,直到HDFS重置这个日志文件,重置操作会将inprogress文件关闭,并将inprogress文件改名为正常的editlog文件,即第一类文件,同时还会打开一个新的inprogress文件,记录正在进行的事务。

可以通过oev命令查看edits文件,基本命令格式为:

hdfs oev -p 文件类型(通常为xml) -i edits文件 -o 转换后文件输出路径
<?xml version="1.0" encoding="UTF-8"?>
<EDITS><EDITS_VERSION>-63</EDITS_VERSION><RECORD><OPCODE>OP_START_LOG_SEGMENT</OPCODE><DATA><TXID>63949</TXID></DATA></RECORD><RECORD><OPCODE>OP_END_LOG_SEGMENT</OPCODE><DATA><TXID>63950</TXID></DATA></RECORD>
</EDITS>

1.3.3 fsimage_*文件

fsimage文件其实是hadoop文件系统元数据的一个永久性的检查点,其中包含hadoop文件系统中的所有目录和文件inode的序列化信息。

fsimage_*的具体文件命名规则是这样的:fsimage_endTransactionId,它包含hadoop文件系统中endTransactionId前的完整的HDFS命名空间元数据镜像。

可以通过oiv命令查看fsimage文件,基本命令格式为:

hdfs oiv -p 文件类型(通常为xml) -i fsimage文件 -o 转换后文件输出路径

1.3.4 fsimage_*.md5文件

md5校验文件,用于确保fsimage文件的正确性,可以作用于磁盘异常导致文件损坏的情况。

1.3.5 seen_txid文件

这个文件中保存了一个事务id,这个事务id值只会在两种情况下更新:

  • 上一个检查点(即合并edits和fsimage文件)时的最新事务id
  • 编辑日志重置(即生成一个新的inprogress文件)时的最新事务id

可以发现,这个事务id并不是Namenode内存中最新的事务id。这个文件的作用在于Namenode启动时,利用这个文件判断是否有edits文件丢失,Namenode启动时会检查seen_txid并确保内存中加载的事务id至少超过seen_txid,否则Namenode将终止启动操作。

1.3.6 in_use.lock文件

这是一个被Namenode线程持有的锁文件,用于防止多个Namenode线程启动并且并发修改这个存储目录。

2 Datanode

2.1 文件所在位置

文件所在位置由hdfs-site.xml中的配置项dfs.datanode.data.dir配置。这些文件都存于${dfs.datanode.data.dir}/current文件夹下,在dfs.namenode.name.dir配置项中可以配置多个目录,这里要注意,Datanode的多个存储目录存储的数据块并不相同,并且不同的存储目录可以是异构的,这样的设计可以提高数据块IO的吞吐率,这是与Namenode中很大不同的一个地方。

<property><name>dfs.datanode.data.dir</name><value>file://${hadoop.tmp.dir}/dfs/data</value>
</property>

dfs.datanode.data.dir在hdfs-site.xml中定义的默认值为file://${hadoop.tmp.dir}/dfs/data,其中hadoop.tmp.dir是core-site.xml中的配置项,hadoop.tmp.dir的默认值为/tmp/hadoop-${user.name}。因此文件默认都是存放在/tmp/hadoop-${user.name}/dfs/data/current路径下的。

<property><name>hadoop.tmp.dir</name><value>/tmp/hadoop-${user.name}</value><description>A base for other temporary directories.</description>
</property>

具体到我的服务器,dfs.datanode.data.dir配置了如下值,因此我的服务器上的文件的路径就包括以下8个路径:/cloud/data*/hadoop/dfs/dn/current。

<property><name>dfs.datanode.data.dir</name>                             <value>/cloud/data1/hadoop/dfs/dn,/cloud/data2/hadoop/dfs/dn,/cloud/data3/hadoop/dfs/dn,/cloud/data4/hadoop/dfs/dn,/cloud/data5/hadoop/dfs/dn,/cloud/data6/hadoop/dfs/dn,/cloud/data7/hadoop/dfs/dn,/cloud/data8/hadoop/dfs/dn</value>
</property>

2.2 文件目录结构

以dfs.datanode.data.dir配置项配置的其中一个目录/cloud/data1/hadoop/dfs/dn为例,它的目录结构为:
以dfs.datanode.data.dir配置项配置的其中一个目录/cloud/data1/hadoop/dfs/dn为例,它的目录结构为:

dn
├── current
│ ├── BP-615261695-192.168.100.74-1602499969654
│ │ ├── current
│ │ │ ├── finalized
│ │ │ │ ├── subdir0
│ │ │ │ ├── subdir1
│ │ │ │ ├── subdir10
│ │ │ │ ├── subdir11
│ │ │ │ ├── subdir12
│ │ │ │ ├── subdir13
│ │ │ │ ├── subdir14
│ │ │ │ ├── subdir15
│ │ │ │ ├── subdir16
│ │ │ │ ├── subdir17
│ │ │ │ ├── subdir18
│ │ │ │ ├── subdir19
│ │ │ │ ├── subdir2
│ │ │ │ ├── subdir20
│ │ │ │ ├── subdir21
│ │ │ │ ├── subdir22
│ │ │ │ ├── subdir23
│ │ │ │ ├── subdir24
│ │ │ │ ├── subdir25
│ │ │ │ ├── subdir26
│ │ │ │ ├── subdir27
│ │ │ │ ├── subdir28
│ │ │ │ ├── subdir29
│ │ │ │ ├── subdir3
│ │ │ │ ├── subdir30
│ │ │ │ ├── subdir31
│ │ │ │ ├── subdir4
│ │ │ │ ├── subdir5
│ │ │ │ ├── subdir6
│ │ │ │ ├── subdir7
│ │ │ │ ├── subdir8
│ │ │ │ └── subdir9
│ │ │ ├── rbw
│ │ │ └── VERSION
│ │ ├── scanner.cursor
│ │ └── tmp
│ │ ├── blk_1080824082
│ │ ├── blk_1080824082_7111789.meta
│ │ ├── blk_1080834049
│ │ └── blk_1080834049_7120152.meta
│ └── VERSION
└── in_use.lock

由于篇幅所限,这里只展开了5层,在实际情况中,subdir0subdir31这32个文件夹每个文件夹下面还是subdir0subdir31这32个文件夹,这些文件夹下面才是类似于tmp文件夹下的blk_*文件。

2.3 文件目录解析

2.3.1 BP-*-*-*文件夹

这个目录是一个块池目录,块池目录保存了一个块池在当前存储目录下存储的所有数据块,在Federation部署方式中,Datanode的一个存储目录会包含多个以BP开头的块池目录。BP后面会紧跟一个唯一的随机块池ID。接下来的第2个*代表当前块池对应的Namenode的IP地址。最后一个*代表这个块池的创建时间。

2.3.2 外层VERSION文件

storageID=DS-fd6c86e2-c1ab-4541-9693-5844c2359a0f
clusterID=CID-a56f3601-ac4b-4c37-95fd-3b04c24a54c9
cTime=0
datanodeUuid=b0f4eafa-54b1-4966-acf9-3986435d5cd6
storageType=DATA_NODE
layoutVersion=-57
  • storageID:存储 id 号

  • clusterID :集群 id,全局唯一

  • cTime :标记了 datanode 存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为 0;但是在文件系统升级之后,该值会更新到新的时间戳。

  • datanodeUuid:datanode 的唯一识别码

  • storageType:存储类型

  • layoutVersion :是一个负整数。通常只有 HDFS 增加新特性时才会更新这个版本号。

2.3.3 内层VERSION文件

namespaceID=800713668
cTime=1602499969654
blockpoolID=BP-615261695-192.168.100.74-1602499969654
layoutVersion=-57
  • namespaceID:是 datanode 首次访问 namenode 的时候从 namenode 处获取的storageID, 对每个 datanode 来说是唯一的(但对于单个 datanode 中所有存储目录来说则是相同的),namenode 可用这个属性来区分不同 datanode。(但我查看了不同datanode上的都相同)

  • cTime :标记了 datanode 存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为 0;但是在文件系统升级之后,该值会更新到新的时间戳。

  • blockpoolID:一个 block pool id 标识一个 block pool,并且是跨集群的全局唯一。当一个新的 Namespace 被创建的时候(format 过程的一部分)会创建并持久化一个唯一 ID。在创建过程构建全局唯一的 BlockPoolID 比人为的配置更可靠一些。NN 将 BlockPoolID 持久化到磁盘中,在后续的启动过程中,会再次 load 并使用。(查看了发现不同datanode上的都相同,BP-1008895165-10.252.87.50-1593312108051的命名就遵循BP-random integer-NameNode-IP address-creation time)

  • layoutVersion: 是一个负整数。通常只有 HDFS 增加新特性时才会更新这个版本号。

2.3.4 finalized/rbw/tmp文件夹

finalized、rbw和tmp目录都是用于存储数据块的文件夹,包括数据块文件及其对应的校验和文件。他们的区别是存放不同状态下的数据块副本文件。我们知道Datanode上保存的数据块副本有5种状态:FINALIZED,RBW(replica being written),RUR(replica under recovery),RWR(replica waiting to be recovered),TEMPORATY(复制数据块或者进行集群数据块平衡操作时的状态)

finalized目录保存所有FINALIZED状态的副本,rbw目录保存RBW、RWR、RUR状态的副本,tmp目录保存TEMPORARY状态的副本。

如果对应到具体的过程,那么当客户端发起写请求创建一个新的副本时,这个副本会被放到rbw目录中;当在数据块备份和集群平衡存储过程中创建一个新的副本时,这个副本就会放到tmp目录中;一旦一个副本完成写操作并被提交,它就会被移到finalized目录中。当Datanode重启时,tmp目录中的所有副本将会被删除,rbw目录中的副本将会被加载为RWR状态,finalized目录中的副本将会被加载为FINALIZED状态。

2.3.5 finalized特殊目录结构解析

finalized目录存储了已经完成写入操作的数据块,由于这样的数据块可能非常多,所以finalized目录会以特定的目录结构存储这些数据块。

在我的机器上,finalized文件夹有32个子文件夹(分别为subdir0-31),每个子文件夹下又有32个子文件夹(同样为subdir0-31),接着才是存的真正的数据块blk文件及其校验文件。你可能会发现自己的目录下不是32个子文件夹,而是64个或者256个,不要奇怪,这是hadoop不同版本之间的差异,下面简要介绍一下不同版本下的目录结构:

  1. 早期版本:当存储目录中的数据块超过64个时,将创建64个子目录来存储数据块。一个父目录最多可以创建64个子目录,一个子目录最多可以存放64个数据块以及64个子目录。

  2. 2.6版本:finalized目录下拥有256个一级子目录,每个一级子目录下可以拥有256个二级子目录。

  3. 2.8.5版本:finalized目录下拥有32个一级子目录,每个一级子目录下可以拥有32个二级子目录。

以2.8.5版本为例,数据块是根据什么判断自己应放在哪个目录下的呢?答案是根据数据块的id,具体的判断规则如下代码所示(DatanodeUtil类的idToBlockDir方法):

  public static File idToBlockDir(File root, long blockId) {int d1 = (int) ((blockId >> 16) & 0x1F);int d2 = (int) ((blockId >> 8) & 0x1F);String path = DataStorage.BLOCK_SUBDIR_PREFIX + d1 + SEP +DataStorage.BLOCK_SUBDIR_PREFIX + d2;return new File(root, path);}

一级目录由d1指定,二级目录由d2指定,d1是数据块id右移16位,再取最后5位得到的数值,可以发现,它的范围是0-31。d2是数据块id右移8位,再取最后5位得到的数值,可以发现,它的范围也是0-31。一级目录和二级目录都对应32个文件夹,与预期相符。

2.6版本的判断规则与2.8.5完全一样,不同点是都是取最后8位,而不是5位,因此,2.6版本的一级目录和二级目录对应的文件夹个数都是256个。

2.3.6 in_use.lock文件

这是一个被Datanode线程持有的锁文件,用于防止多个Datanode线程启动并发修改这个存储目录。

2.3.7 scanner.cursor文件

这个文件记录了访问文件的游标,文件具体内容如下所示:

{"lastSavedMs" : 1604459692263,"iterStartMs" : 1604314428656,"curFinalizedDir" : null,"curFinalizedSubDir" : null,"curEntry" : null,"atEnd" : true
}

2.3.8 blk_*文件

blk_*是数据块文件,其中*代表的数据是数据块id。

blk_*_*.meta是数据块校验文件,其中第一个*是数据块id,第二个*代表数据块的版本号。

blk的meta校验文件(保存blk的checksum信息)大小大概是blk文件大小的1/128,因为每512字节做一次校验生成4字节校验,在机器上验证了一下大小,接近1/128。

TODO

VERSION文件属性解释修改(像namespaceId有问题)

HDFS文件目录结构详解相关推荐

  1. vue文件目录结构详解(一)---基础配置

    参考文献: vue-cli入门(二)--项目结构 | 思否-Reachel Vue-cli创建vue项目以及配置文件梳理|思否-AshleyLv Vue系列之WebPack与Eslint | 充电实践 ...

  2. 抽了一包华子才写出来的linux 文件目录结构详解

    文章末尾给大家留下了大量的福利 前言 今天笔者想和大家聊聊linux操作系统的文件目录结构,废话呢笔者也不想多说直接进入正文吧,希望这一篇文章能够更好的帮助大家了解到linux操作系统的文件目录结构. ...

  3. vue 文件目录结构详解

    项目简介 基于 vue.js 的前端开发环境,用于前后端分离后的单页应用开发,可以在开发时使用 ES Next.scss 等最新语言特性.项目包含: 基础库: vue.js.vue-router.vu ...

  4. Linux文件目录结构详解

    目录结构及主要内容 "/"根目录部分有以下子目录: /usr 目录包含所有的命令.程序库.文档和其它文件.这些文件在正常操作中不会被改变的.这个目录也包含你的Linux发行版本的主 ...

  5. Android系统目录结构详解

    Android系统基于linux内核.JAVA应用,算是一个小巧精致的系统.虽是开源,但不像Linux一般庞大,娇小可亲,于是国内厂商纷纷开发出自己基于Android的操作系统.在此呼吁各大厂商眼光放 ...

  6. Linux文件系统的目录结构详解(转)

    Linux文件系统的目录结构详解(转) 原文链接https://www.cnblogs.com/cyjaysun/p/4462325.html 一.前 言 文章对Linux下所有目录一一说明,对比较重 ...

  7. Windows GPT磁盘GUID结构详解

    前一篇 Windows磁盘MBR结构详解 中我们介绍了Basic Disk中的Master Boot Record结构.GPT Disk作为Windows 2003以后引入的分区结构.使用了GUID分 ...

  8. TEXTMETRIC 结构详解

    TEXTMETRIC 结构详解 函数GetTextMetrics可以获取一个字体文本度量并将它放入一个类型为TEXTMETRIC的数据结构中,该结构如下所示: typedef struct ta TE ...

  9. 微信小程序01【目录结构详解、视图与渲染、事件、input、scroll-view】

    学习地址:https://www.bilibili.com/video/BV1sx411z77P 笔记01:https://blog.csdn.net/weixin_44949135/article/ ...

最新文章

  1. ELK性能优化实战分析
  2. 操作多台_一支热电偶能否连接多台显示仪表
  3. 向架构师进军--定义需求
  4. udp广播收到重复包
  5. 详解display:inline | block |inline-block的区别(转)
  6. mysql悲观锁隔离级别_mysql隔离级别与悲观锁、乐观锁
  7. 几何画板椭圆九种画法_椭圆的画法几何画板的动画演示
  8. Python爬虫之使用正则表达式匹配网页内容
  9. [x y w h]转化为[ymin xmin ymax xmax]
  10. angular中的?:什么意思
  11. matlab函数exp,Matlab基本函数-exp函数
  12. 具统计全国淘宝村增至211个 直接就业超过28万人
  13. 【图结构】之图注意力网络GAT详解
  14. OECD富裕经济体系通胀飙升至 25 年高位-全球薪资停滞不前
  15. 两军交战在即,我却还在等妹纸脱衣服?!
  16. Linux命令之管道
  17. 大数据篇(六) Spark Stream简介
  18. oracle数据库归档闪回,oracle数据库开归档闪回模式
  19. jyzy noip模拟赛5.22-1,3
  20. 使用JMeter上传excel文件

热门文章

  1. C# OpenCvSharp 安讯士视频编码器
  2. “Error: Encountered an improper argument”的解决方法
  3. 笔记本蓝牙搜索不到设备解决方案
  4. Fritzing软件绘制Arduino面包板接线图传感器模块库文件272
  5. springboot 实训总结
  6. 2006-11随想录
  7. [python3]string字符串
  8. android 系统拍照 方向,Android 系统Camera拍照照片旋转
  9. springboot毕设项目威客任务平台系统nd882(java+VUE+Mybatis+Maven+Mysql)
  10. c语言机票座位预定系统_C++实现机票预订系统