HDFS 系列整理(全)

文章目录

1. HDFS 概念

1.1 概念

HDFS,它是一个文件系统,用于存储文件,通过目录树来定位文件

其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色

HDFS的设计适合一次写入,多次读出的场景,且不支持文件的修改,适合用来做数据分析,并不适合用来做网盘应用

1.2 组成

HDFS 集群包括,NameNode 和 DataNode 以及 Secondary Namenode

  1. NameNode 负责管理整个文件系统的元数据,以及每一个路径(文件)所对应的数据块信息
  2. DataNode 负责管理用户的文件数据块,每一个数据块都可以在多个 Datanode 上存储多个副本
  3. Secondary NameNode 用来监控 HDFS 状态的辅助后台程序,每隔一段时间获取 HDFS 元数据的快照

1.3 HDFS 文件块大小

HDFS 中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在 hadoop2.x 版本中是 128M,老版本中是 64M

HDFS 的块比磁盘的块大,其目的是为了最小化寻址开销

如果块设置得足够大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间

因而,传输一个由多个块组成的文件的时间取决于磁盘传输速率

如果寻址时间约为 10ms,而传输速率为 100MB/s,为了使寻址时间仅占传输时间的 1%,我们要将块大小设置约为100MB

块的大小:10ms100100M/s = 100M

2. HFDS命令行操作

2.1 基本语法

bin/hadoop fs 具体命令

2.2 参数大全

bin/hadoop fs

[-appendToFile <localsrc> ... <dst>]
[-cat [-ignoreCrc] <src> ...]
[-checksum <src> ...]
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-copyFromLocal [-f] [-p] <localsrc> ... <dst>]
[-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-count [-q] <path> ...]
[-cp [-f] [-p] <src> ... <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> ...]]
[-du [-s] [-h] <path> ...]
[-expunge]
[-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-getfacl [-R] <path>]
[-getmerge [-nl] <src> <localdst>]
[-help [cmd ...]]
[-ls [-d] [-h] [-R] [<path> ...]]
[-mkdir [-p] <path> ...]
[-moveFromLocal <localsrc> ... <dst>]
[-moveToLocal <src> <localdst>]
[-mv <src> ... <dst>]
[-put [-f] [-p] <localsrc> ... <dst>]
[-renameSnapshot <snapshotDir> <oldName> <newName>]
[-rm [-f] [-r|-R] [-skipTrash] <src> ...]
[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
[-setrep [-R] [-w] <rep> <path> ...]
[-stat [format] <path> ...]
[-tail [-f] <file>]
[-test -[defsz] <path>]
[-text [-ignoreCrc] <src> ...]
[-touchz <path> ...]
[-usage [cmd ...]]

2.3 常用命令实操

2.3.1 -help:输出这个命令参数

bin/hdfs dfs -help rm

2.3.2 -ls: 显示目录信息

hadoop fs -ls /

2.3.3 -mkdir: 在hdfs上创建目录

hadoop fs -mkdir -p /aaa/bbb/cc/dd

2.3.4 -moveFromLocal: 从本地剪切粘贴到hdfs

hadoop fs - moveFromLocal /home/hadoop/a.txt /aaa/bbb/cc/dd

2.3.5 -moveToLocal: 从hdfs剪切粘贴到本地

hadoop fs - moveToLocal /aaa/bbb/cc/dd /home/hadoop/a.txt

2.3.6 --appendToFile: 追加一个文件到已经存在的文件末尾

hadoop fs -appendToFile ./hello.txt /hello.txt

2.3.7 -cat: 显示文件内容

2.3.8 -tail: 显示一个文件的末尾

hadoop fs  -tail  /weblog/access_log.1

2.3.9 -text:以字符形式打印一个文件的内容

hadoop  fs  -text  /weblog/access_log.1

2.3.10 -chgrp 、-chmod、-chown: linux文件系统中的用法一样,修改文件所属权限

hadoop  fs  -chmod  666  /hello.txt
hadoop  fs  -chown  someuser:somegrp   /hello.txt

2.3.11 -copyFromLocal:从本地文件系统中拷贝文件到hdfs路径去

hadoop  fs  -copyFromLocal  ./jdk.tar.gz  /aaa/

2.3.12 -copyToLocal: 从hdfs拷贝到本地

hadoop fs -copyToLocal /aaa/jdk.tar.gz

2.3.13 -cp: 从hdfs的一个路径拷贝到hdfs的另一个路径

hadoop  fs  -cp  /aaa/jdk.tar.gz  /bbb/jdk.tar.gz.2

2.3.14 -mv: 在hdfs目录中移动文件

hadoop  fs  -mv  /aaa/jdk.tar.gz  /

2.3.15 -get: 等同于copyToLocal,就是从hdfs下载文件到本地

hadoop fs -get  /aaa/jdk.tar.gz

2.3.16 -getmerge: 合并下载多个文件,比如hdfs的目录 /aaa/下有多个文件:log.1, log.2,log.3,…

hadoop fs -getmerge /aaa/log.* ./log.sum

2.3.17 -put: 等同于copyFromLocal

hadoop  fs  -put  /aaa/jdk.tar.gz  /bbb/jdk.tar.gz.2

2.3.18 -rm: 删除文件或文件夹

hadoop fs -rm -r /aaa/bbb/

2.3.19 -rmdir: 删除空目录

hadoop fs -rmdir /aaa/bbb/ccc

2.3.20 -df: 统计文件系统的可用空间信息

hadoop  fs  -df  -h  /

2.3.21 -du: 统计文件夹的大小信息

hadoop  fs  -du  -s  -h /aaa/*

2.3.22 -count: 统计一个指定目录下的文件节点数量

hadoop fs -count /aaa/

2.3.23 -setrep: 设置hdfs中文件的副本数量

hadoop fs -setrep 3 /aaa/jdk.tar.gz

image

这里设置的副本数只是记录在 Namenode 的元数据中,是否真的会有这么多副本,还得看 Datanode 的数量

因为目前只有3台设备,最多也就3个副本,只有节点数的增加到10台时,副本数才能达到10

3. HDFS 数据流

3.1 HDFS 写数据流程

3.1.1 剖析文件写入

  1. Client 向 NameNode 通信请求上传文件,NameNode 检查目标文件是否已经存在,父目录是否已经存在

  2. NameNode 返回是否可以上传

  3. Client 先对文件进行切分,请求第一个 block 该传输到哪些 DataNode 服务器上

  4. NameNode 返回3个 DataNode 服务器 DataNode 1,DataNode 2,DataNode 3

  5. Client 请求3台中的一台 DataNode 1(网络拓扑上的就近原则,如果都一样,则随机挑选一台DataNode)上传数据(本质上是一个RPC调用,建立pipeline),DataNode 1 收到请求会继续调用 DataNode 2,然后 DataNode 2 调用 DataNode 3,将整个 pipeline 建立完成,然后逐级返回客户端

  6. Client 开始往 DataNode 1 上传第一个 block (先从磁盘读取数据放到一个本地内存缓存),以 packet 为单位。写入的时候 DataNode 会进行数据校验,它并不是通过一个 packet 进行一次校验而是以 chunk 为单位进行校验(512byte)。DataNode 1 收到一个 packet 就会传给 DataNode 2,DataNode 2 传给 DataNode 3,DataNode 1 每传一个 packet 会放入一个应答队列等待应答

  7. 当一个 block 传输完成之后,Client 再次请求 NameNode 上传第二个block的服务器

3.1.2 网络拓扑概念

在本地网络中,两个节点被称为“彼此近邻”是什么意思?

在海量数据处理中,其主要限制因素是节点之间数据的传输速率——带宽很稀缺

这里的想法是将两个节点间的带宽作为距离的衡量标准

节点距离:两个节点到达最近的共同祖先的距离总和

例如,假设有 数据中心d1 机架r1 中的节点 n1,该节点可以表示为/d1/r1/n1,利用这种标记,这里给出四种距离描述:

Distance(/d1/r1/n1, /d1/r1/n1)=0(同一节点上的进程)
Distance(/d1/r1/n1, /d1/r1/n2)=2(同一机架上的不同节点)
Distance(/d1/r1/n1, /d1/r3/n2)=4(同一数据中心不同机架上的节点)
Distance(/d1/r1/n1, /d2/r4/n2)=6(不同数据中心的节点)

image

3.1.3 机架感知(副本节点选择)

官方介绍:

http://hadoop.apache.org/docs/r2.7.3/hadoop-project-dist/hadoop-common/RackAwareness.html
http://hadoop.apache.org/docs/r2.7.3/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html#Data_Replication
3.1.3.1 低版 本Hadoop 副本节点选择

第一个副本在 Client 所处的节点上,如果客户端在集群外,随机选一个

第二个副本和第一个副本位于不相同机架的随机节点上

第三个副本和第二个副本位于相同机架,节点随机

image

3.1.3.2 Hadoop 2.9.2 副本节点选择

第一个副本在 Client 所处的节点上,如果客户端在集群外,随机选一个。

第二个副本和第一个副本位于相同机架,随机节点

第三个副本位于不同机架,随机节点

image

3.2 HDFS 读数据流程

  1. 与 NameNode 通信查询元数据,找到文件块所在的 DataNode 服务器

  2. 挑选一台 DataNode(网络拓扑上的就近原则,如果都一样,则随机挑选一台 DataNode)服务器,请求建立 socket 流

  3. DataNode 开始发送数据(从磁盘里面读取数据放入流, packet(一个 packet 为64kb)为单位来做校验)

  4. 客户端以 packet 为单位接收,先在本地缓存,然后写入目标文件

image

4. NameNode 工作机制

4.1 NameNode、Fsimage 、Edits 和 SecondaryNameNode 概述

NameNode:在内存中储存 HDFS 文件的元数据信息(目录)

如果节点故障或断电,存在内存中的数据会丢失,显然只在内存中保存是不可靠的

实际在磁盘当中也有保存:Fsimage 和 Edits,一个 NameNode 节点在重启后会根据这磁盘上的这两个文件来恢复到之前的状态

Fsimage(镜像文件) 和 Edits(编辑日志):记录内存中的元数据

如果每次对 HDFS 的操作都实时的把内存中的元数据信息往磁盘上传输,这样显然效率不够高,也不稳定

这时就出现了 Edits 文件,用来记录每次对 HDFS 的操作,这样在磁盘上每次就只用做很小改动(只进行追加操作)

当 Edits 文件达到了一定大小或过了一定的时间,就需要把 Edits 文件转化 Fsimage 文件,然后清空 Edits

这样的 Fsimage 文件不会和内存中的元数据实时同步,需要加上 Edits 文件才相等

SecondaryNameNode:负责 Edits 转化成 Fsimage

SecondaryNameNode 不是 NameNode 的备份

SecondaryNameNode 会定时定量的把集群中的 Edits 文件转化为 Fsimage 文件,来保证 NameNode 中数据的可靠性

4.2 NameNode & Secondary NameNode 工作机制

image

4.2.1 第一阶段:Namenode 启动

  1. 第一次启动 Namenode 格式化后,创建 fsimage 和 edits 文件,如果不是第一次启动,直接加载编辑日志和镜像文件到内存

  2. 客户端对元数据进行增删改的请求

  3. Namenode 记录操作日志,追加滚动日志

  4. Namenode 在内存中对数据进行增删改查

4.2.2 第二阶段:Secondary NameNode 工作

  1. Secondary NameNode 询问 Namenode 是否需要checkpoint,直接带回 Namenode 是否检查结果

  2. Secondary NameNode 请求执行 checkpoint

  3. Namenode 滚动正在写的 edits 日志

  4. 将滚动前的编辑日志和镜像文件拷贝到 Secondary NameNode

  5. Secondary NameNode 加载编辑日志和镜像文件到内存,并合并

  6. 生成新的镜像文件 fsimage.chkpoint

  7. 拷贝 fsimage.chkpoint 到 Namenode

  8. Namenode 将 fsimage.chkpoint 重新命名成 fsimage

4.2.3 web 端访问 SecondaryNameNode

  1. 启动集群

  2. 浏览器中输入:http://slave1:50090/status.html

  3. 查看 SecondaryNameNode 信息

4.2.4 chkpoint检查时间参数设置

[hdfs-default.xml]

  1. 通常情况下,SecondaryNameNode 每隔一小时执行一次
<property>
    <name>dfs.namenode.checkpoint.period</name>
    <value>3600</value>
</property>
  1. 一分钟检查一次操作次数,当操作次数达到一百万时,SecondaryNameNode执行一次。
<property>
    <name>dfs.namenode.checkpoint.txns</name>
    <value>1000000</value>
    <description>操作动作次数</description>
</property>
<property>
    <name>dfs.namenode.checkpoint.check.period</name>
    <value>60</value>
    <description> 1分钟检查一次操作次数</description>
</property>

4.3 镜像文件和编辑日志文件

4.3.1 概念

Namenode 被格式化之后,将在 /usr/local/hadoop/tmp/dfs/name/current 目录中产生如下文件:

image

edits_0000000000000000000
fsimage_0000000000000000000.md5
seen_txid
VERSION

  1. Fsimage文件:HDFS 文件系统元数据的一个永久性的检查点,其中包含 HDFS 文件系统的所有目录和文件 idnode 的序列化信息

  2. Edits文件:存放 HDFS 文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到 edits 文件中

  3. seen_txid 文件:保存的是一个数字,就是最后一个 edits_ 的数字

  4. 每次 Namenode 启动的时候都会将 fsimage 文件读入内存,并从 00001 开始到 seen_txid 中记录的数字依次执行每个 edit s里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成Namenode启动的时候就将 fsimage 和 edits 文件进行了合并

4.3.2 oiv 查看 fsimage 文件

  1. 查看 oiv 和 oev 命令
[root@master current]$ hdfs
oiv	apply the offline fsimage viewer to an fsimage
oev	apply the offline edits viewer to an edits file
  1. 基本语法

hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径

  1. 案例实操
[root@master current]# pwd
/usr/local/hadoop/tmp/dfs/name/current

[root@master current]# hdfs oiv -p XML -i fsimage_0000000000000002141 -o /usr/hadoop/fsimage.xml
20/03/04 20:44:45 INFO offlineImageViewer.FSImageHandler: Loading 5 strings

[root@master current]# cat /usr/hadoop/fsimage.xml

将显示的 xml 文件内容格式化 查看 (可看到 Hdfs 上各个文件目录信息)

4.3.3 oev 查看 edits 文件

  1. 基本语法

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

  1. 案例实操
[root@master current]# hdfs oev -p XML -i edits_0000000000000002491-0000000000000002492 -o /usr/hadoop/edits.xml
[root@master current]# cat /usr/hadoop/edits.xml

将显示的 xml 文件内容格式化 查看

4.4 滚动编辑日志

正常情况 HDFS 文件系统有更新操作时,就会滚动编辑日志,也可以用命令强制滚动编辑日志

  1. 滚动编辑日志(前提必须启动集群)
[root@master current]# hdfs dfsadmin -rollEdits
Successfully rolled edit logs.
New segment starts at txid 2507
  1. 镜像文件什么时候产生

Namenode 启动时加载镜像文件和编辑日志

image

4.5 Namenode 版本号

4.5.1 查看 Namenode 版本号

在 /usr/local/hadoop/tmp/dfs/name/current 这个目录下查看 VERSION

[root@master current]# cat VERSION 
#Wed Mar 04 17:53:02 CST 2020
namespaceID=866472014
clusterID=CID-f383d6c4-da30-47c7-beb6-02c589c47f27
cTime=1582684942545
storageType=NAME_NODE
blockpoolID=BP-116957957-192.168.27.101-1582684942545
layoutVersion=-63

4.5.2 Namenode 版本号具体解释

  1. NamespaceID 在 HDFS 上,会有多个 Namenode,所以不同 Namenode 的 namespaceID 是不同的,分别管理一组 blockpoolID

  2. clusterID 集群id,全局唯一

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

  4. storageType 属性说明该存储目录包含的是 Namenode 的数据结构

  5. blockpoolID:一个 blockpoolid 标识一个 block pool,并且是跨集群的全局唯一。当一个新的 Namespace 被创建的时候(format过程的一部分)会创建并持久化一个唯一ID。在创建过程构建全局唯一的 BlockPoolID 比人为的配置更可靠一些。NN 将 BlockPoolID 持久化到磁盘中,在后续的启动过程中,会再次load并使用

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

4.6 SecondaryNameNode 目录结构

Secondary NameNode 用来监控 HDFS 状态的辅助后台程序,每隔一段时间获取 HDFS 元数据的快照

在 slave2 机器上的 /usr/local/hadoop/tmp/dfs/namesecondary/current 这个目录中查看 SecondaryNameNode 目录结构

[root@slave1 current]# pwd
/usr/local/hadoop/tmp/dfs/namesecondary/current
[root@slave1 current]# ll
total 1060
-rw-r--r--. 1 root root 1048576 Mar  4 23:05 edits_0000000000000002749-0000000000000002749
-rw-r--r--. 1 root root      42 Mar  4 23:05 edits_0000000000000002750-0000000000000002751
-rw-r--r--. 1 root root      42 Mar  5 15:21 edits_0000000000000002781-0000000000000002782
-rw-r--r--. 1 root root    4115 Mar  5 15:21 fsimage_0000000000000002780
-rw-r--r--. 1 root root      62 Mar  5 15:21 fsimage_0000000000000002780.md5
-rw-r--r--. 1 root root    4115 Mar  5 15:21 fsimage_0000000000000002782
-rw-r--r--. 1 root root      62 Mar  5 15:21 fsimage_0000000000000002782.md5
-rw-r--r--. 1 root root     217 Mar  5 15:21 VERSION

SecondaryNameNode 的 namesecondary/current 目录和主 Namenode 的 current 目录的布局相同

好处:在主 Namenode 发生故障时(假设没有及时备份数据),可以从 SecondaryNameNode 恢复数据

4.6.1 Namenode 故障恢复方法一

将 SecondaryNameNode 中数据拷贝到 Namenode 存储数据的目录

案例实操:模拟 Namenode 故障,并采用方法一,恢复 Namenode 数据

  1. kill -9 namenode 进程 (-9 表示无条件终止)

  2. 删除 Namenode 存储的数据 (/usr/local/hadoop/tmp/dfs/name)

    rm -rf /usr/local/hadoop/tmp/dfs/name/*
    

    打开 http://master:50070/ 无法访问

  3. 拷贝 SecondaryNameNode 中数据到原 Namenode 存储数据目录

    [root@slave1 dfs]# scp -r /usr/local/hadoop/tmp/dfs/namesecondary/* master:/usr/local/hadoop/tmp/dfs/name/
    edits_0000000000000002749-0000000000000002749                100% 1024KB   1.0MB/s   00:00    
    edits_0000000000000002750-0000000000000002751                100%   42     0.0KB/s   00:00    
    VERSION                                                      100%  217     0.2KB/s   00:00    
    fsimage_0000000000000002780.md5                              100%   62     0.1KB/s   00:00    
    fsimage_0000000000000002780                                  100% 4115     4.0KB/s   00:00    
    edits_0000000000000002781-0000000000000002782                100%   42     0.0KB/s   00:00    
    fsimage_0000000000000002782.md5                              100%   62     0.1KB/s   00:00    
    fsimage_0000000000000002782                                  100% 4115     4.0KB/s   00:00    
    in_use.lock
    
  4. 重新启动 Namenode

    sbin/hadoop-daemon.sh start namenode
    

    打开 http://master:50070/ 可以访问,并可操作 Hdfs

4.6.2 Namenode 故障恢复方法二

使用 -importCheckpoint 选项启动 Namenode 守护进程,从而将 SecondaryNameNode 用作新的主 Namenode

案例实操:模拟 Namenode 故障,并采用方法二,恢复 Namenode 数据

  1. 修改 hdfs-site.xml 中的

    <property>
        <name>dfs.namenode.checkpoint.period</name>
        <value>120</value>
    </property>
    
  2. kill -9 namenode进程

  3. 删除 Namenode 存储的数据(/usr/local/hadoop/tmp/dfs/name)

    rm -rf /usr/local/hadoop/tmp/dfs/name/*
    

    打开 http://master:50070/ 无法访问

  4. 如果 SecondaryNameNode 不和 Namenode 在一个主机节点上,需要将 SecondaryNameNode 存储数据的目录拷贝到 Namenode 存储数据的平级目录

    [root@master dfs]# pwd
    /usr/local/hadoop/tmp/dfs
    [root@master dfs]# ls
    name  namesecondary
    
  5. 导入检查点数据(等待一会 ctrl+c 结束掉)

    bin/hdfs namenode -importCheckpoint
    
  6. 启动 Namenode

    sbin/hadoop-daemon.sh start namenode
    
  7. 如果提示文件锁了,可以删除 in_use.lock

    rm -rf /usr/local/hadoop/tmp/dfs/namesecondary/in_use.lock
    

4.7 集群安全模式操作

4.7.1 概述

Namenode 启动时,首先将映像文件(fsimage)载入内存,并执行编辑日志(edits)中的各项操作

一旦在内存中成功建立文件系统元数据的映像,则创建一个新的 fsimage 文件和一个空的编辑日志,此时 Namenode 开始监听 Datanode 请求

但是此刻,Namenode 运行在安全模式,即 Namenode 的文件系统对于客户端来说是只读的

系统中的数据块的位置并不是由 Namenode 维护的,而是以块列表的形式存储在 Datanode 中

在系统的正常操作期间,Namenode 会在内存中保留所有块位置的映射信息

在安全模式下,各个 Datanode 会向 Namenode 发送最新的块列表信息,Namenode 了解到足够多的块位置信息之后,即可高效运行文件系统

如果满足“最小副本条件”,Namenode 会在30秒钟之后就退出安全模式

所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1)

在启动一个刚刚格式化的 HDFS 集群时,因为系统中还没有任何块,所以 Namenode 不会进入安全模式

4.7.2 基本语法

集群处于安全模式,不能执行重要操作(写操作),集群启动完成后,自动退出安全模式。

  1. bin/hdfs dfsadmin -safemode get (功能描述:查看安全模式状态)
  2. bin/hdfs dfsadmin -safemode enter (功能描述:进入安全模式状态)
  3. bin/hdfs dfsadmin -safemode leave (功能描述:离开安全模式状态)
  4. bin/hdfs dfsadmin -safemode wait (功能描述:等待安全模式状态)

4.7.3 案例

模拟等待安全模式

  1. 先进入安全模式

    bin/hdfs dfsadmin -safemode enter
    

    安全模式下只可查看 Hdfs 文件,无法新增、删除

  2. 执行下面的脚本

    编辑一个脚本

    #!/bin/bash
    bin/hdfs dfsadmin -safemode wait
    bin/hdfs dfs -put ~/hello.txt /root/hello.txt
    
  3. 再打开一个窗口,执行

    bin/hdfs dfsadmin -safemode leave
    

4.8 Namenode 多目录配置

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

具体配置如下:

[hdfs-site.xml]

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

5. DataNode 工作机制

5.1 DataNode工作机制

image

  1. 一个数据块在 Datanode 上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳

  2. DataNode 启动后向 Namenode 注册,通过后,周期性(1小时)的向 Namenode 上报所有的块信息

  3. 心跳是每 3 秒一次,心跳返回结果带有 Namenode 给该 DataNode 的命令如复制块数据到另一台机器,或删除某个数据块。如果超过 10 分钟没有收到某个 DataNode 的心跳,则认为该节点不可用

  4. 集群运行中可以安全加入和退出一些机器

5.2 数据完整性

  1. 当 DataNode 读取 block 的时候,它会计算 checksum

  2. 如果计算后的 checksum,与 block 创建时值不一样,说明 block 已经损坏

  3. client 读取其他 DataNode 上的 block.

  4. DataNode 在其文件创建后周期验证 checksum

5.3 掉线时限参数设置

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-interval</name>
    <value>300000</value>
</property>
<property>
    <name> dfs.heartbeat.interval </name>
    <value>3</value>
</property>

5.4 DataNode 的目录结构

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

5.4.1 查看 DataNode 的版本号

在 /usr/local/hadoop/tmp/dfs/data/current 这个目录下查看版本号

[root@slave1 current]# cat VERSION 
#Fri Mar 06 16:58:36 CST 2020
storageID=DS-7908c807-e3ec-4b85-952a-922ba8d3a24f
clusterID=CID-f383d6c4-da30-47c7-beb6-02c589c47f27
cTime=0
datanodeUuid=f230ca32-5797-4949-b996-95bf66a25a0d
storageType=DATA_NODE
layoutVersion=-57

5.4.2 DataNode 版本号具体解释

  1. storageID:存储id号

  2. clusterID:集群id,全局唯一

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

  4. datanodeUuid:Datanode 的唯一识别码

  5. storageType:存储类型

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

5.4.3 DataNode 数据块版本号

在 /usr/local/hadoop/tmp/dfs/data/current/BP-116957957-192.168.27.101-1582684942545/current 这个目录下查看该数据块的版本号

[root@slave1 current]# pwd
/usr/local/hadoop/tmp/dfs/data/current/BP-116957957-192.168.27.101-1582684942545/current
[root@slave1 current]# cat VERSION 
#Fri Mar 06 16:58:36 CST 2020
namespaceID=866472014
cTime=1582684942545
blockpoolID=BP-116957957-192.168.27.101-1582684942545
layoutVersion=-57

5.4.4 DataNode 数据块版本号的具体解释

  1. namespaceID:是 Datanode 首次访问 Namenode 的时候从 Namenode 处获取的 storageID; 对每个 Datanode 来说是唯一的(但对于单个 Datanode 中所有存储目录来说则是相同的),Namenode 可用这个属性来区分不同 Datanode

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

  3. blockpoolID:一个 block pool id 标识一个block pool,并且是跨集群的全局唯一;当一个新的 Namespace 被创建的时候(format过程的一部分)会创建并持久化一个唯一ID;在创建过程构建全局唯一的 lockPoolID 比人为的配置更可靠一些。Namenode 将 BlockPoolID 持久化到磁盘中,在后续的启动过程中,会再次 load 并使用

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

5.5 服役新数据节点

5.5.1 需求

随着公司业务的增长,数据量越来越大,原有的数据节点的容量已经不能满足存储数据的需求,需要在原有集群基础上动态添加新的数据节点

5.5.2 环境准备

  1. 克隆一台虚拟机(master -> slave3),并启动

    从 master 上克隆可节省文件同步的时间,否则需要重新安装、配置 JDK、Hadoop

  2. 修改 ip 地址为 192.168.27.104

  3. 修改 ip 映射(/etc/hosts),并在 master、slave1、slave2 上同步修改

    在 master、slave1、slave2 基础上新增 192.168.27.104 slave3

    192.168.27.101 master
    192.168.27.102 slave1
    192.168.27.103 slave2
    192.168.27.104 slave3
    
  4. 修改主机名

    hostnamectl set-hostname slave3
    
  5. 建立 master、slave1、slave2 和 slave3 之间的免密

    删除 slave3 下的 .ssh,重新生成公钥进行同步

以上五步可参考 Hadoop集群搭建-3

  1. 删除原来 HDFS 文件系统留存的文件

    从 master 上拷贝过来的 Hadoop 信息,清除 logs 和 data

    rm -rf /usr/hadoop/hadoop-2.9.2/logs /usr/local/hadoop/tmp/dfs/data
    

    因为 msater 上没跑 Datanode,所以 data 的目录可以不加

所有准备工作完备

5.5.3 服役新节点具体步骤

  1. 在 Namenode 的 ~/etc/hadoop 目录下创建 dfs.hosts 文件

    [root@master .ssh]# cd /usr/hadoop/hadoop-2.9.2/etc/hadoop/
    [root@master hadoop]# vim dfs.hosts
    

    添加如下主机名称(包含新服役的节点)

    master
    slave1
    slave2
    slave3
    
  2. 在 Namenode 的 hdfs-site.xml 配置文件中增加 dfs.hosts 属性

    <property>
        <name>dfs.hosts</name>
        <value>/usr/hadoop/hadoop-2.9.2/etc/hadoop/dfs.hosts</value>
    </property>
    
  3. 刷新 Namenode

    [root@master hadoop]# hdfs dfsadmin -refreshNodes
    Refresh nodes successful
    

    image

    新增了 master、slave3 的 Datanode 节点

  4. 更新 resourcemanager 节点

    [root@master hadoop]# yarn rmadmin -refreshNodes
    20/03/06 15:07:16 INFO client.RMProxy: Connecting to ResourceManager at master/192.168.27.101:8033
    
  5. 在 Namenode 的 slaves 文件中增加新主机名称

    增加 master、slave3 不需要分发

    master
    slave1
    slave2
    slave3
    
  6. 单独命令启动新的数据节点和节点管理器

    master、slave3 上都启动 Datanode 和 NodeManager

    [root@slave3 hadoop-2.9.2]# hadoop-daemon.sh start datanode
    starting datanode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-datanode-slave3.out
    [root@slave3 hadoop-2.9.2]# yarn-daemon.sh start nodemanager
    starting nodemanager, logging to /usr/hadoop/hadoop-2.9.2/logs/yarn-root-nodemanager-slave3.out
    
    [root@slave3 hadoop-2.9.2]# jps
    3154 DataNode
    3266 NodeManager
    3423 Jps
    

    确认 DataNode 和 NodeManager 进程已启动

  7. 在 web 浏览器上检查是否 ok

    image

    目前只启动了 slave3 节点上的 Datanode 和 NodeManager

5.5.4 集群再平衡

如果数据不均衡,可以用命令实现集群的再平衡

[root@slave1 .ssh]# start-balancer.sh
starting balancer, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-balancer-slave1.out
Time Stamp               Iteration#  Bytes Already Moved  Bytes Left To Move  Bytes Being Moved

重新配置 192.168.27.105 slave4,作为后续旧数据节点的退役

5.6 退役旧数据节点

此例退役上面刚服役的节点: 192.168.27.105 slave4

  1. 在 Namenode 的 ~/etc/hadoop 目录下创建 dfs.hosts.exclude 文件

    [root@master hadoop]# pwd
    /usr/hadoop/hadoop-2.9.2/etc/hadoop
    [root@master hadoop]# vim dfs.hosts.exclude
    

    添加如下主机名称(要退役的节点)

    slave4
    
  2. 在 Namenode 的 hdfs-site.xml 配置文件中增加 dfs.hosts.exclude 属性

    <property>
        <name>dfs.hosts.exclude</name>
        <value>/usr/hadoop/hadoop-2.9.2/etc/hadoop/dfs.hosts.exclude</value>
    </property>
    
  3. 刷新 Namenode、刷新 Resourcemanager

    [root@master hadoop]# hdfs dfsadmin -refreshNodes
    Refresh nodes successful
    [root@master hadoop]# yarn rmadmin -refreshNodes
    20/03/06 15:58:31 INFO client.RMProxy: Connecting to ResourceManager at master/192.168.27.101:8033
    
  4. 检查 web 浏览器,退役节点的状态 无(退役中),说明数据节点正在复制块到其他节点

    image

  5. 等待退役节点状态为 decommissioned(所有块已经复制完成),停止该节点及节点资源管理器

    image

    此时,slave4 上的 DataNode 和 NodeManager 进程仍在

    [root@slave4 hadoop]#  jps
    5232 NodeManager
    5563 Jps
    5116 DataNode
    

    注意:如果副本数是3,服役的节点小于等于3,是不能退役成功的,需要修改副本数后才能退役

    停止该节点及节点资源管理器

    [root@slave4 hadoop]# hadoop-daemon.sh stop datanode
    stopping datanode
    [root@slave4 hadoop]# yarn-daemon.sh stop nodemanager
    stopping nodemanager
    
  6. 从 include 文件中删除退役节点,再运行刷新节点的命令

    (1) 从 Namenode 的 dfs.hosts 文件中删除退役节点 slave4

     master
     slave1
     slave2
     slave3
    

    (2) 刷新 Namenode,刷新 Resourcemanager

    [root@master hadoop]# hdfs dfsadmin -refreshNodes
    Refresh nodes successful
    [root@master hadoop]# yarn rmadmin -refreshNodes
    20/03/06 17:11:21 INFO client.RMProxy: Connecting to ResourceManager at master/192.168.27.101:8033
    
  7. 从 Namenode 的 slave 文件中删除退役节点 hadoop105

    master
    slave1
    slave2
    slave3
    
  8. 如果数据不均衡,可以用命令实现集群的再平衡

    [root@master hadoop]# start-balancer.sh 
    starting balancer, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-balancer-master.out
    Time Stamp               Iteration#  Bytes Already Moved  Bytes Left To Move  Bytes Being Moved
    

5.7 Datanode 多目录配置

Datanode 也可以配置成多个目录,每个目录存储的数据不一样,即数据不是副本

具体配置如下:

[hdfs-site.xml]

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

6. HDFS 其他功能

6.1 集群间数据拷贝

  1. scp 实现两个远程主机之间的文件复制
scp -r hello.txt root@master:/user/wj/hello.txt		// 推 push
scp -r root@master:/user/wj/hello.txt  hello.txt		// 拉 pull
scp -r root@master:/user/wj/hello.txt root@master:/user/wj   //是通过本地主机中转实现两个远程主机的文件复制;如果在两个远程主机之间ssh没有配置的情况下可以使用该方式。
  1. 采用 discp 命令实现两个 Hadoop 集群之间的递归数据复制
bin/hadoop distcp hdfs://master1:9000/user/wj/hello.txt hdfs://master2:9000/user/wj/hello.txt

6.2 Hadoop 存档

6.2.1 理论概述

每个文件均按块存储,每个块的元数据存储在 Namenode 的内存中,因此 Hadoop 存储小文件会非常低效

因为大量的小文件会耗尽 Namenode 中的大部分内存

但注意,存储小文件所需要的磁盘容量和存储这些文件原始内容所需要的磁盘空间相比也不会增多

例如,一个 1MB 的文件以大小为 128MB 的块存储,使用的是 1MB 的磁盘空间,而不是128MB

Hadoop 存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入 HDFS 块,在减少 Namenode 内存使用的同时,允许对文件进行透明的访问

具体说来,Hadoop 存档文件可以用作 MapReduce 的输入

6.2.2 案例实操

  1. 需要启动 yarn 进程

    start-yarn.sh
    
  2. 归档文件

    归档成一个叫做 xxx.har 的文件夹,该文件夹下有相应的数据文件

    Xx.har目录是一个整体,该目录看成是一个归档文件即可

    bin/hadoop archive -archiveName myhar.har -p /user/wj   /user/my
    
  3. 查看归档

    hadoop fs -lsr /user/my/myhar.har
    hadoop fs -lsr har:///myhar.har
    
  4. 解归档文件

    hadoop fs -cp har:/// user/my/myhar.har /* /user/wj
    

6.3 快照管理

快照相当于对目录做一个备份,并不会立即复制所有文件,而是指向同一个文件

当写入发生时,才会产生新文件

6.3.1 基本语法

  1. hdfs dfsadmin -allowSnapshot 路径 (功能描述:开启指定目录的快照功能)

  2. dfs dfsadmin -disallowSnapshot 路径 (功能描述:禁用指定目录的快照功能,默认是禁用)

  3. hdfs dfs -createSnapshot 路径 (功能描述:对目录创建快照)

  4. hdfs dfs -createSnapshot 路径 名称 (功能描述:指定名称创建快照)

  5. hdfs dfs -renameSnapshot 路径 旧名称 新名称 (功能描述:重命名快照)

  6. hdfs lsSnapshottableDir (功能描述:列出当前用户所有可快照目录)

  7. hdfs snapshotDiff 路径1 路径2 (功能描述:比较两个快照目录的不同之处)

  8. hdfs dfs -deleteSnapshot (功能描述:删除快照)

6.3.2 案例实操

  1. 开启/禁用指定目录的快照功能

    hdfs dfsadmin -allowSnapshot /user/wj/data		
    hdfs dfsadmin -disallowSnapshot /user/wj/data
    
  2. 对目录创建快照

    hdfs dfs -createSnapshot /user/wj/data		// 对目录创建快照
    

    通过web访问hdfs://hadoop102:9000/user/wj/data/.snapshot/s……// 快照和源文件使用相同数据块

    hdfs dfs -lsr /user/wj/data/.snapshot/
    
  3. 指定名称创建快照

    hdfs dfs -createSnapshot /user/wj/data miao170508
    
  4. 重命名快照

    hdfs dfs -renameSnapshot /user/wj/data/ miao170508 wj111
    
  5. 列出当前用户所有可快照目录

    hdfs lsSnapshottableDir
    
  6. 比较两个快照目录的不同之处

    hdfs snapshotDiff /user/wj/data/  .  .snapshot/wj170508
    
  7. 恢复快照

    hdfs dfs -cp /user/wj/input/.snapshot/s20170708-134303.027 /user
    

6.4 回收站

6.4.1 默认回收站

默认值 fs.trash.interval=0,0 表示禁用回收站,可以设置删除文件的存活时间

默认值 fs.trash.checkpoint.interval=0,检查回收站的间隔时间

要求 fs.trash.checkpoint.interval <= fs.trash.interval

6.4.2 启用回收站

修改 core-site.xml,配置垃圾回收时间为 1 分钟

<property>
    <name>fs.trash.interval</name>
    <value>1</value>
</property>

6.4.3 查看回收站

回收站在集群中的路径:/user/wj/.Trash/….

6.4.4 修改访问垃圾回收站用户名称

进入垃圾回收站用户名称,默认是 dr.who,修改为 wj 用户

[core-site.xml]

<property>
  <name>hadoop.http.staticuser.user</name>
  <value>wj</value>
</property>

6.4.5 进入回收站

通过程序删除的文件不会经过回收站,需要调用 moveToTrash() 才进入回收站

Trash trash = New Trash(conf);
trash.moveToTrash(path);

6.4.6 恢复回收站数据

hadoop fs -mv /user/wj/.Trash/Current/user/wj/input    /user/wj/input

6.4.7清空回收站

hdfs dfs -expunge

文章目录

7. HDFS HA 高可用

7.1 HA 概述

所谓 HA(high available),即高可用(7*24小时不中断服务)

实现高可用最关键的策略是消除单点故障,HA 严格来说应该分成各个组件的 HA 机制:HDFS的HA 和 YARN的HA

Hadoop2.0 之前,在 HDFS 集群中 NameNode 存在单点故障(SPOF)

NameNode 主要在以下两个方面影响 HDFS 集群

1. NameNode 机器发生意外,如宕机,集群将无法使用,直到管理员重启
2. NameNode 机器需要升级,包括软件、硬件升级,此时集群也将无法使用

HDFS HA 功能通过配置 Active/Standby 两个 NameNodes 实现在集群中对 NameNode 的热备来解决上述问题

如果出现故障,如机器崩溃或机器需要升级维护,这时可通过此种方式将 NameNode 很快的切换到另外一台机器

注意:HDFS 配置 HA 后,SecondNamenode 的角色被备用 Namenode 所包含,备用 Namenode 为活动的 Namenode 命名空间设置周期性的检查点

7.2 HDFS-HA 工作机制

通过双 NameNode 消除单点故障

7.3 HDFS-HA 手动故障转移

7.3.1 HDFS-HA 工作要点

  1. 元数据管理方式需要改变:

    内存中各自保存一份元数据

    Edits 日志只有 Active 状态的 Namenode 节点可以做写操作

    两个 Namenode 都可以读取 edits

    共享的 edits 放在一个共享存储中管理(qjournal 和 NFS 两个主流实现)

  2. 需要一个状态管理功能模块

    实现了一个 zkfailover,常驻在每一个 Namenode 所在的节点,每一个 zkfailover 负责监控自己所在 Namenode 节点,利用 zk 进行状态标识,当需要进行状态切换时,由 zkfailover 来负责切换,切换时需要防止 brain split 现象的发生

  3. 必须保证两个 NameNode 之间能够 ssh 无密码登录

  4. 隔离(Fence),即同一时刻仅仅有一个 NameNode 对外提供服务

7.3.2 环境准备

将上面 master、slave1、slave2 三个机器克隆修改相关配置即可,要点如下:

  1. 修改 IP (可以保持不变)、主机名(改为 hadoop-1,hadoop-2,hadooop-3)

    hadoop-1 192.168.27.101
    hadoop-2 192.168.27.102
    hadoop-3 192.168.27.103
    
  2. 修改主机名及主机名和 IP 地址的映射

  3. 关闭防火墙

  4. ssh 免密登录

  5. 清空 Hadoop 的 data 和 logs

7.3.3 集群规划

hadoop-1hadoop-2hadooop-3
NameNodeNameNode-
JournalNodeJournalNodeJournalNode
DataNodeDataNodeDataNode
-ResourceManager-
NodeManagerNodeManagerNodeManager

7.3.4 配置 HDFS-HA 集群(以三台为例)

  1. 官方地址:https://hadoop.apache.org/docs/r2.9.2/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html

  2. 配置 core-site.xml

    <configuration>
        <!-- 把两个 NameNode 的地址组装成一个集群 mycluster -->
        <property>
            <name>fs.defaultFS</name>
            <value>hdfs://mycluster</value>
        </property>
    
        <!-- 声明 journalnode 服务本地文件系统存储目录-->
        <property>
            <name>dfs.journalnode.edits.dir</name>
            <value>/usr/local/hadoop/tmp/dfs/data/jn</value>
        </property>
    
        <!-- 指定 hadoop 运行时产生文件的存储目录(和之前一样) -->
        <property>
            <name>hadoop.tmp.dir</name>
            <value>/usr/hadoop/tmp</value>
        </property>
    </configuration>
    
  3. 配置 hdfs-site.xml

    <configuration>
    
        <!-- 完全分布式集群名称 -->
        <property>
            <name>dfs.nameservices</name>
            <value>mycluster</value>
        </property>
    
        <!-- 集群中 NameNode 节点都有哪些 -->
        <property>
            <name>dfs.ha.namenodes.mycluster</name>
            <value>nn1,nn2</value>
        </property>
    
        <!-- nn1 的 RPC 通信地址 -->
        <property>
            <name>dfs.namenode.rpc-address.mycluster.nn1</name>
            <value>hadoop-1:8020</value>
        </property>
    
        <!-- nn2 的 RPC 通信地址 -->
        <property>
            <name>dfs.namenode.rpc-address.mycluster.nn2</name>
            <value>hadoop-2:8020</value>
        </property>
    
        <!-- nn1 的 http 通信地址 -->
        <property>
            <name>dfs.namenode.http-address.mycluster.nn1</name>
            <value>hadoop-1:50070</value>
        </property>
    
        <!-- nn2 的 http 通信地址 -->
        <property>
            <name>dfs.namenode.http-address.mycluster.nn2</name>
            <value>hadoop-2:50070</value>
        </property>
    
        <!-- 指定 NameNode 元数据在 JournalNode 上的存放位置 -->
        <property>
            <name>dfs.namenode.shared.edits.dir</name>
            <value>qjournal://hadoop-1:8485;hadoop-2:8485;hadoop-3:8485/mycluster</value>
        </property>
    
        <!-- 配置隔离机制,即同一时刻只能有一台服务器对外响应 -->
        <property>
            <name>dfs.ha.fencing.methods</name>
            <value>sshfence</value>
        </property>
    
        <!-- 使用隔离机制时需要 ssh 无秘钥登录-->
        <property>
            <name>dfs.ha.fencing.ssh.private-key-files</name>
            <value>/root/.ssh/id_rsa</value>
        </property>
    
        <!-- 关闭权限检查-->
        <property>
            <name>dfs.permissions.enable</name>
            <value>false</value>
        </property>
    
        <!-- 访问代理类:client,mycluster,active 配置失败自动切换实现方式-->
        <property>
            <name>dfs.client.failover.proxy.provider.mycluster</name>
            <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
        </property>
    </configuration>
    
  4. 拷贝配置好的 hadoop 环境到其他节点

7.3.5 启动 HDFS-HA 集群

  1. 在各个 JournalNode 节点上,输入以下命令启动 JournalNode 服务

    [root@hadoop-1 hadoop]# hadoop-daemon.sh start journalnode
    starting journalnode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-journalnode-hadoop-1.out
    [root@hadoop-1 hadoop]# jps
    2709 Jps
    2648 JournalNode
    
    [root@hadoop-2 hadoop]# hadoop-daemon.sh start journalnode
    starting journalnode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-journalnode-hadoop-2.out
    [root@hadoop-2 hadoop]# jps
    2578 JournalNode
    2639 Jps
    
    [root@hadoop-3 hadoop]# hadoop-daemon.sh start journalnode
    starting journalnode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-journalnode-hadoop-3.out
    [root@hadoop-3 hadoop]# jps
    2946 JournalNode
    3007 Jps
    
  2. 在 [nn1] 上,对其进行格式化,并启动

    [root@hadoop-1 hadoop]# hdfs namenode -format
    
    [root@hadoop-1 hadoop]# hadoop-daemon.sh start namenode
    starting namenode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-namenode-hadoop-1.out
    

    目前 hadoop-1 已启动,为 standby 状态,如下图

    image

  3. 在 [nn2] 上,同步 nn1 的元数据信息

    [root@hadoop-2 hadoop]# hdfs namenode -bootstrapStandby
    

    可以从日志看出从 [nn1] 进行同步,如下图:

    image

  4. 启动 [nn2]

    [root@hadoop-2 hadoop]# hadoop-daemon.sh start namenode
    

    目前 hadoop-2 已启动,也为 standby 状态,如下图

    image

  5. 在 [nn1] 上,启动所有 Datanode

    [root@hadoop-1 .ssh]# hadoop-daemons.sh start datanode
    

    备注:hadoop-daemons 本质是到 slaves 文件中找所有 DataNode

    此时所有 Namenode 都是 standby 状态,不支持读文件

    image

  6. 将 [nn1] 切换为 Active

    [root@hadoop-1 .ssh]# hdfs haadmin -transitionToActive nn1
    
  7. 查看是否 Active

    [root@hadoop-1 .ssh]# hdfs haadmin -getServiceState nn1
    active
    

    image

7.3.6 HDFS-HA 集群手动故障转移

  1. 强杀 Active NameNode [nn1]

    [root@hadoop-1 hadoop]# jps
    4389 Jps
    2648 JournalNode
    3112 NameNode
    4091 DataNode
    [root@hadoop-1 hadoop]# kill -9 3112
    
  2. 手动 将 [nn2] 切为 Active

    [root@hadoop-1 hadoop]# hdfs haadmin -transitionToActive nn2
    
    20/03/07 16:49:45 INFO ipc.Client: Retrying connect to server: hadoop-1/192.168.27.101:8020. Already tried 0 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=1, sleepTime=1000 MILLISECONDS)
    Unexpected error occurred  Call From hadoop-1/192.168.27.101 to hadoop-1:8020 failed on connection exception: java.net.ConnectException: Connection refused; For more details see:  http://wiki.apache.org/hadoop/ConnectionRefused
    Usage: haadmin [-ns <nameserviceId>] [-transitionToActive [--forceactive] <serviceId>]
    

    发现 Connection refused,因为为了防止脑裂,[nn2] 必须和 [nn1] 取得联系,但是此时 [nn1] 已挂,所以必须先把 [nn1] 先启动,再手动将 [nn2] 切为 Active

  3. 启动 [nn1]

    [root@hadoop-1 hadoop]# hadoop-daemon.sh start namenode
    starting namenode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-namenode-hadoop-1.out
    

    此时 [nn1] 和 [nn2] 都是 standyby 状态

  4. 手动 将 [nn2] 切为 Active

    [root@hadoop-1 hadoop]# hdfs haadmin -transitionToActive nn2
    

    image

7.4 HDFS-HA 自动故障转移

7.4.1 工作要点

前面使用命令 hdfs haadmin -failover 手动进行故障转移,在该模式下,即使现役 NameNode 已经失效,系统也不会自动从现役 NameNode 转移到待机 NameNode,下面配置部署 HA 自动进行故障转移

自动故障转移为 HDFS 部署增加了两个新组件:ZooKeeperZKFailoverController(ZKFC) 进程

ZooKeeper 是维护少量协调数据,通知客户端这些数据的改变和监视客户端故障的高可用服务

7.4.2 ZooKeeper 在 自动故障转移 中的作用

7.4.2.1 故障检测

集群中的每个 NameNode 在 ZooKeeper 中维护了一个持久会话,如果机器崩溃,ZooKeeper 中的会话将终止,ZooKeeper 通知另一个 NameNode 需要触发故障转移

7.4.2.2 现役 NameNode 选择

ZooKeeper 提供了一个简单的机制用于唯一的选择一个节点为 active 状态

如果目前现役 NameNode 崩溃,另一个节点可能从 ZooKeeper 获得特殊的排外锁以表明它应该成为现役 NameNode

ZKFC 是自动故障转移中的另一个新组件,是 ZooKeeper 的客户端,也监视和管理 NameNode 的状态

每个运行 NameNode 的主机也运行了一个 ZKFC 进程,ZKFC 负责:

  1. 健康监测

    ZKFC 使用一个健康检查命令定期地 ping 与之在相同主机的 NameNode,只要该 NameNode 及时地回复健康状态,ZKFC 认为该节点是健康的

    如果该节点崩溃,冻结或进入不健康状态,健康监测器标识该节点为非健康的

  2. ZooKeeper 会话管理

    当本地 NameNode 是健康的,ZKFC 保持一个在 ZooKeeper 中打开的会话

    如果本地 NameNode 处于 active 状态,ZKFC 也保持一个特殊的 znode 锁,该锁使用了 ZooKeeper 对短暂节点的支持,如果会话终止,锁节点将自动删除

  3. 基于 ZooKeeper 的选择

    如果本地 NameNode 是健康的,且 ZKFC 发现没有其它的节点当前持有 znode 锁,它将为自己获取该锁

    如果成功,则它已经赢得了选择,并负责运行故障转移进程以使它的本地 NameNode 为 active

    故障转移进程与前面描述的手动故障转移相似,首先如果必要保护之前的现役 NameNode,然后本地 NameNode 转换为 active 状态

image

7.4.3 环境准备

将上面 master、slave1、slave2 三个机器克隆修改相关配置即可,要点如下:

  1. 修改 IP (可以保持不变)、主机名(改为 hadoop-1,hadoop-2,hadooop-3)

    hadoop-1 192.168.27.101
    hadoop-2 192.168.27.102
    hadoop-3 192.168.27.103
    
  2. 修改主机名及主机名和 IP 地址的映射

  3. 关闭防火墙

  4. ssh 免密登录

  5. 清空 Hadoop 的 data 和 logs

7.4.4 规划集群

hadoop-1hadoop-2hadoop-3
NameNodeNameNode-
JournalNodeJournalNodeJournalNode
DataNodeDataNodeDataNode
ZKZKZK
-ResourceManager-
NodeManagerNodeManagerNodeManager

7.4.5 配置 Zookeeper 集群

7.4.5.1 Zookeeper 集群规划

在 hadoop-1、hadoop-2 和 hadoop-3 三个节点上部署 Zookeeper

7.4.5.2 解压安装
  1. 解压 Zookeeper 安装包到 /usr/zookeeper/ 目录下

    [root@hadoop-1 zookeeper]# tar -zxvf zookeeper-3.4.14.tar.gz -C /usr/zookeeper/
    
  2. 在 /usr/zookeeper/zookeeper-3.4.14 这个目录下创建 zkData

    [root@hadoop-1 zookeeper-3.4.14]# mkdir -p zkData
    
  3. 复制 /usr/zookeeper/zookeeper-3.4.14/conf 这个目录下的 zoo_sample.cfg 为 zoo.cfg

    [root@hadoop-1 conf]# cp zoo_sample.cfg zoo.cfg
    
7.4.5.3 配置 zoo.cfg 文件
  1. 具体配置

    dataDir=/usr/zookeeper/zookeeper-3.4.14/zkData

    增加如下配置

    #######################cluster##########################
    server.1=hadoop-1:2888:3888
    server.2=hadoop-2:2888:3888
    server.3=hadoop-3:2888:3888
    
  2. 配置参数解读

    Server.A=B:C:D

    A 是一个数字,表示这个是第几号服务器

    B 是这个服务器的 ip 地址

    C 是这个服务器与集群中的 Leader 服务器交换信息的端口

    D 是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口

    集群模式下配置一个文件 myid,这个文件在 dataDir 目录下,这个文件里面有一个数据就是 A 的值,Zookeeper 启动时读取此文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是哪个 server

  3. 集群操作

    A. 在 /usr/zookeeper/zookeeper-3.4.14/zkData 目录下创建一个 myid 的文件

    touch myid
    

    添加 myid 文件,注意一定要在 linux 里面创建,在 notepad++ 里面很可能乱码

    B. 编辑 myid 文件

    vim myid
    

    在文件中添加与 server 对应的编号:如 1

    C. 拷贝配置好的 zookeeper 到其他机器上

    scp -r /usr/zookeeper/zookeeper-3.4.14/ root@hadoop-2:/usr/zookeeper/zookeeper-3.4.14/
    scp -r /usr/zookeeper/zookeeper-3.4.14/ root@hadoop-3:/usr/zookeeper/zookeeper-3.4.14/
    

    并分别修改myid文件中内容为 2、3

    D. 分别启动 zookeeper

    [root@hadoop-1 zookeeper-3.4.14]# bin/zkServer.sh start
    [root@hadoop-2 zookeeper-3.4.14]# bin/zkServer.sh start
    [root@hadoop-3 zookeeper-3.4.14]# bin/zkServer.sh start
    

    E. 查看状态

    [root@hadoop-1 zookeeper-3.4.14]# bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /usr/zookeeper/zookeeper-3.4.14/bin/../conf/zoo.cfg
    Mode: follower
    
    [root@hadoop-2 zookeeper-3.4.14]# bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /usr/zookeeper/zookeeper-3.4.14/bin/../conf/zoo.cfg
    Mode: follower
    
    [root@hadoop-3 zookeeper-3.4.14]# bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /usr/zookeeper/zookeeper-3.4.14/bin/../conf/zoo.cfg
    Mode: leader
    

    hadoop-1、hadoop-2 为 follower,hadoop-3 为 leader

7.4.6 配置 HDFS-HA 集群(以三台为例)

  1. 官方地址:https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html

  2. 配置 core-site.xml

    在前面手动 HA 配置的基础上,新增 [core-site.xml] 配置

    <property>
    	<name>ha.zookeeper.quorum</name>
    	<value>hadoop-1:2181,hadoop-2:2181,hadoop-3:2181</value>
    </property>
    
  3. 配置 hdfs-site.xml

    在前面手动 HA 配置的基础上,新增 [hdfs-site.xml] 配置

    <property>
    	<name>dfs.ha.automatic-failover.enabled</name>
    	<value>true</value>
    </property>
    
  4. 拷贝配置好的 hadoop 环境到其他节点

7.4.7 启动

  1. 关闭所有 HDFS 服务

    [root@hadoop-1 hadoop-2.9.2]# stop-dfs.sh
    
  2. 启动 Zookeeper 集群

    [root@hadoop-1 zookeeper-3.4.14]# bin/zkServer.sh start
    [root@hadoop-2 zookeeper-3.4.14]# bin/zkServer.sh start
    [root@hadoop-3 zookeeper-3.4.14]# bin/zkServer.sh start
    

    检查 ZK 启动状态,一个 leader,两个 follower

  3. 初始化 HA 在 Zookeeper 中状态

    [root@hadoop-1 hadoop-2.9.2]# hdfs zkfc -formatZK
    

    image

    初始化 ZK 的 HA 状态后,可到 ZK 上确认 hadoop-ha 目录存在,并且 mycluster 集群已被 ZK 管理

    [root@hadoop-2 hadoop-2.9.2]# cd /usr/zookeeper/zookeeper-3.4.14/
    [root@hadoop-2 zookeeper-3.4.14]# bin/zkCli.sh
    ......
    [zk: localhost:2181(CONNECTED) 0] ls /
    [zookeeper, hadoop-ha]
    [zk: localhost:2181(CONNECTED) 1] ls /hadoop-ha
    [mycluster]
    
  4. 启动 HDFS 服务:

    [root@hadoop-1 hadoop-2.9.2]# start-dfs.sh
    Starting namenodes on [hadoop-1 hadoop-2]
    hadoop-1: starting namenode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-namenode-hadoop-1.out
    hadoop-2: starting namenode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-namenode-hadoop-2.out
    hadoop-1: starting datanode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-datanode-hadoop-1.out
    hadoop-3: starting datanode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-datanode-hadoop-3.out
    hadoop-2: starting datanode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-datanode-hadoop-2.out
    Starting journal nodes [hadoop-1 hadoop-2 hadoop-3]
    hadoop-1: starting journalnode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-journalnode-hadoop-1.out
    hadoop-2: starting journalnode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-journalnode-hadoop-2.out
    hadoop-3: starting journalnode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-journalnode-hadoop-3.out
    Starting ZK Failover Controllers on NN hosts [hadoop-1 hadoop-2]
    hadoop-1: starting zkfc, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-zkfc-hadoop-1.out
    hadoop-2: starting zkfc, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-zkfc-hadoop-2.out
    

    启动 HDFS 服务,观察启动日志,发现主要启动了:

    (1) namenodes : [hadoop-1 hadoop-2]

    (2) journal nodes : [hadoop-1 hadoop-2 hadoop-3]

    (3) ZK Failover Controllers : [hadoop-1 hadoop-2] (ZKFC 跟着 NN 走)

    在各个节点上 jps 观察所有组件启动成功,在 web 界面观察两个 Namenode 的状态

    image

    image

    NameNode 先启动的就是 Active 状态

7.4.8 验证
  1. 将 Active NameNode 进程 kill

    [root@hadoop-1 hadoop-2.9.2]# jps
    5028 DataNode
    2581 QuorumPeerMain
    5607 Jps
    5256 JournalNode
    5465 DFSZKFailoverController
    4910 NameNode
    [root@hadoop-1 hadoop-2.9.2]# kill -9 4910
    

    但是遗憾发现,Namenode1 被 kill 之后,Namenode2 并没有启动,解决方式见: 7.4.9 HDFS-HA 自动故障转移失败的原因

    ,到 Namenode2 节点上看 hadoop-root-zkfc-hadoop-2.log 日志

  2. 将 Active NameNode 机器断开网络

    service network stop
    

观察上述两个场景下的 HDFS-HA 自动故障转移

7.4.9 HDFS-HA 自动故障转移失败的原因

如果发现 HA 配置没有问题,但是不能自动切换 active 的 Namenode,我们可以查看 zkfc 的 log 日志,看是否会出现下面的 Warn 或者 Exception:

image

hadoop-2 ssh 到 hadoop-1 上,尝试连接到 8020 这个 rpc 端口,但是因为 hadoop-1 上的 Namenode 进程被关了,自然连不上

hadoop-2 使用了 fuser 工具,但是装的 Centos 是最小化安装,并不包含 fuser,所以需要在所有 Namenode 机器(hadoop-1,hadoop-2)上安装 fuser

[root@hadoop-1 logs]# yum install psmisc
[root@hadoop-2 logs]# yum install psmisc

7.5 YARN-HA 配置

7.5.1 YARN-HA 工作机制

  1. 官方文档

https://hadoop.apache.org/docs/stable/hadoop-yarn/hadoop-yarn-site/ResourceManagerHA.html

  1. YARN-HA 工作机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fhBh1JRt-1583649351279)(https://hadoop.apache.org/docs/stable/hadoop-yarn/hadoop-yarn-site/images/rm-ha-overview.png)]

7.5.2 配置 YARN-HA 集群

7.5.2.1 环境准备

在前面 Hdfs HA 的基础上进行配置

7.5.2.2 规划集群

和前面 Hdfs HA 的集群的基础上规划:hadoop-1 和 hadoop-2 上配置 active/standby ResourceManager

hadoop-1hadoop-2hadoop-3
NameNodeNameNode-
JournalNodeJournalNodeJournalNode
DataNodeDataNodeDataNode
ZKZKZK
ResourceManagerResourceManager-
NodeManagerNodeManagerNodeManager

7.5.2.3 配置 yarn-site.xml

[yarn-site.xml]

<configuration>

	<!-- Site specific YARN configuration properties -->

	<!-- reducer 获取数据的方式 -->
	<property>
		<name>yarn.nodemanager.aux-services</name>
		<value>mapreduce_shuffle</value>
	</property>

    <!--启用 resourcemanager ha-->
    <property>
        <name>yarn.resourcemanager.ha.enabled</name>
        <value>true</value>
    </property>
 
    <!--声明两台resourcemanager的地址-->
    <property>
        <name>yarn.resourcemanager.cluster-id</name>
        <value>cluster-yarn</value>
    </property>

    <property>
        <name>yarn.resourcemanager.ha.rm-ids</name>
        <value>rm1,rm2</value>
    </property>

    <property>
        <name>yarn.resourcemanager.hostname.rm1</name>
        <value>hadoop-1</value>
    </property>

    <property>
        <name>yarn.resourcemanager.hostname.rm2</name>
        <value>hadoop-2</value>
    </property>
 
    <!--指定zookeeper集群的地址--> 
    <property>
        <name>yarn.resourcemanager.zk-address</name>
        <value>hadoop-1:2181,hadoop-2:2181,hadoop-3:2181</value>
    </property>

    <!--启用自动恢复--> 
    <property>
        <name>yarn.resourcemanager.recovery.enabled</name>
        <value>true</value>
    </property>
 
    <!--指定resourcemanager的状态信息存储在zookeeper集群--> 
    <property>
        <name>yarn.resourcemanager.store.class</name>     
		<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
    </property>
	
	<!-- 忽略虚拟内存检查,如果实在实体机上,并且内存够多,可以去掉 -->
	<property>
		<name>yarn.nodemanager.vmen-check-enabled</name>
		<value>false</value>
	</property>

</configuration>

同步更新其他节点的配置信息

7.4.2.4 启动 Hdfs

前置状态:ZK 集群已起,Hadoop 未起

  1. 启动 Hdfs

    [root@hadoop-1 hadoop]# start-dfs.sh 
    Starting namenodes on [hadoop-1 hadoop-2]
    hadoop-1: starting namenode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-namenode-hadoop-1.out
    hadoop-2: starting namenode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-namenode-hadoop-2.out
    hadoop-1: starting datanode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-datanode-hadoop-1.out
    hadoop-3: starting datanode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-datanode-hadoop-3.out
    hadoop-2: starting datanode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-datanode-hadoop-2.out
    Starting journal nodes [hadoop-1 hadoop-2 hadoop-3]
    hadoop-1: starting journalnode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-journalnode-hadoop-1.out
    hadoop-3: starting journalnode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-journalnode-hadoop-3.out
    hadoop-2: starting journalnode, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-journalnode-hadoop-2.out
    Starting ZK Failover Controllers on NN hosts [hadoop-1 hadoop-2]
    hadoop-1: starting zkfc, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-zkfc-hadoop-1.out
    hadoop-2: starting zkfc, logging to /usr/hadoop/hadoop-2.9.2/logs/hadoop-root-zkfc-hadoop-2.out
    

    注意,此处 namenodes 在 [hadoop-1 hadoop-2] 都起来了!

  2. 启动 Yarn

    因为配置了 ResourceManager 在 hadoop-1、hadoop-2 上,所以在 hadoop-2 上启动效果一样

    [root@hadoop-2 hadoop]# yarn-daemon.sh start resourcemanager
    starting resourcemanager, logging to /usr/hadoop/hadoop-2.9.2/logs/yarn-root-resourcemanager-hadoop-2.out
    
    [root@hadoop-2 hadoop]# jps
    24064 DataNode
    24432 ResourceManager
    24688 Jps
    4995 QuorumPeerMain
    23978 NameNode
    24314 DFSZKFailoverController
    24174 JournalNode
    

    确认 ResourceManager 在 hadoop-2 上启动成功,可再次在 web 端确认:

    image

    但是和 Hdfs HA 不一样,此时 hadoop-1 上并不会启动 ResourceManager,需要我们再次启动

    [root@hadoop-1 hadoop]# yarn-daemon.sh start resourcemanager
    starting resourcemanager, logging to /usr/hadoop/hadoop-2.9.2/logs/yarn-root-resourcemanager-hadoop-1.out
    
  3. 查看服务状态

    [root@hadoop-3 hadoop]# yarn rmadmin -getServiceState rm1
    standby
    
    [root@hadoop-3 logs]# yarn rmadmin -getServiceState rm2
    active
    

    可见 rm2 是 active 状态

7.5 HDFS Federation 架构设计

7.5.1 NameNode 架构的局限性

  1. Namespace(命名空间)的限制

    由于 NameNode 在内存中存储所有的元数据(metadata),因此单个 Namenode 所能存储的对象(文件+块)数目受到 Namenode 所在 JVM 的 heap size 的限制

    50G 的 heap 能够存储 20亿(200million)个对象,这 20 亿个对象支持 4000 个 Datanode,12PB 的存储(假设文件平均大小为 40MB)

    随着数据的飞速增长,存储的需求也随之增长

    单个 Datanode 从 4T 增长到 36T,集群的尺寸增长到 8000 个 Datanode,存储的需求从 12PB 增长到大于100PB

  2. 隔离问题

    由于 HDFS 仅有一个 Namenode,无法隔离各个程序,因此 HDFS 上的一个实验程序就很有可能影响整个 HDFS 上运行的程序

  3. 性能的瓶颈

    由于是单个 Namenode 的 HDFS 架构,因此整个 HDFS 文件系统的吞吐量受限于单个 Namenode 的吞吐量

7.5.2 HDFS Federation 架构设计

能不能有多个NameNode

NameNodeNameNodeNameNode
元数据元数据元数据
Logmachine电商数据/话单数据

7.5.3 HDFS Federation 应用思考

不同应用可以使用不同 NameNode 进行数据管理

图片业务、爬虫业务、日志审计业务

Hadoop 生态系统中,不同的框架使用不同的 NameNode 进行管理 Namespace(隔离性)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值