HDFS分布式文件系统
目录
1.HDFS概述
在现代的企业环境中,单机容量往往无法存储大量数据,需要跨机器存储。统一管理分布在集群上的文件系统称为分布式文件系统 。
HDFS(Hadoop Distributed File System)是Apache Hadoop项目的子项目。Hadoop 非常适于存储大型数据 (比如 TB 和 PB), 其就是使用 HDFS 作为存储系统. HDFS 使用多台计算机存储文件, 并且提供统一的访问接口, 像是访问一个普通文件系统一样使用分布式文件系统.
分布式文件系统解决的问题就是大数据存储。他们是横跨在多台计算机上的存储系统。分布式文件系统在大数据时代有着广泛的应用场景,它们为存储和处理大规模数据提供所需的扩展能力。
2.HDFS发展历史
1、Doug Cutting 在做 Lucene 的时候, 需要编写一个爬虫服务, 这个爬虫写的并不顺利, 遇到 了一些问题, 诸如: 如何存储大规模的数据, 如何保证集群的可伸缩性, 如何动态容错等。
2、2013年的时候, Google 发布了三篇论文, 被称作为三驾马车, 其中有一篇叫做 GFS, 是描述了 Google 内部的一个叫做 GFS 的分布式大规模文件系统, 具有强大的可伸缩性和容错。
3、Doug Cutting 后来根据 GFS 的论文, 创造了一个新的文件系统, 叫做 HDFS。
3. HDFS设计目标
1、硬件故障是常态,HDFS将有成百上千的服务器组成,每一个组成部分都有可能出现故障。因此故障的检测和自动快速恢复是HDFS的核心架构目标。
2、HDFS上的应该与一般的应用不同,HDFS被设计成适合批量处理,而不是用户交互式的。相较于数据访问的反应时间,更注重数据访问的高吞吐量。
3、典型的HDFS文件大小是GB到TB的级别。所以,HDFS被调整成支持大文件。它应该提供很高的聚合数据宽带,一个集群中支持数百个节点,一个集群中应该支持千万级别的文件。
4、大部分HDFS应用对文件要求的是write-one-read-many访问模式。一个文件一旦创建、写入、关闭之后就不需要修改了。这一假设简化了数据一致性问题,使高吞吐量的数据访问成为可能。
5.移动计算的代价比之移动数据的代价低。一个应该请求的计算,离它操作的数据越近就越高效,这在数据达到海量级别的时候更是如此。将计算移动到数据附近,比之将数据移动到应用所在显然更好。
6、在异构的硬件和软件平台上的可移植性。这将推动需要大数据的应用更广泛地采用HDFS作为
4. HDFS应用场景
4.1适应的应用场景
-
存储非常大的文件:这里非常大指的是几百M、G或者TB级别,需要高吞吐量,对延时没有要求。
-
采用流式的数据访问方式:即一次写入、多次读取,数据集经常从数据源生成或者拷贝一次,然就在其上做很多分析工作,且不支持文件的随机修改。
-
正因为如此,HDFS适应用来做大数据分析的低层存储服务,并不适合用来做网盘等应用,因为修改不方便,延时大,网络开销大,成本太高
-
运行与商业硬件上:Hadoop不需要特别贵的机器,可运行于普通廉价机器,可以节约成本
-
需要高容错性
-
为数据存储提供所需的扩展能力
4.2不适合的场景
-
低延时的数据访问 对延时要求在毫秒级别的应用,不适合采用HDFS。HDFS是为高吞吐数据传输设计的,因此可能牺牲延时。
-
大量小文件 文件的元数据保存在NameNode的内存中,整个文件系统的文件数量会受限于NameNode的内存大小。经验而言,一个文件、目录、文件块一般占有150字节的元数据内存空间。如果有100万个文件,每个文件占用1个文件块,则需要大约300的内存。因此十亿级别的文件数量在现有商用机器上难以支持。
-
多方读写,需要任意的文件修改HDFS采用追加(append-only)的方式写入数据。不支持文件任意offset的修改。HDFS适合用来做大数据分析的低层存储服务,并不适合用来做网盘的应用,因为,修改不方便,延迟大、网络开销大,成本太高。
5.HDFS的架构
**HDFS采用Master/Slave架构,**一个HDFS集群有两个重要的角色,分别是Namenode和Datanode。Namenode是管理节点,负责管理文件系统的命名空间(namespace)以及客户端对文件的访问。Datanode是实际存储数据的节点。HDFS暴露了文件系统的命名空间,用户能够以操作文件的形式在上面操作数据。
HDFS的四个基本组件:HDFS Client、NameNode、DataNode和Secondary NameNode
1、Clinet:就是客户端。
- 文件切分。文件上传HDFS的时候,Client将文件切分成为一个一个的Block,然后进行存储
- 与NameNode交互,获取文件的位置信息。
- 与DataNode交互,读取或者写入数据。
- Client提供一些命令来管理和访问HDFS,比如启动或者关闭HDFS
2、NameNode:就是master,它是一个主管、管理者。
- 管理HDFS的命令空间
- 管理数据块(Block)映射信息
- 配置副本策略
- 处理客户端读写请求。
3、DataNode:就是Slave。NameNode下达命令,DataNode执行实际的操作。
-
存储实际的数据块。
-
执行数据块的读、写操作。
-
定时向namenode汇报block信息
4、Secondary NameNode:并非NameNode的热备。当NameNode挂掉,它并不能马上替换NameNode并提供服务。
- 辅助NameNode,分担供服务。
- 定期合并fsimage和fsedits,并推送供给NameNode。
- 在紧急情况下,可辅助恢复NameNode。
6.HDFS的副本机制
6.1HDFS文件副本机制
HDFS被设计成能够在一个大集群中跨机器可靠地存储超大文件。将**每个文件存储成一系列的数据块,这个数据块被称为block。**除了最后一个,多有的数据块都是同样大小的。
为了容错,文件的所有block都会有副本。每个文件的数据块大小和副本系数都是可配置的。
所有的文件都是以block块的方式存放在HDFS文件系统当中,作为如下
1、一个文件有可能大于集群中任意一个磁盘,引入块机制,可以很好的解决这个问题。
2、使用块作为文件存储的逻辑单位可以简化存储子系统
3、块非常适合用户数据备份进而提供数据容错能力
4、副本有点是安全,缺点是占空间
在 Hadoop1 当中, 文件的 block 块默认大小是 64M, hadoop2 当中, 文件的 block 块大小**默认是 128M(134217728字节)。**假设文件大小是100GB,从字节位置0开始,每128MB字节划分为一个block,依此类推,可以划分出很多的block。每个block就是128MB大小。
block块的大小可以通过 hdfs-site.xml 当中的配置文件进行指定,Hadoop默认的副本数为3,也就是每个block会存三份。
<property>
<name>dfs.block.size</name>
<value>块大小以字节为单位</value>
</property>
注意当一个文件的大小不足128M时,比如文件大小为2M,,那么这个文件也占用一个block,但是这个block实际只占2M的空间,所以从某种意义上来讲,block只是一个逻辑单位。
6.2HDFS副本放置策略(机架感知)
HDFS分布式文件系统的内部有一个副本存放策略,默认副本数为3,在这里以副本数=3为例:
**第一副本:**优先放置到离写入客户端最近的DataNode节点,如果上传节点就是DataNode,则直接上传到该节点,如果是集群中提交,则随机挑选一台磁盘不太满,cup不太忙的节点。
**第二个副本:**放置在于第一个副本不同的机架的节点上(随机选择)
**第三个副本:**与第二个副本相同机架的不同节点中。
7、HDFS的Shell命令行使用
7.1shell命令行客户端
HDFS是存取数据的分布式文件系统,那么对HDFS的操作,就是文件系统的基本操作,比如文件的创建、修改、删除、修改权限等,文件夹的创建、删除、重命名等。对HDFS的操作命令类似于Linux的shell对文件的操作,如ls、mkdir、rm等。
Hadoop提供了文件系统的shell命令行客户端,使用方法如下:
hadoop fs <args>
文件系统shell包括与Hadoop分布式系统(HDFS)以及Hadoop支持的其他文件系统(如本地FS,HFTP FS,S3 FS等)直接交互的各种类似shell的命令。
所有FS shell命令都将路径URI作为参数。URL格式为scheme://authority/path。对于HDFS,该scheme是hdfs,对于本地FS,该scheme是file。scheme和authority是可选的。如果未指定,则使用配置中指定的默认方案。
对于HDFS,命令示范如下:
hadoop fs -ls hdfs://namenode:port/parent/child
hadoop fs -ls /parent/child # core-site.xml中的fs.defaultFS中有配置
对于本文件系统,命令示范如下:
hadoop fs -ls file:///root/
如果使用的文件系统是HDFS,则也可以使用 hdfs dfs 命令。
7.2Shell命令选项
选项名称 | 使用格式 | 含义 |
---|---|---|
-ls | -ls <路径> | 查看指定路径的当前目录结构 |
-lsr | -lsr <路径> | 递归查看指定路径的目录结构 |
-du | -du <路径> | 统计目录下个文件大小 |
-dus | -dus <路径> | 汇总统计目录下文件(夹)大小 |
-count | -count [-q] <路径> | 统计文件(夹)数量 |
-mv | -mv <源路径> <目的路径> | 移动 |
-cp | -cp <源路径> <目的路径> | 复制 |
-rm | -rm [-skipTrash] <路径> | 删除文件/空白文件夹 |
-rmr | -rmr [-skipTrash] <路径> | 递归删除 |
-put | -put <多个linux上的文件> <hdfs路径> | 上传文件 |
-copyFromLocal | -copyFromLocal <多个linux上的文件> <hdfs路径> | 从本地复制 |
-moveFromLocal | -moveFromLocal <多个linux上的文件> <hdfs路径> | 从本地移动 |
-getmerge | -getmerge <源路径> <linux路径> | 合并到本地 |
-cat | -cat <hdfs路径> | 查看文件内容 |
-text | -text <hdfs路径> | 查看文件内容 |
-copyToLocal | -copyToLocal [-ignoreCrc] [-crc] [hdfs源路径] [linux目的路径] | 从本地复制 |
-moveToLocal | -moveToLocal [-crc] <hdfs源路径> <linux目的路径> | 从本地移动 |
-mkdir | -mkdir <hdfs路径> | 创建空白文件夹 |
-touchz | -touchz <文件路径> | 创建空白文件 |
-stat | -stat [format] <路径> | 显示文件统计信息 |
-tail | -tail [-f] <文件> | 查看文件尾部信息 |
-chmod | -chmod [-R] <权限模式> [路径] | 修改权限 |
-chown | -chown [-R] [属主][:[属组]] 路径 | 修改属主 |
-chgrp | -chgrp [-R] 属组名称 路径 | 修改属组 |
-help | -help [命令选项] | 帮助 |
7.3常见的shell命令
-ls
格式:hadoop fs -ls URL
作用:类似于Linux的ls命令,显示文件列表
hadoop fs -ls /
-lsr
格式:hdfs dfs -lsr URL
作用:在整个目录下递归执行ls,与UNIX中的ls -R类似
hadoop fs -lsr /
-mkdir
格式 : hdfs dfs [-p] -mkdir <paths>
作用 : 以<paths>中的URI作为参数,创建目录。使用-p参数可以递归创建目录
hadoop fs -mkdir /dir1
hadoop fs -mkdir /dir2
hadoop fs -p -mkdir /aaa/bbb/ccc
-put
格式:hadoop fs -put <localsrc > ... <dst>
作用:将单个的源文件src或者多个源文件srcs从本地文件系统拷贝到目标文件系统中(<dst>对应的路径)。也可以从标准输入中读取输入,写入目标文件系统中
echo "Hello HDFS" >> /root/1.txt
hadoop fs -put /root/1.txt /dir
-moveFromLocal
格式:hdfs dfs-moveFromLocal <localsrc> <dst>
作用:和put命令类似,但是源文件localsrc拷贝之后自身被删除
echo "Hello HDFS" >> /root/2.txt
hdfs dfs -moveFromLocal /root/2.txx
-moveToLocal
未实现
-get
格式 hadoop fs -get [-ignorecrc ] [-crc] <src> <localdst>
作用:将文件拷贝到本地文件系统。CRC 校验失败的文件通过-ignorecrc选项拷贝。文件和CRC校验和可以通过-CRC选项拷贝
hadoop fs -get /2.txt /export/data
-getmerge
格式:hadoop fs -getmerge -nl < hdfs dir > <local file>
功能:合并下载多个文件
参数:加上nl后,合并到local file中的hdfs文件之间会空出一行
事例:比如hdfs的目录 /aaa/下有多个文件:local.1,log.2,log.3,...
hadoop fs -getmerge /aaa/log.* ./log.sum
-mv
格式:hafs dfs -mv URL <dest>
作用:将hdfs上的文件从原路径移动到目标路径(移动之后文件删除),该命令不能跨文件系统
hdfs dfs -mv /dir/a.txt /dir2
-rm
格式:hadoop fs -rm [-r] 【-skipTrash】 URI 【URI 。。。】
作用:删除参数指定的文本和目录,参数可以有多个,删除目录需要加-r 参数
如果指定-skipTrash选项,那么在回收站可用的情况下,该选项将跳过回收站而直接删除文件:
否则,在回收可用时,在HDFS shell中执行此命令,获将文件暂时放到回收站中。
hadoop fs -rm /2.txt # 删除文件
hadoop fs -rm -r /dir # 删除目录
-cp
格式:hdfs dfs -cp URI [URI ...] <dest>
作用: 将文件拷贝到目标路径中。如果<dest> 为目录的话,可以将多个文件拷贝到该目录下。
-f 选项将覆盖目标,如果它已经存在。
-p 选项将保留文件属性(时间戳、所有权、许可、ACL、XAttr)。
hadoop fs -cp /dir1/1.txt /dir2/2.txt
-cat
hadoop fs -cat URI [uri ...]
作用:将参数所指示的we年内容输出到控制台
hadoop fs -cat /dir2/2.txt
-du
hadoop fs -du URL
功能:显示目录中所有文件大小,当只指定一个文件时,显示此文件的大小。
hadoop fs -du /
-chmod
格式:hadoop fs -chmod [-R] URI[URI ...]
作用:改变文件权限。如果使用 -R 选项,则对整个目录有效递归执行。使用这一命令的用户必须是文件的所有用户,或者超级用户。
例如:可以创建一个用户hadoop,将/a.txt的所属用户和所属用户组修改为hadoop
hadoop fs -chmod -R 777 /dir1
-chown
格式:hdfs dfs -chmod [-R] URI[URI ...]
作用: 改变文件的所属用户和用户组。如果使用 -R选项,则对整个目录有效递归执行。使用这一命令的用户必须是文件的所属用户,或者超级用户
hadoop fs -chown -R hadoop:hadoop /a.txt
-appendToFile
格式:hadoop fs -appendToFile<localsrc> ... <dst>
作用:追加一个或多个文件到hdfs指定文件中。也可以从命令行读取输入
cd /export/server/hadoop2.7.5/etc/hadoop/
hadoop fs -appendToFile *.xml /big.xml
8.HDFS的高级使用命令
8.1HDFS的安全模式
安全模式是hadoop的一种保护机制,用于保证集群中的数据块的安全性。当集群启动的时候,会首先进入安全模式。当系统处于安全模式时会检查数据块的完整性。
假设我们设置的副本数(即参数 dfs.replication)是3,那么在datanode上就应该有3个副本存在,假设只存在2个副本,那么比例就是2/3=0.6666.hdfs默认的副本率0.999。我们的副本率0.666明显小于0.999,因此系统会自动的复制副本到其他dataNode,使得副本率不小于0.999。如果系统中有5个副本,超过我们设定的3个副本,那么系统会删除多余的2个副本。
在安全模式状态下,文件系统只接受读数据请求,而不接受删除,修改等变更请求。在当前整个系统达到安全标准时,hdfs自动离开安全模式。
hdfs dfsadmin -safemode get #查看安全模式状态
hdfs dfsadmin -safemode enter #进入安全模式
hdfs dfsadmin -safemode leave #离开安全模式
8.2HDFS基准测试
实际生产环境当中,hadoop的环境搭建完成后,第一件事情就是进行压力测试,测试我们的集群的读写和写入速度,测试我们的网络宽带是否足够等一些基准测试
8.2.1测试写入速度
向HDFS文件系统中写入数据,10个文件,每个文件10MB,文件存放到/benchmarks/TestDFSIO中
hadoop jar /export/server/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -write -nrFiles 10 -fileSize 10MB
完成之后查看写入速度结果
hadoop fs -text /benchmarks/TestDFSIO/io_write/part-00000
8.2.2测试读取速度
测试hdfs的读取文件性能
在HDFS文件系统中读写10个文件,每个文件10M
hadoop jar /export/server/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -read -nrFiles 10 -fileSize 10MB
查看读取果
hadoop fs -text /benchmarks/TestDFSIO/io_read/part-00000
8.2.3清除测试数据
hadoop /export/server/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -clean
9. HDFS基本原理
9.1NameNode
1、概念
NameNode在内存中保存着整个文件系统的命令空间和文件数据块的地址映射
整个HDFS可存储的文件数受限于NameNode的内存大小
1、NmeNode元数据信息文件名,文件目录结构,文件属性(生成时间,副本数,权限)每个文件的块列表。以及列表中的块与块所在的DataNode之间的地址映射关系在内存中加载文件系统中每个文件和每个数据块的引用关系(文件、block、datanode之间的映射信息)数据会定期保存到本地磁盘(fsImage文件和edits文件)
2、NameNode文件操作NameNode负责文件元数据的操作 DataNode负责处理文件内容的读写请求,数据流不经过NameNode,会询它跟那个DataNode联系
3、DataNode数据副本文件数据块到底存放到哪些DataNode上,是由NameNode决定的,NameNode根据全局情况做出放置副本的决定
4、NameNode心跳机制全权管理数据块的复制,周期性的接受心跳和块的状态报告信息(包含该DataNode上所有数据块的列表)若接受到心跳信息,NameNode认为DataNode工作正常,如果在指定时间内还接受到不到DataNode的心跳,那么NameNode认为DataNode已经宕机 ,这时候NameNode准备要把DN上的数据块进行重新的复制。 块的状态报告包含了一个DataNode上所有数据块的列表,blocks report 每个1小时发送一次.****
2作用
1、NameNode是HDFS的核心
2、NameNode也称为Master
3、NameNode仅存储HDFS的元数据:文件系统中所有文件的目录树,并跟踪整个集群中的文件。
4、NameNode不存储实际数据或数据集。数据本身实际存储在DataNodes中。
5、NameNode知道HDFS中任何给定文件的块列表及其位置。使用此信息NameNode知道如何从块中构建文件。
6、NameNode并不持久化存储每个文件中各个块所在的DataNode的位置信息,这些信息会在系统启动时从数据节点重建。
7、NameNode对于HDFS至关重要,当NameNode关闭时,HDFS / Hadoop集群无法访问。****
8、NameNode是Hadoop集群中的单点故障。
9、NameNode所在机器通常会配置有大量内存(RAM)。
9.2. DataNode
1、Data Node以数据块的形式存储HDFS文件
2、DataNode也称为Slave。
3、NameNode和DataNode会保持不断通信。
4、DataNode启动时,它将自己发布到NameNode并汇报自己负责持有的块列表。
5、当某个DataNode关闭时,它不会影响数据或群集的可用性。NameNode将安排由其他DataNode管理的块进行副本复制。
6、DataNode所在机器通常配置有大量的硬盘空间。因为实际数据存储在DataNode中。
7、DataNode会定期(dfs.heartbeat.interval配置项配置,默认是3秒)向NameNode发送心跳,如果NameNode长时间没有接受到DataNode发送的心跳, NameNode就会认为该DataNode失效。
8、block汇报时间间隔取参数dfs.blockreport.intervalMsec,参数未配置的话默认为6小时.
10. HDFS的数据读写流程(面)
10.1HDFS写数据流程
详细步骤解析:
1、client发起文件上传请求,通过RPC与NameNode建立通讯,NameNode检查目标文件是否已存在,父目录是否存在,返回是否可以上传。
2、client请求第一个block该传输到哪些DataNode服务器上;
3、NameNode根据配置文件中指定的备份数量及副本放置策略进行文件分配,返回可用的DataNode的地址,如:A,B,C;
4、client请求3台DataNode中的一台A上传数据(本质上是一个RPC调用,建立pipeline),A收到请求会继续调用B,然后B调用C,将整个pipeline建立完成,后逐级返回client;
5、client开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位(默认64K),A收到一个packet就会传给B,B传给C;A每传一个packet会放入一个应答队列等待应答(几个副本有几个应答才算正常)。
6、数据被分割成一个个packet数据包在pipeline上依次传输,在pipeline反方向上,逐个发送ack(命令正确应答),最终由pipeline中第一个DataNode节点A将pipeline ack发送给client;
7、当一个block传输完成之后,client再次请求NameNode上传第二个block到服务器。
详细步骤图:
10.2.HDFS读数据流程
详细步骤解析:
1、Client向NameNode发起RPC请求,来确定请求文件block所在的位置;
2、NameNode会视情况返回文件的部分或者全部block列表,对于每个block,NameNode都会返回含有该block副本的DataNode地址;
3、这些返回的DN地址,会按照集群拓扑结构得出DataNode与客户端的距离,然后进行排序,排序两个规则:网络拓扑结构中距离Client近的排靠前;心跳机制中超时汇报的DN状态为STALE,这样的排靠后;
4、Client选取排序靠前的DataNode来读取block,如果客户端本身就是DataNode,那么将从本地直接获取数据;底层上本质是建立Socket Stream(FSDataInputStream),重复的调用父类DataInputStream的read方法,直到这个块上的数据读取完毕;
5、当读完列表的block后,若文件读取还没有结束,客户端会继续向NameNode获取下一批的block列表;
6、读取完一个block都会进行checksum验证,如果读取DataNode时出现错误,客户端会通知NameNode,然后再从下一个拥有该block副本的DataNode继续读。
7、read方法是并行的读取block信息,不是一块一块的读取;NameNode只是返回Client请求包含块的DataNode地址,并不是返回请求块的数据;
最终读取来所有的block会合并成一个完整的最终文件。
详细步骤图:
11.HDFS的元数据辅助管理
当 Hadoop 的集群当中, NameNode的所有元数据信息都保存在了 FsImage 与 Eidts 文件当中, 这两个文件就记录了所有的数据的元数据信息, 元数据信息的保存目录配置在了 hdfs-site.xml
当中
<property>
<name>dfs.namenode.name.dir</name>
<value>
file:///export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas</value>
</property>
<property>
<name>dfs.namenode.edits.dir</name>
<value>file:///export/servers/hadoop-2.7.5/hadoopDatas/nn/edits</value>
</property>
11.1.FsImage和Edits
edits:
edits
是在NameNode启动时对整个文件系统的快照存放了客户端最近一段时间的操作日志
客户端对 HDFS 进行写文件时会首先被记录在 edits
文件中
edits
修改时元数据也会更新
fsimage:
fsimage
是在NameNode启动时对整个文件系统的快照
NameNode 中关于元数据的镜像, 一般称为检查点, fsimage
存放了一份比较完整的元数据信息
因为 fsimage
是 NameNode 的完整的镜像, 如果每次都加载到内存生成树状拓扑结构,这是非常耗内存和CPU, 所以一般开始时对 NameNode 的操作都放在 edits 中
随着edits
内容增大, 就需要在一定时间点和 fsimage
合并
11.2. SecondaryNameNode的作用
SecondaryNameNode的作用是合并fsimage和edits文件。
NameNode的存储目录树的信息,而目录树的信息则存放在fsimage文件中,当NameNode启动的时候会首先读取整个fsimage文件,将信息装载到内存中。
Edits文件存储日志信息,在NameNode上所有对目录的最新操作,增加,删除,修改等都会保存到edits文件中,并不会同步到fsimage中,当NameNode关闭的时候,也不会将fsimage和edits进行合并。
所以当NameNode启动的时候,首先装载fsimage文件,然后按照edits中的记录执行一遍所有记录的操作,最后把信息的目录树写入fsimage中,并删掉edits文件,重新启用新的edits文件。
但是如果NameNode执行了很多操作的话,就会导致edits文件会很大,那么在下一次启动的过程中,就会导致NameNode的启动速度很慢,慢到几个小时也不是不可能,所以出现了SecondNameNode。
11.3. SecondaryNameNode唤醒合并的规则
SecondaryNameNode 会按照一定的规则被唤醒,进行fsimage和edits的合并,防止文件过大。
合并的过程是,将NameNode的fsimage和edits下载到SecondryNameNode 所在的节点的数据目录,然后合并到fsimage文件,最后上传到NameNode节点。合并的过程中不影响NameNode节点的操作
SecondaryNameNode被唤醒的条件可以在core-site.xml中配置:
fs.checkpoint.period:单位秒,默认值3600(1小时),检查点的间隔时间,当距离上次检查点执行超过该时间后启动检查点
fs.checkpoint.size:单位字节,默认值67108864(64M),当edits文件超过该大小后,启动检查点
[core-site.xml]
<!-- 多久记录一次 HDFS 镜像, 默认 1小时 -->
<property>
<name>fs.checkpoint.period</name>
<value>3600</value>
</property>
<!-- 一次记录多大, 默认 64M -->
<property>
<name>fs.checkpoint.size</name>
<value>67108864</value>
</property>
SecondaryNameNode一般处于休眠状态,当两个检查点满足一个,即唤醒SecondaryNameNode执行合并过程。
11.4SecondaryNameNode工作过程
第一步:将hdfs更新记录写入一个新的文件—edits.new。
**第二步:**将fsimage和editlog通过http协议发送至secondary namenode。
**第三步:**将fsimage与editlog合并,生成一个新的文件——fsimage.ckpt。这步之所以要在secondary namenode中进行,是因为比较耗时,如果在namenode中进行,或导致整个系统卡顿。
**第四步:**将生成的fsimage.ckpt通过http协议发送至namenode
**第五步:**重命名fsimage.ckpt为fsimage,edits.new为edits。
**第六步:**等待下一次checkpoint触发SecondaryNameNode进行工作,一直这样循环操作。
注意:SecondaryNameNode 在合并 edits 和 fsimage 时需要消耗的内存和 NameNode 差不多, 所以一般把 NameNode 和 SecondaryNameNode 放在不同的机器上
11.5. fsimage 中的文件信息查看
使用命令 hdfs oiv
cd /export/server/hadoop-2.7.5/hadoopDatas/namenodeDatas/current
hdfs oiv -i fsimage_0000000000000000138 -p XML -o hello.xml
11.6. edits中的文件信息查看
使用命令hdfs oev
cd /export/server/hadoop-2.7.5/hadoopDatas/namenodeDatas/current
hdfs oev -i edits_0000000000000000865-0000000000000000866 -p XML -o myedit.xml
11.7.NameNode元数据恢复
当NameNode发生故障时,我们可以通过将SecondaryNameNode中数据拷贝到NameNode存储数据的目录的方式来恢复NameNode的数据
操作步骤:
1、杀死NameNode进程
kill -9 NameNode进程号
2、删除NameNode存储的数据
rm /export/server/hadoop-2.7.5/hadoopDatas/namenodeDatas/* -fr
3、拷贝SecondaryNameNode中数据到源NameNode存储数据目录
cd /export/server/hadoop-2.7.5/hadoopDatas/namenodeDatas/
scp -r node2:/export/server/hadoop-2.7.5/hadoopDatas/snn/name/* ./
4、重新启动NameNode
hadoop-daemon.sh start namenode
12.HDFS的API操作
12.1HDFS的JAVA API操作
HDFS在生产应用中主要是客户端的开发,其核心步骤是从HDFS提供的api中构造一个HDFS的访问客户端对象,然后通过该客户端对象操作(增删改查)HDFS上的文件。
12.2 配置Windows下Hadoop环境
在windows上做HDFS客户端应用开发,需要设置Hadoop环境,而且要求是windows平台编译的Hadoop,不然会报以下的错误:
缺少winutils.exe
Could not locate executable null \bin\winutils.exe in the hadoop binaries
缺少hadoop.dll
Unable to load native-hadoop library for your platform… using builtin-Java classes where applicable
搭建步骤:
第一步:将已经编译好的Windows版本Hadoop解压到到一个没有中文没有空格的路径下面
第二步:在windows上面配置hadoop的环境变量: HADOOP_HOME,并将%HADOOP_HOME%\bin添加到path中
第三步:把hadoop2.7.5文件夹中bin目录下的hadoop.dll文件放到系统盘:
C:\Windows\System32 目录
第四步:关闭windows重启
12.3. 导入Maven依赖
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
</dependencies>
12.4使用文件系统方式访问数据
12.4.1涉及的主要类
在java中操作HDFS,主要涉及以下Class:
Configuration:该类的对象封装了客户端或者服务器的配置;
**FileSystem:**该类的对象是一个文件系统对象,可以用该对象的一些方法来对文件进行操作,通过FileSystem的静态方法get获得该对象。
FileSystem fs =FlieSystem.get(conf);
get方法从conf中的一个参数 fs.defaultFS的配置值判断具体是什么类型的文件系统。如果我们的代码中没有指定fs.defaultFS,并且工程classpath下也没有给定相应的配置,conf中的默认值就来自于hadoop的jar包中的core-default.xml,默认值为: file:///,则获取的将不是一个DistributedFileSystem的实例,而是一个本地文件系统的客户端对象。
12.4.2获取FileSystem方式
第一种方式
@Test
public void getFileSystem1() throws IOException {
Configuration configuration = new Configuration();
//指定我们使用的文件系统类型:
configuration.set("fs.defaultFS", "hdfs://node1:8020/");
//获取指定的文件系统
FileSystem fileSystem = FileSystem.get(configuration);
System.out.println(fileSystem.toString());
}
第二种方式
@Test
public void getFileSystem2() throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
System.out.println("fileSystem:"+fileSystem);
}
14.4.3遍历HDFS中所有文件
@Test
public void listMyFiles()throws Exception{
//获取fileSystem类
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
//获取RemoteIterator 得到所有的文件或者文件夹,第一个参数指定遍历的路径,第二个参数表示是否要递归遍历
RemoteIterator<LocatedFileStatus> locatedFileStatusRemoteIterator = fileSystem.listFiles(new Path("/"), true);
while (locatedFileStatusRemoteIterator.hasNext()){
LocatedFileStatus next = locatedFileStatusRemoteIterator.next();
System.out.println(next.getPath().toString());
}
fileSystem.close();
}
12.4.4HDFS上创建文件夹
@Test
public void mkdirs() throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
boolean mkdirs = fileSystem.mkdirs(new Path("/hello/mydir/test"));
fileSystem.close();
}
12.4.5下载文件
@Test
public void getFileToLocal()throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
FSDataInputStream inputStream = fileSystem.open(new Path("/timer.txt"));
FileOutputStream outputStream = new FileOutputStream(new File("e:\\timer.txt"));
IOUtils.copy(inputStream,outputStream );
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
fileSystem.close();
}
12.4.6. 上传文件
@Test
public void putData() throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
fileSystem.copyFromLocalFile(new Path("file:///c:\\install.log"),new Path("/hello/mydir/test"));
fileSystem.close();
}
12.4.7小文件合并
由于Hadoop 擅长存储大文件,因为大文件的元数据信息比较少,如果Hadoop集群当中有大量小文件,那么每个小文件需要维护一份元数据信息,会大大的增加集群管理元数据的内存压力,所以在实际工作当中,如果有必要一定要将小文件合并成大文件进行一起处理,可以在上传的时候将小文件合并到一个大文件里面去
@Test
public void mergeFile() throws Exception{
//获取分布式文件系统
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration(),"root");
FSDataOutputStream outputStream = fileSystem.create(new Path("/bigfile.txt"));
//获取本地文件系统
LocalFileSystem local = FileSystem.getLocal(new Configuration());
//通过本地文件系统获取文件列表,为一个集合
FileStatus[] fileStatuses = local.listStatus(new Path("file:///E:\\input"));
for (FileStatus fileStatus : fileStatuses) {
FSDataInputStream inputStream = local.open(fileStatus.getPath());
IOUtils.copy(inputStream,outputStream);
IOUtils.closeQuietly(inputStream);
}
IOUtils.closeQuietly(outputStream);
local.close();
fileSystem.close();
}
12.4.8. hdfs访问权限控制
HDFS权限模型和Linux系统类似。每个文件和目录有一个所有者(owner)和一个组(group)。文件或目录对其所有者、同组的其他用户以及所有其他用户(other)分别有着不同的权限。对文件而言,当读取这个文件时需要有r权限,当写入或者追加到文件时需要有w权限。对目录而言,当列出目录内容时需要具有r权限,当新建或删除子文件或子目录时需要有w权限,当访问目录的子节点时需要有x权限。但hdfs的文件权限需要开启之后才生效,否则在HDFS中设置权限将不具有任何意义!
HDFS的权限设置是通过hdfs-site.xml文件来设置,在搭建Hadoop集群时,将HDFS的权限关闭了,所以对HDFS的任何操作都不会受到影响的。
接下来我们将HDFS的权限开启,测试下HDFS的权限控制。
- 停止hdfs集群,在node1机器上执行以下命令
stop-dfs.sh
2、修改node1机器上的hdfs-site.xml当中的配置文件
vim hdfs-site.xml
<property>
<name>dfs.permissions.enabled</name>
<value>true</value>
</property>
3、修改完成之后配置文件发送到其他机器上面去
scp hdfs-site.xml node2:$PWD
scp hdfs-site.xml node3:$PWD
4、重启hdfs集群
start-dfs.sh
5.随意上传一些文件到我们的hadoop集群当中准备测试使用
cd /export/server/hadoop-2.7.5/etc/hadoop
hadoop fs -mkdir /config
hadoop fs -put *.xml /config
hadoop fs -chmod 600 /config/core-site.xml
经过以上操作之后,core-site.xml文件的权限如下:
这个权限是当前所属用户root具有对core-site.xml文件的可读,可写权限。
6.使用代码准备准备下载文件
@Test
public void getConfig()throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration(),"root");
fileSystem.copyToLocalFile(new Path("/config/core-site.xml"),new Path("file:///c:/core-site.xml"));
fileSystem.close();
}
当HDFS的权限开启之后,运行以上代码发现权限拒绝,不允许访问
这是因为我们在Windows下运行HDFS的客户端,用户名一般不是root,是其他用户,所以对core-site.xml文件没有任何操作权限。
解决方法:
方式1-修改core-site.xml的文件权限
hadoop fs -chmod 777 /config/core-site.xml
方式2-伪造用户
在这里,我们可以以root用户的身份去访问文件
@Test
public void getConfig()throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration(),"root");
fileSystem.copyToLocalFile(new Path("/config/core-site.xml"),new Path("file:///c:/core-site.xml"));
fileSystem.close();
}
执行结果如下:
执行成功
13.HDFS其他功能
13.1不同集群之间的数据复制
在我们实际工作当中,既有可能会遇到将测试集群的数据拷贝到生产环境集群,或者将生产环境集群的数据拷贝到测试集群,那么就需要我们在多个集群之间进行数据的远程拷贝,hadoop自带也有命令可以帮我们实现这个功能。
13.2集群内部文件拷贝scp
13.2.1本地复制到远程
方式1:指定命令行,命令执行后需要再输入密码:
scp -r local_folder remote_username@remote_ip:remote_folder
方式2:没有指定用户名,命令执行后需要输入用户名和密码
scp -r local_folder remote_ip:remote_folder
注意:如果实现了ssh免密登录之后,则不需要输入密码即可拷贝。
实例:
#复制文件 将/root/test.txt 拷贝到192.168.88.161的/root/目录下,文件名还是text.txt,使用root用户,此时会提示输入远程root用户的密码。
scp /root/test.txt root@192.168.88.161:/root/
#复制文件名重命名-将/root/test.txt 拷贝到 192.168.88.161 的 /root/ 目录下,文件名还是 text1.txt,使用 root 用户,此时会提示输入远程 root 用户的密码。
scp /root/test.txt root@192.168.88.161:/root/test1.txt
#复制目录-将整个目录 /root/test/ 复制到 192.168.88.161 的 /root/ 下,即递归的复制,使用 root 用户,此时会提示输入远程 root 用户的密码。
scp -r /root/test/ root@192.168.88.161:/root/
13.2.2远程复制到本地
远程复制到本地与从本地复制到远程命令类似,不同的是远程文件作为源文件在前,本地文件作为目标文件在后。
#复制文件-将192.168.88.162的/root目录下的test.txt拷贝到当前主机的/root/目录下,文件名不变
scp root@192.168.88.162:/root/test.txt /root/test.txt
13.3跨集群之间的数据拷贝distcp
DistCp(distributed copy)是一款被用于大象集群集群间/集群内的复制工具,该命令的内部原理是MapReduce。
cd /export/server/hadoop-2.7.5/
bin/hadoop distcp hdfs://node1:8020/jdk-8u241-linux-x64.tar.gz hdfs://cluster2:8020/
13.4.Archive档案的使用
HDFS并不擅长存储小文件,因为每个文件最少一个blcok,每个block的元数据都会在NameNode占用内存,如果存在大量的小文件,它们会吃掉NameNode节点的大量内存。
Hadoop Archives可以有效的处理以上问题,它可以把多个文件归档成为一个文件,归档成一个文件后还可以透明的访问每一个文件。
13.4.1如何创建Archive*
Usage: hadoop archive -archiveName name -p *
其中-archiveName是指要创建的存档的名称。比如test.har,archive的名字的扩展名应该是*.har。 -p参数指定文件存档文件(src)的相对路径。
例如:如果你要想存档一个目录/config下的所有文件:
hadoop archive -archiveName test.harm -p /config /outputdir
这样就会在/outputdir目录下创建一个名为test.har的存档文件。
13.4.2如何查看Archive
首先我们来看下创建好的har文件。使用如下的命令:
hadoop fs -ls /outputdir/test.har
这里可以看到har文件包括:两个索引文件,多个part文件(本例只有一个)以及一个标识成功与否的文件。part文件是多个原文件的集合,根据index文件去找到原文件。
例如上述的/input目录下有很多小的xml文件。进行archive操作之后,这些小文件就归档到test.har里的part-0一个文件里。
hadoop fs -cat /outputdir/test.har/part-0
archive作为文件系统层暴露给外界。所以所有的fs shell命令都能在archive上运行,但是要使用不同的URI。Hadoop Archives的URI是:
har://scheme-hostname:port/archivepath/fileinarchive
scheme-hostname格式为hdfs-域名:端口,如果没有提供scheme-hostname,它会使用默认的文件系统。这种情况下URI是这种形式:
har:///archivepath/filenarchive
如果用har uri去访问的话,索引、标识等文件就会隐藏起来,只显示创建档案之前的原文件:
查看归档文件中的小文件,使用har uri
hadoop fs -ls har://hdfs-node1:8020/outputdir/test.har
查看归档文件中的小文,不使用har uri
hadoop fs -cat har:///outputdir/test.har/core-site.xml
13.4.3如何解压Archive
hadoop fs -mkdir /config2
hadoop fs -cp har:///outputdir/test.har/* /config2
查看HDFS页面,发现/config2目录中已经有解压后的小文件了
13.4.4 Archive注意事项
1、Hadoop archives是特殊的档案格式。一个Hadoop archive对应一个文件系统目录。
Hadoop archive 的扩展名是*.har;
2、创建archives 本质是运行一个Map/Reduce任务,所以应该在Hadoop集群上运行创建档案的命令,要是提前启动Yarn集群;
3、创建archive文件要消耗和源文件一样多的硬盘空间。
4、archive文件不支持压缩,尽管archive文件看起来像已经被压缩过;
5、archive文件一旦创建就无法改变,要修改的话,需要创建新的archive文件。事实上,一般不会再对存档后的文件进行修改,因为他们是定期存档的,比如每周或每日;
6、当创建archive时,源文件不会被更改或删除;
13.5. Snapshot快照的使用
快照顾名思义,就是相当于对hdfs文件系统做一个 备份,可以通过快照对指定的文件夹设备备份,但是添加快照之后,并不会立即复制所有文件,而是指向同一个文件。当写入发生时,才会产生新文件。
HDFS快照(HDFS Snapshots)是文件系统在某个时间点的只读副本。可以在文件系统的子树或者整个文件系统上创建快照。快照的常见用途主要包括数据备份,防止用户误操作和容灾恢复。
13.5.1快照使用基本语法
1、开启指定目录的快照功能
hdfs dfsadmin -allowSnapshot 路径
2、禁用指定目录的快照功能(默认就是禁用状态)
hdfs dfsadmin -disallowSnapshot 路径
3、给某个路径创建快照snapshot
hdfs dfs -createSnapshot 路径
4、指定快照名称
hdfs lsSnapshottableDir
7、恢复快照
hdfs dfs -cp -ptopax 快照路径 恢复路径
8、删除快照snapshot
hdfs dfs -deleteSnapshot<path><snapshotName>
13.5.2快照操作实际案例
1、开启指定目录的快照
hdfs dfsadmin -allowSnapshot /config
2、对指定目录创建快照
注意:创建快照之前,先要允许该目录创建快照
hadf dfs -creatSnapshot /config
通过web浏览器访问快照
http://ndoe1:50070/explorer.html#/config/.snapshot/
3、指定名称创建快照
hdfs dfs -createSnapshot /config mysnap1
4、重命名快照
hdfs dfs -renameSnapshot /config mysnap1 mysnap2
5、列出当前用户所有可以快照的目录
hdfs lsSnapshottableDir
6、恢复快照
hdfs dfs -cp -potpax /input/.snapshot/mysnap1 /config3
#已经恢复到 config3
7、删除快照
hdfs dfs -deleteSnapshot /config mysnap1
13.6HDFS的Trash回收站功能
和Linux系统的回收站设计一样,HDFS会为每一个用户创建一个回收站目录:/user/用户名/.Trash/current,每一个被用户通过Shell删除的文件/目录,在系统回收站中都有一个周期,也就是当系统回收站中的文件/目录在一段时间之后没有没用户恢复的话,HDFS就会自动的把这个文件/目录彻底删除,之后,用户就永远也找不回这个文件/目录了。
如果检查点*已经启动,会定期使用时间戳重命名Current目录。.Trash中的文件在用户可配置的时间延迟后被永久删除。回收站中的文件和目录可以简单地通过将它们移动到.Transh目录之外的位置来恢复。
13.6.1配置
HDFS的回收站就像Windows操作系统中的回收站一样。它的目的是防止你无意中删除某些东西。你可以通过设置如下属性来启动此功能(默认是不开启的):
<property>
<name>fs.trash.interval</name>
<value>10080</value>
<description>Number of minutes after which the checkpoint gets deleted. If zero, the trash feature is disabled.</description>
</property>
属性 | 说明 |
---|---|
fs.trash.interval | 分钟数,回收站文件的存活时间, 当超过这个分钟数后文件会被删除。如果为零,回收站功能将被禁用。 |
13.6.2恢复回收站站数据
hadoop fs -mv /user/root/.Trash/current/hadoop-env.sh /config
#恢复的是被误删的Hadoop-env.sh文件
13.6.3注意点
回收站功能默认是禁用的。对于生产环境,建议启用回收站功能以避免意外的删除操作。启用回收站提供了从用户操作删除或用户意外删除中恢复数据的机会。但是为fs.trash.interval
设置合适的值也是非常重要的,以使垃圾回收以你期望的方式运作。例如,如果你需要经常从HDFS
上传和删除文件,则可能需要将fs.trash.interval
设置为较小的值。
当启用垃圾回收并删除一些文件时,HDFS
容量不会增加,因为文件并未真正删除。
回收站功能默认只适用于使用Hadoop shell
删除的文件和目录。使用其他接口(例如WebHDFS
或Java API
)以编程的方式删除的文件或目录不会移动到回收站,即使已启用回收站,除非程序已经实现了对回收站功能的调用。
有时你可能想要在删除文件时临时禁用回收站,也就是删除的文件或目录不用放在回收站而直接删除,在这种情况下,可以使用-skipTrash
选项运行rm
命令。例如:
hadoop fs -rm -skipTrash /dir1/a.txt
14.HDFS的高可用机制
14.1HDFS高可用介绍
在Hadoop 中,NameNode所处的位置是非常重要的,整个HDFS文件系统的元数据信息都由NameNode来管理,NameNode的可用性直接决定了Hadoop的可用性,一旦NameNode进程不能工作了,就会影响整个集群的正常使用。
在典型的HA集群中,两台独立的机器被配置为NameNode。在工作集群中,NameNode 机器中的一个处于Active状态,另一个处于Standby状态。Active NameNode负责群集中的所有客户端操作,而Standby充当从服务器。Standby机器保持足够的状态以提供快速障碍切换(如果需要)。
14.2组件介绍
Active NameNode和Standby NameNode:两台NameNode形成互备,一台处于Active状态,为主NameNode,另一台处于Standby状态,为备NameNode,只有主NameNode才能对外提供读写服务。
主备切换控制器ZKFC(ZKFailoverController):ZKFailoverController作为独立的进程运行,对NameNode的主备切换进行总体控制。ZKFailoverController能及时检测到NameNode的健康状况,在主NameNode故障时借助Zookeeper实现自动的主备选举和切换。
**Zookeeper集群:**为主备切换控制器提供主备选举支持。
**元数据信息共享存储系统:**共享存储系统是实现NameNode的高可用最为关键的部分,共享存储系统保存了NameNode在运行过程中所产生的HDFS的元数据。主NameNode和备用NameNode通过共享存储系统实现元数据同步。在进行主备切换的时候,新的主NameNode在确认元数据完全同步之后才能继续对外提供服务。
元信息共享存储系统主要用于保存EditLog,并不保存FSImage文件。FSImage文件还是在NameNode的本地磁盘上?*。共享存储采用多个称为JournalNode的节点组成的JournalNode集群来存储EditLog。每个JournalNode保存同样的EditLog副本。每次NameNode写EditLog的时候,除了向本地磁盘写入EditLog之外,也会并行地向JournalNode集群之中的每一个JournalNode发送写请求,只要大多数的JournalNode节点返回成功就认为向JournalNode集群写入EditLog成功。如果有2N+1台JournalNode,那么根据大多数的原则,最多可以容忍有N台JournalNode节点挂掉。
**DataNode节点:**除了通过共享存储系统共享HDFS的元数据信息之外,主NameNode和备NameNode之间的映射关系。DataNode会同时向主NameNode和备NameNode上报数据块的位置信息。
14.3NameNode的主备切换实现
NameNode主备切换主要由ZKFailvoerController、HealthMonitor和ActiveStandbyElector这3个组件来协同实现:
ZKFailoverController作为NameNode机器上一个独立的进程启动(在hdfs启动脚本之中的进程名为zkfc),启动的时候会创建HealthMonitor和ActiveStandbyElector这两个主要的内部组件,这两个主要的内部组件,ZKFailoverController在创建HealthMonitor和ActiveStandbyElector的同时,也会向HealthMonitor和ActiveStandbyElector的同时,也会向HealthMonitor和ActiveStandbyElector注册响应的回调方法。
HealthMonitor主要负责检测NameNode的健康状态,如果检测到NameNode的状态发生变化,会回调ZKFailoverController的相应用方法进行自动的主备选举。
ActiveStandbyElector主要负责完成自动的主备选举,内部封装了Zookeeper的处理逻辑,一旦Zookeeper主备选举完成,会调用ZKFailoverController的相应方法来进行NameNode的主备状态切换。
NameBNode实现主备状态切换的流程如图2所示,有以下几步:
1、HealthMonitor初始化完成之后会启动内部的线程来定时调用对应NameNode的HAServiceProtocol RPC接口的方法,对NameNode的健康状态进行检测。
2、HealthMonitor如果检测到NameNode的健康状态发生变化,会回调ZKFailoverController注册的相关方法进行处理。
3、如果ZKFailoverController判断需要进行主备切换,会首先使用ActiveStandbyElector来进行自动的主动的主备选举。
4、ActiveStandbyElector与Zookeeper进行交互完成自动的主备选举。
5、ActiveStandbyElector在主备选举完成后,会回调ZKFailoverController的相关方法来通知当前的NameNode成为主NameNode成为主NameNode或备NameNode。
6、ZKFailoverController调用对应NameNode的HAServerceProtocol RPC接口的方法将NameNode转换为Active状态或者Standby状态。
15.Hadoop的联邦机制(Federation)
15.1背景概述
单NameNode的架构使得HDFS在集群扩展性和性能上都有潜在的问题,当集群大到一定程度后,NameNode进程使用的内存可能会达到上百G,NameNode成为了性能的瓶颈。因而提出了namenode水平扩展方案–Federation。中文意思为联邦,联盟,是NameNode的Federation,也就是有多个NameNode。多个NameNode的情况意味着有多个namespace(命名空间),区别于HA模式下的多NameNode,他们是拥有着同一个namesapce。既然说到了NameNode的命名空间的概念,这里就看一下现有的HDFS数据管理架构,如下图所示:
从上图中,我们可以很明显地看出现在的HDFS数据管理,数据存储2层的结构,也就是说,所有关于存储数据的信息和管理是放在NameNode这边,而真实数据的存储则是在各个DataNode下。而这些隶属于同一个NameNode所管理的数据都是在同一个命名空间下的,而一个namespace对应一个block pool。Block pool是同一个namespace下的block的集合当然这是我们最常见的单个namespace的情况,也就是一个NameNode管理集群中所有元数据信息的时候。如果我们遇到了之前提到的NameNode内存使用过高的问题,这时候怎么办?
元数据空间依然还是在不断增大,一味调高NameNode的jvm大小绝对不是一个持久的办法,这时候就诞生了HDFS Federation的机制。
15.2Federation架构设计
HDFS Federation 是解决namenode内存瓶颈问题的水平横向扩展方案。
Federation意味着在集群中将会有多个namenode/namespace。这些namenode之间是联合的,也就是说,他们之间相互独立且不需要互相协调,各自分工,管理自己的区域。分布式的datanode被用作通用的数据块存储存储设备。每个datanode要向集群中所有的namenode注册,且周期性地向所有namenode发送心跳和块报告,并执行来自所有namenode的命令。
Federation一个典型的例子就是上面提到的NameNode内存过高问题,我们完全可以将上面部分大的文件目录移到另外一个NameNode上做管理。更重要的一点在于,这些NameNode是共享集群中所以有的DataNode的,他们还是在同一个集群内的。
这时候在DataNode上就不仅仅存储一个Block Pool下的数据了,而是多个(在DataNode的datadir所在目录里面查看BP-xx.xx.xx.xx打头的目录)。
概括起来:
多个NN共用一个集群里的存储资源,每个NN都可以单独对外提供服务。
每个NN都会定义一个存储池,有单独的id。每个DN都为所有存储池提提供存储。
DN会按照存储池id向其对应的NN汇报块信息。同时,DN会向所有NN汇报本地存储可用资源情况。
15.3HDFS Federation不足
HDFS Federation并没有完全解决单间故障问题。虽然namenode/namespace存在多个,但是从单个namenode/namespace看,仍然存在单点故障:如果某个namenode挂掉了,其管理的相应的文件便不可以访问。Federation中每个namenode依然像之前HDFS上实现一样,配有一个secondary namendoe,以便主namenode挂掉,用于还原元数据信息。
所以一般集群规模真的很大的时候,会采用HA+Federation的部署方案。也就是每个联合的namenodes都是ha的。