HDFS之namenode与datanode理解

一、HDFS集群

  HDFS集群有两类节点以管理节点-工作节点模式运行,即一个namenode(管理节点)和多个datanode(工作节点)。namenode管理文件系统的命名空间。它维护着文件系统树及整棵树内的所有文件和目录。这些信息以两个文件形式永久保存在本地磁盘上:命名空间镜像文件和编辑日志文件。namenode也记录着每个文件中各个块所在的数据节点信息,但是它并不会永久保存块的位置信息,因为这些信息会在系统启动时根据数据节点信息重建。

[root@hadoop001 current]# pwd

#namenode中命名空间镜像文件和编辑日志文件位置:
/opt/module/hadoop-2.6.5/data/tmp/dfs/name/current
[root@hadoop001 current]# ll
total 1132

# fsimage开头的文件是命名空间镜像文件,edits开头的文件是编辑日志文件
-rw-r--r--. 1 root root   14971 Aug 14 20:47 edits_0000000000000000001-0000000000000000125
-rw-r--r--. 1 root root   26458 Aug 14 21:47 edits_0000000000000000126-0000000000000000344
-rw-r--r--. 1 root root    5712 Aug 14 22:48 edits_0000000000000000345-0000000000000000386
-rw-r--r--. 1 root root      42 Aug 14 23:48 edits_0000000000000000387-0000000000000000388
-rw-r--r--. 1 root root   11851 Aug 15 00:48 edits_0000000000000000389-0000000000000000484
-rw-r--r--. 1 root root   10530 Aug 15 01:49 edits_0000000000000000485-0000000000000000566
-rw-r--r--. 1 root root 1048576 Aug 15 01:49 edits_inprogress_0000000000000000567
-rw-r--r--. 1 root root    3929 Aug 15 00:48 fsimage_0000000000000000484
-rw-r--r--. 1 root root      62 Aug 15 00:48 fsimage_0000000000000000484.md5
-rw-r--r--. 1 root root    4470 Aug 15 01:49 fsimage_0000000000000000566
-rw-r--r--. 1 root root      62 Aug 15 01:49 fsimage_0000000000000000566.md5
-rw-r--r--. 1 root root       4 Aug 15 01:49 seen_txid
-rw-r--r--. 1 root root     207 Aug 14 19:59 VERSION

  客户端(client)代表用户通过与namenode和datanode交互来访问整个文件系统。客户端提供一个类似于POSIX(可移植操作系统界面)的文件系统接口,因此用户在编程时无需知道namenode和datanode也可实现其功能。
datanode是文件系统的工作节点。它们根据需要存储并检检索数据块(受客户端或namenode调度),并且定期向namenode发送它们所存储的块的列表。

  没有namenode, 文件系统将无法使用。事实上,如果运行namenode 服务的机器毁坏,文件系统上所有的文件将会丟失,因为我们不知道如何根据datanode 的块重建文件。因此,对namenode实现容错非常重要,Hadoop 为此提供两种机制。

  • 第一种机制是备份那些组成文件系统元数据持久状态的文件。Hadoop可以通过配置使namenode在多个文件系统上保存元数据的持久状态。这些写操作是实时同步的,且是原子操作。一般的配置是,将持久状态写入本地磁盘的同时,写入一个远程挂载的网络文件系统(NFS)。
  • 另一种可行的方法是运行一个辅助namenode,但它不能被用作namenode。这个辅助namenode的重要作用是定期合并编辑日志与命名空间镜像,以防止编辑日志过大。这个辅助namenode一般在另一台单独的物理计算机上运行,因为它需要占用大量CPU时间,并且需要与namenode一样多的内存来执行合并操作。它会保存合并后的命名空间镜像的副本,并在namenode 发生故障时启用。但是,辅助namenode保存的状态总是滞后于主节点,所以在主节点全部失效时,难免会丢失部分数据。在这种情况下,一般把存储在 NFS上的namenode元数据复制到辅助namenode并作为新的主namenode 运行。

二、namenode

  namenode的目录结构:

[root@hadoop001 name]# pwd
/opt/module/hadoop-2.6.5/data/tmp/dfs/name
[root@hadoop001 name]# tree
.
├── current
│   ├── edits_0000000000000000001-0000000000000000125
│   ├── edits_0000000000000000126-0000000000000000344
│   ├── edits_0000000000000000345-0000000000000000386
│   ├── edits_0000000000000000387-0000000000000000388
│   ├── edits_0000000000000000389-0000000000000000484
│   ├── edits_0000000000000000485-0000000000000000566
│   ├── edits_0000000000000000567-0000000000000000568
│   ├── edits_inprogress_0000000000000000569
│   ├── fsimage_0000000000000000566
│   ├── fsimage_0000000000000000566.md5
│   ├── fsimage_0000000000000000568
│   ├── fsimage_0000000000000000568.md5
│   ├── seen_txid
│   └── VERSION
└── in_use.lock

  namenode的文件目录可以在core-site.xml中设置:

<property>
    
    <name>hadoop.tmp.dirname>
    <value>/opt/module/hadoop-2.6.5/data/tmpvalue>
property>

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

[root@hadoop001 current]# vi VERSION
#Tue Aug 14 19:59:14 PDT 2018
namespaceID=672644148
clusterID=CID-c49b4913-f14f-43d2-bffd-740d6021cc3c
cTime=0
storageType=NAME_NODE
blockpoolID=BP-1958150420-192.168.170.131-1534301954910
layoutVersion=-60
  • layoutVersion是一个负整数,描述HDFS持久性数据结构的版本,但是改版本号与Hadoop发布的包的版本无关。只要
    布局变更,版本号就会递减。
  • namespaceID是文件系统命名空间的唯一标识符,是在namenode首次格式化时创建的。
  • clusterID是将HDFS集群作为一个整体赋予的唯一标识符,当一个集群拥有多个namenode时,数值相同。
  • blockpoolID是数据块池的唯一标识符,数据块池中包含由一个namenode管理的命名空间中的所有文件。
  • cTime属性标记了namenode存储系统的创建时间。对于刚刚格式化的文件系统,这个属性值为0,但是文件系统升级后,改值会更新到新的时间戳。
  • storageType属性说明该存储目录包含的是namenode的数据结构。

in_use_lock文件是一个锁文件,namenode使用该文件为存储目录加锁。可以避免其他namenode实例同时使用同一个存储目录的情况。

文件系统映像和编辑日志

文件系统客户端执行写操作时,这些食物首先被记录到编辑日志中。namenode在内存中维护文件系统的元数据;当编辑日志被修改时,相关元数据信息也同步更新。内存中的元数据可以支持客户端的读请求。

  • 编辑日志(edits_xxx)在概念上是单体的,但是它在磁盘的体现是多个文件,每个文件被称为一个“段”,名称由前缀edits及后缀组成,后缀指出该文件所包含的事务id。任一时刻只有一个文件处于打开可写状态(表现为:edits_inprogress_xxx开头),每个事务完成之后,且在客户端发送成功代码之前,文件都需要更新和同步。当namenode向多个目录写数据时,只有在所有写操作都更新并同步到每个副本之后方可返回成功代码。

  • 文件系统映像(fsimage_xxx)都是文件系统元数据的一个完整的永久性检查点,并非每一个写操作都会更新该文件,因为fsimage是一个大型文件,如果频繁的读写会使系统运行缓慢。但是这个特性不会降低系统的恢复能力,如果namenode发生故障,还是需要将最近的fsimage文件读入内存来重构元数据的最近状态,再从相关点开始向前执行编辑日志中记录的每个事务。

HDFS之namenode与datanode理解_第1张图片

因为编辑日志和映像文件需要合并,而在同一namenode来执行合并操作会耗费大量内存和计算能力,所以一般合并操作会在另一台机器上(SecondaryNamenode),即辅助节点,使用辅助节点来创建检查点:

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

辅助检查点的触发条件一般受两个配置参数控制。默认情况下,

  • 辅助namenode每隔一小时创建检查点
  • 从上一检查点开始编辑日志的大小已经达到100万个事务

可以使用以下配置进行更改:
hdfs-site.xml


  dfs.namenode.checkpoint.period
      <value>3600value> #单位:秒
  The number of seconds between two periodic checkpoints.
  


  dfs.namenode.checkpoint.txns
  <value>1000000value> # edits事务数量
  The Secondary NameNode or CheckpointNode will create a checkpoint
  of the namespace every 'dfs.namenode.checkpoint.txns' transactions, regardless
  of whether 'dfs.namenode.checkpoint.period' has expired.
  

安全模式

  namenode启动时,首先将映像文件fsimage载入内存,并执行编辑日志edits中的各项编辑操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个新的fsimage和空的编辑日志。在这个过程中,namenode运行在安全模式。意味着namenode的文件系统对客户端来说是只读的。
(严格来说,在安全模式下,在访问元数据可以成功,对于读文件来说,只有集群中当前datanode上的块可用时,才能读)

安全模式的命令
检查是否处于安全模式:

[root@hadoop001 name]# hdfs dfsadmin -safemode get
Safe mode is OFF

在脚本中用户希望在执行某条命令之前namenode先退出安全模式:

[root@hadoop001 name]# hdfs dfsadmin -safemode wait

立即进入安全模式:

[root@hadoop001 name]# hdfs dfsadmin -safemode enter
Safe mode is ON

离开安全模式:

[root@hadoop001 name]# hdfs dfsadmin -safemode leave
Safe mode is OFF

安全模式的属性
HDFS之namenode与datanode理解_第2张图片

Namenode多目录配置
namenode的本地目录可以配置成多个,且每个目录存放内容相同,增加了可靠性。

具体配置如下:
hdfs-site.xml


    dfs.namenode.name.dir
file:///${hadoop.tmp.dir}/dfs/name1,file:///${hadoop.tmp.dir}/dfs/name2

三、datanode

工作机制

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

数据完整性

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

掉线时限参数设置

    datanode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。HDFS默认的超时时长为10分钟+30秒。如果定义超时时间为timeout,则超时时长的计算公式为:
      timeout = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval。
而默认的dfs.namenode.heartbeat.recheck-interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。
需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。

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

DataNode的目录结构

[root@hadoop001 data]# tree
.
├── current
│   ├── BP-1958150420-192.168.170.131-1534301954910
│   │   ├── current
│   │   │   ├── finalized
│   │   │   │   └── subdir0
│   │   │   │       └── subdir0
│   │   │   │           ├── blk_1073741825
│   │   │   │           ├── blk_1073741825_1001.meta
│   │   │   │           ├── blk_1073741826
│   │   │   │           ├── blk_1073741826_1002.meta
│   │   │   │           ├── blk_1073741833
│   │   │   │           ├── blk_1073741833_1009.meta
│   │   │   │           ├── blk_1073741834
│   │   │   │           ├── blk_1073741834_1010.meta
│   │   │   │           ├── blk_1073741836
│   │   │   │           ├── blk_1073741836_1012.meta
│   │   │   │           ├── blk_1073741837
│   │   │   │           ├── blk_1073741837_1013.meta
│   │   │   │           ├── blk_1073741838
│   │   │   │           ├── blk_1073741838_1014.meta
│   │   │   │           ├── blk_1073741839
│   │   │   │           ├── blk_1073741839_1015.meta
│   │   │   │           ├── blk_1073741846
│   │   │   │           ├── blk_1073741846_1022.meta
│   │   │   │           ├── blk_1073741847
│   │   │   │           ├── blk_1073741847_1023.meta
│   │   │   │           ├── blk_1073741848
│   │   │   │           ├── blk_1073741848_1024.meta
│   │   │   │           ├── blk_1073741849
│   │   │   │           ├── blk_1073741849_1025.meta
│   │   │   │           ├── blk_1073741850
│   │   │   │           ├── blk_1073741850_1026.meta
│   │   │   │           ├── blk_1073741859
│   │   │   │           ├── blk_1073741859_1035.meta
│   │   │   │           ├── blk_1073741860
│   │   │   │           ├── blk_1073741860_1036.meta
│   │   │   │           ├── blk_1073741861
│   │   │   │           ├── blk_1073741861_1037.meta
│   │   │   │           ├── blk_1073741870
│   │   │   │           ├── blk_1073741870_1046.meta
│   │   │   │           ├── blk_1073741871
│   │   │   │           ├── blk_1073741871_1047.meta
│   │   │   │           ├── blk_1073741872
│   │   │   │           ├── blk_1073741872_1048.meta
│   │   │   │           ├── blk_1073741873
│   │   │   │           ├── blk_1073741873_1049.meta
│   │   │   │           ├── blk_1073741874
│   │   │   │           ├── blk_1073741874_1050.meta
│   │   │   │           ├── blk_1073741881
│   │   │   │           ├── blk_1073741881_1057.meta
│   │   │   │           ├── blk_1073741882
│   │   │   │           ├── blk_1073741882_1058.meta
│   │   │   │           ├── blk_1073741883
│   │   │   │           ├── blk_1073741883_1059.meta
│   │   │   │           ├── blk_1073741884
│   │   │   │           ├── blk_1073741884_1060.meta
│   │   │   │           ├── blk_1073741891
│   │   │   │           ├── blk_1073741891_1067.meta
│   │   │   │           ├── blk_1073741892
│   │   │   │           ├── blk_1073741892_1068.meta
│   │   │   │           ├── blk_1073741893
│   │   │   │           ├── blk_1073741893_1069.meta
│   │   │   │           ├── blk_1073741894
│   │   │   │           └── blk_1073741894_1070.meta
│   │   │   ├── rbw
│   │   │   └── VERSION
│   │   ├── dncp_block_verification.log.curr
│   │   ├── dncp_block_verification.log.prev
│   │   └── tmp
│   └── VERSION
└── in_use.lock

datanode的版本:

[root@hadoop001 current]# vi VERSION

#Tue Aug 14 20:00:18 PDT 2018
storageID=DS-4bc1a0a5-8c82-417a-830d-513ffffcb51f
clusterID=CID-c49b4913-f14f-43d2-bffd-740d6021cc3c
cTime=0
datanodeUuid=af344182-a7f0-4467-9d34-9f77cba81855
storageType=DATA_NODE
layoutVersion=-56

解释:

  • storageID:存储id号
  • clusterID集群id,全局唯一
  • cTime属性标记了datanode存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为0;但是在文件系统升级之后,该值会更新到新的时间戳。
  • datanodeUuid:datanode的唯一识别码
  • storageType:存储类型
  • layoutVersion是一个负整数。通常只有HDFS增加新特性时才会更新这个版本号。

查看BP-1958150420-192.168.170.131-1534301954910数据块的版本号:

[root@hadoop001 current]# cd BP-1958150420-192.168.170.131-1534301954910/current
[root@hadoop001 current]# vi VERSION

#Tue Aug 14 20:00:18 PDT 2018
namespaceID=672644148
cTime=0
blockpoolID=BP-1958150420-192.168.170.131-1534301954910
layoutVersion=-56

解释:

  • namespaceID:是datanode首次访问namenode的时候从namenode处获取的storageID对每个datanode来说是唯一的(但对于单个datanode中所有存储目录来说则是相同的),namenode可用这个属性来区分不同datanode。
  • cTime属性标记了datanode存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为0;但是在文件系统升级之后,该值会更新到新的时间戳。
  • blockpoolID:一个block pool id标识一个block pool,并且是跨集群的全局唯一。当一个新的Namespace被创建的时候(format过程的一部分)会创建并持久化一个唯一ID。在创建过程构建全局唯一的BlockPoolID比人为的配置更可靠一些。NN将BlockPoolID持久化到磁盘中,在后续的启动过程中,会再次load并使用。
  • layoutVersion是一个负整数。通常只有HDFS增加新特性时才会更新这个版本号。

增加新节点

    当集群达到瓶颈时,需要增加新的节点(这里使用虚拟机模拟)。

  • 在一台新的主机上做好准备,准备过程在我的之前的博客有:前往
  • 在namenode的hadoop目录下的etc/hadoop/下创建dfs.hosts文件,并添加主机名称(包括新增加的节点名称):
[root@hadoop001 hadoop]# pwd
/opt/module/hadoop-2.6.5/etc/hadoop
[root@hadoop001 hadoop]# touch dfs.hosts
[root@hadoop001 hadoop]# vim dfs.host

hadoop001
hadoop002
hadoop003
hadoop004
  • 在namenode的hdfs-site.xml配置文件中增加dfs.hosts属性
<property>
  <name>dfs.hostsname>
  /opt/module/hadoop-2.6.5/etc/hadoop/dfs.hosts
  Names a file that contains a list of hosts that are
  permitted to connect to the namenode. The full pathname of the file
  must be specified.  If the value is empty, all hosts are
  permitted.
property>
  • 刷新namenode
[root@hadoop001 hadoop]# hdfs dfsadmin -refreshNodes
Refresh nodes successful
  • 更新resourcemanager节点
[root@hadoop001 hadoop]# yarn rmadmin -refreshNodes
17/06/24 14:17:11 INFO client.RMProxy: Connecting to ResourceManager at hadoop002/192.168.170.1132:8033
  • 在namenode的slaves文件中增加新主机名称
  • 单独命令启动新的数据节点和节点管理器
[root@hadoop001 hadoop-2.6.5]# sbin/hadoop-daemon.sh start datanode
starting datanode, logging to /opt/module/hadoop-2.6.5/logs/hadoop-root-datanode-hadoop004.out
[root@hadoop001 hadoop-2.6.5]# sbin/yarn-daemon.sh start nodemanager
starting nodemanager, logging to /opt/module/hadoop-2.6.5/logs/yarn-root-nodemanager-hadoop004.out
  • 如果数据不均衡,可以用命令实现集群的再平衡
[root@hadoop001 sbin]# ./start-balancer.sh
starting balancer, logging to /opt/module/hadoop-2.6.5/logs/hadoop-root-balancer-hadoop002.out
Time Stamp               
Iteration#  Bytes Already Moved  Bytes Left To Move  Bytes Being Moved

删除数据节点

  • 在namenode的/opt/module/hadoop-2.6.5/etc/hadoop目录下创建dfs.hosts.exclude文件
[root@hadoop001 hadoop]# pwd
/opt/module/hadoop-2.6.5/etc/hadoop
[root@hadoop001 hadoop]# touch dfs.hosts.exclude
[root@hadoop001 hadoop]# vim dfs.hosts.exclude
hadoop004
  • 在namenode的hdfs-site.xml配置文件中增加dfs.hosts.exclude属性
<property>
  <name>dfs.hosts.excludename>
  /opt/module/hadoop-2.6.5/etc/hadoop/dfs.hosts.exclude
  Names a file that contains a list of hosts that are
  not permitted to connect to the namenode.  The full pathname of the
  file must be specified.  If the value is empty, no hosts are
  excluded.
property> 
  • 刷新namenode、刷新resourcemanager
[root@hadoop001 hadoop-2.6.5]# hdfs dfsadmin -refreshNodes
Refresh nodes successful
[root@hadoop001 hadoop-2.6.5]# yarn rmadmin -refreshNodes
17/06/24 14:55:56 INFO client.RMProxy: Connecting to ResourceManager at hadoop004/192.168.170.134:8033
  • 检查web浏览器,退役节点的状态为decommission in progress(退役中),说明数据节点正在复制块到其他节点。
    这里写图片描述
  • 等待退役节点状态为decommissioned(所有块已经复制完成),停止该节点及节点资源管理器。注意:如果副本数是3,服役的节点小于等于3,是不能退役成功的,需要修改副本数后才能退役。
    这里写图片描述
  • 停止节点的运行
[root@hadoop004 hadoop-2.6.5]# sbin/hadoop-daemon.sh stop datanode
stopping datanode
[root@hadoop004 hadoop-2.6.5]# sbin/yarn-daemon.sh stop nodemanager
stopping nodemanager
  • 从namenode的dfs.hosts文件中删除退役节点hadoop105
  • 刷新namenode,刷新resourcemanager
[root@hadoop001 hadoop-2.6.5]# hdfs dfsadmin -refreshNodes
Refresh nodes successful
[root@hadoop001 hadoop-2.6.5]# yarn rmadmin -refreshNodes
17/06/24 14:55:56 INFO client.RMProxy: Connecting to ResourceManager at hadoop004/192.168.170.134:8033
  • 从namenode的slave文件中删除退役节点hadoop004
  • 如果数据不均衡,可以用命令实现集群的再平衡

你可能感兴趣的:(hadoop)