分布式文件系统——HDFS
文章目录
- 分布式文件系统——HDFS
HDFS概述
HDFS(Hadoop Distributed File System)是 Apache Hadoop 项目的一个子项目. Hadoop 非常适于存储大型数据 (比如 TB 和 PB), 其就是使用 HDFS 作为存储系统. HDFS 使用多台计算机存储文件, 并且提供统一的访问接口, 像是访问一个普通文件系统一样使用分布式文件系统.
分布式文件系统解决的问题就是大数据存储。它们是横跨在多台计算机上的存储系统。分布式文件系统在大数据时代有着广泛的应用前景,它们为存储和处理超大规模数据提供所需的扩展能力。
HDFS发展历史
- Doug Cutting 在做 Lucene 的时候, 需要编写一个爬虫服务, 这个爬虫写的并不顺利, 遇到 了一些问题, 诸如: 如何存储大规模的数据, 如何保证集群的可伸缩性, 如何动态容错等。
- 2003年的时候, Google 发布了三篇论文, 被称作为三驾马车, 其中有一篇叫做 GFS, 是描述了 Google 内部的一个叫做 GFS 的分布式大规模文件系统, 具有强大的可伸缩性和容错。
- Doug Cutting 后来根据 GFS 的论文, 创造了一个新的文件系统, 叫做 HDFS。
HDFS的设计目标
- 硬件是不可靠的:HDFS将有成千上万台机器组成,每一个组成部分,都有可能出现故障,因此,故障检测和自动恢复是HDFS的核心设计目标。
- 流式的数据访问:HDFS上的应用于一般的应用程序不同,他们只要是以流式的读取文件数据,HDFS被设计成适合批量处理,而不是用户交互式的,相较于数据访问的反应时间,更注重于数据访问的高吞吐量。
- 支持超大文件存储:典型的HDFS文件大小是GB到TB的级别。所以,HDFS被调整成支持大文件。它应该提供很高的聚合数据带宽,一个集群中支持数百个节点,一个集群中还应该支持千万级别的文件。
- 简单的一致性模型:大部分HDFS应用对文件要求的是write-one-read-many访问模型。一个文件一旦创建、写入、关闭之后就不需要修改了。这一假设简化了数据一致性问题,使高吞吐量的数据访问成为可能。
- 移动计算的代价比之移动数据的代价更低:一个应用请求的计算,离它操作的数据越近就越高效,这在数据达到海量级别的时候更是如此。将计算移动到数据附近,比之将数据移动到应用所在显然更好。
- 可移植性:在异构的硬件和软件平台上的可移植性。这将推动需要大数据集的应用更广泛地采用HDFS作为平台。
HDSF应用场景
适合的应用场景
- 存储非常大的文件:这里非常大指的是几百M、G、或者TB级别,需要高吞吐量,对延时没有要求。
- 采用流式的数据访问方式: 即一次写入、多次读取,数据集经常从数据源生成或者拷贝一次,然后在其上做很多分析工作 ,且不支持文件的随机修改。正因为如此,HDFS适合用来做大数据分析的底层存储服务,并不适合用来做网盘等应用,因为,修改不方便,延迟大,网络开销大,成本太高。
- 运行于商业硬件上: Hadoop不需要特别贵的机器,可运行于普通廉价机器,可以处节约成本
- 需要高容错性
- 为数据存储提供所需的扩展能力
不适合的应用场景
- 低延时的数据访问:对延时要求在毫秒级别的应用,不适合采用HDFS。HDFS是为高吞吐数据传输设计的,因此可能牺牲延时
- 大量小文件 文件的元数据保存在NameNode****的内存中, 整个文件系统的文件数量会受限于NameNode的内存大小。 经验而言,一个文件/目录/文件块一般占有150字节的元数据内存空间。如果有100万个文件,每个文件占用1个文件块,则需要大约300M的内存。因此十亿级别的文件数量在现有商用机器上难以支持。
- 多方读写,需要任意的文件修改 HDFS采用追加(append-only)的方式写入数据。不支持文件任意offset的修改,HDFS适合用来做大数据分析的底层存储服务,并不适合用来做.网盘等应用,因为,修改不方便,延迟大,网络开销大,成本太高。
HDFS架构
HDFS采用Master/Slave架构
,一个HDFS集群有两个重要的角色,分别是Namenode和Datanode。Namenode是管理节点,负责管理文件系统的命名空间(namespace)以及客户端对文件的访问。Datanode是实际存储数据的节点。HDFS暴露了文件系统的命名空间,用户能够以操作文件的形式在上面操作数据。
HDFS的四个基本组件:HDFS Client、NameNode、DataNode 和 Secondary NameNode。
-
Client:就是客户端。
- 文件切分。文件上传 HDFS 的时候,Client 将文件切分成 一个一个的Block,然后进行存储
- 与 NameNode 交互,获取文件的位置信息。
- 与 DataNode 交互,读取或者写入数据。
- Client 提供一些命令来管理 和访问HDFS,比如启动或者关闭HDFS。
-
NameNode:就是 master,它是一个主管、管理者。
- 管理 HDFS 的名称空间
- 管理数据块(Block)映射信息
- 配置副本策略
- 处理客户端读写请求。
-
DataNode:就是Slave。NameNode 下达命令,DataNode 执行实际的操作。
- 存储实际的数据块。
- 执行数据块的读/写操作。
- Secondary NameNode:并非 NameNode 的热备。当NameNode 挂掉的时候,它并不能马上替换 NameNode 并提供服务。
- 辅助 NameNode,分担其工作量。
- 定期合并 fsimage和fsedits,并推送给NameNode。
- 在紧急情况下,可辅助恢复 NameNode。
HDFS的基本原理
NameNode
概念:
- NameNode在内存中保存着整个文件系统的名称空间和文件数据块的地址映射
- 整个HDFS可存储的文件数受限于NameNode的内存大小
- NameNode元数据信息 文件名,文件目录结构,文件属性(生成时间,副本数,权限)每个文件的块列表。 以及列表中的块与块所在的DataNode之间的地址映射关系 在内存中加载文件系统中每个文件和每个数据块的引用关系(文件、block、datanode之间的映射信息) 数据会定期保存到本地磁盘(fsImage文件和edits文件)
- NameNode文件操作 NameNode负责文件元数据的操作 DataNode负责处理文件内容的读写请求,数据流不经过NameNode,会询问它跟那个DataNode联系
- NameNode副本文件数据块到底存放到哪些DataNode上,是由NameNode决定的,NameNode根据全局情况做出放置副本的决定
- NameNode心跳机制全权管理数据块的复制,周期性的接受心跳和块的状态报告信息(包含该DataNode上所有数据块的列表) 若接受到心跳信息,NameNode认为DataNode工作正常,如果在10分钟后还接受到不到DataNode的心跳,那么NameNode认为DataNode已经宕机 ,这时候NN准备要把DN上的数据块进行重新的复制。 块的状态报告包含了一个DataNode上所有数据块的列表,blocks report 每个1小时发送一次.
作用:
- NameNode是HDFS的核心。
- NameNode也称为Master。
- NameNode仅存储HDFS的元数据:文件系统中所有文件的目录树,并跟踪整个集群中的文件。
- NameNode不存储实际数据或数据集。数据本身实际存储在DataNodes中。
- NameNode知道HDFS中任何给定文件的块列表及其位置。使用此信息NameNode知道如何从块中构建文件。
- NameNode并不持久化存储每个文件中各个块所在的DataNode的位置信息,这些信息会在系统启动时从数据节点重建。
- NameNode对于HDFS至关重要,当NameNode关闭时,HDFS / Hadoop集群无法访问。
- NameNode是Hadoop集群中的单点故障。
- NameNode所在机器通常会配置有大量内存(RAM)。
DataNode
- Data Node以数据块的形式存储HDFS文件
- DataNode也称为Slave。
- NameNode和DataNode会保持不断通信。
- DataNode启动时,它将自己发布到NameNode并汇报自己负责持有的块列表。
- 当某个DataNode关闭时,它不会影响数据或群集的可用性。NameNode将安排由其他DataNode管理的块进行副本复制。
- DataNode所在机器通常配置有大量的硬盘空间。因为实际数据存储在DataNode中。
- DataNode会定期(dfs.heartbeat.interval配置项配置,默认是3秒)向NameNode发送心跳,如果NameNode长时间没有接受到DataNode发送的心跳, NameNode就会认为该DataNode失效。
- block汇报时间间隔取参数dfs.blockreport.intervalMsec,参数未配置的话默认为6小时.
HDFS的工作机制
NameNode负责管理整个文件系统元数据;
DataNode负责管理具体文件数据块存储;
Secondary NameNode协助NameNode进行元数据的备份。
HDFS的内部工作机制对客户端保持透明,客户端请求访问HDFS都是通过向NameNode申请来进行。
HDFS写数据流程
漫画图解
详细步骤解析:
- client发起文件上传请求,通过RPC与NameNode建立通讯,NameNode检查目标文件是否已存在,父目录是否存在,返回是否可以上传;
- client请求第一个 block该传输到哪些DataNode服务器上;
- NameNode根据配置文件中指定的备份数量及副本放置策略进行文件分配,返回可用的DataNode的地址,如:A,B,C;
- client请求3台DataNode中的一台A上传数据(本质上是一个RPC调用,建立pipeline),A收到请求会继续调用B,然后B调用C,将整个pipeline建立完成,后逐级返回client;
- client开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位(默认64K),A收到一个packet就会传给B,B传给C;A每传一个packet会放入一个应答队列等待应答。
- 数据被分割成一个个packet数据包在pipeline上依次传输,在pipeline反方向上,逐个发送ack(命令正确应答),最终由pipeline中第一个DataNode节点A将pipeline ack发送给client;
- 当一个block传输完成之后,client再次请求NameNode上传第二个block到服务器。
HDFS读数据流程
漫画图解:
图解:
详细步骤解析:
- Client向NameNode发起RPC请求,来确定请求文件block所在的位置;
- NameNode会视情况返回文件的部分或者全部block列表,对于每个block,NameNode都会返回含有该block副本的DataNode地址;
- 这些返回的DN地址,会按照集群拓扑结构得出DataNode与客户端的距离,然后进行排序,排序两个规则:网络拓扑结构中距离Client近的排靠前;心跳机制中超时汇报的DN状态为STALE,这样的排靠后;
- Client选取排序靠前的DataNode来读取block,如果客户端本身就是DataNode,那么将从本地直接获取数据;底层上本质是建立Socket Stream(FSDataInputStream),重复的调用父类DataInputStream的read方法,直到这个块上的数据读取完毕;
- 当读完列表的block后,若文件读取还没有结束,客户端会继续向NameNode获取下一批的block列表;
- 读取完一个block都会进行checksum验证,如果读取DataNode时出现错误,客户端会通知NameNode,然后再从下一个拥有该block副本的DataNode继续读。
- read方法是并行的读取block信息,不是一块一块的读取;NameNode只是返回Client请求包含块的DataNode地址,并不是返回请求块的数据;
- 最终读取来所有的block会合并成一个完整的最终文件。
HDFS 在读取文件的时候,如果其中一个块突然损坏了怎么办
- 客户端读取完 DataNode 上的块之后会进行 checksum 验证,也就是把客户端读取 到本地的块与 HDFS 上的原始块进行校验,如果发现校验结果不一致,客户端会 通知 NameNode,然后再从下一个拥有该 block 副本的 DataNode 继续读。
HDFS 在上传文件的时候,如果其中一个 DataNode 突然挂掉了怎么办
- 客户端上传文件时与 DataNode 建立 pipeline 管道,管道的正方向是客户端向 DataNode 发送的数据包,管道反向是 DataNode 向客户端发送 ack 确认,也就是 正确接收到数据包之后发送一个已确认接收到的应答。 当 DataNode 突然挂掉了,客户端接收不到这个 DataNode 发送的 ack 确认,客户 端会通知 NameNode,NameNode 检查该块的副本与规定的不符,NameNode 会通知 DataNode 去复制副本,并将挂掉的 DataNode 作下线处理,不再让它参与文件上 传与下载。
HDFS故障类型和其检测方法
HDFS读写故障的处理:
DataNode 故障处理
HDFS副本机制
HDFS文件副本机制
HDFS被设计成能够在一个大集群中跨机器可靠地存储超大文件。它将每个文件存储成一系列的数据块,这个数据块被称为block,除了最后一个,所有的数据块都是同样大小的。
- 为了容错,文件的所有block都会有副本。每个文件的数据块大小和副本系数都是可配置的。
- 所有的文件都是以 block 块的方式存放在 HDFS 文件系统当中,作用如下
- 一个文件有可能大于集群中任意一个磁盘,引入块机制,可以很好的解决这个问题
- 使用块作为文件存储的逻辑单位可以简化存储子系统
- 块非常适合用于数据备份进而提供数据容错能力
- 副本优点是安全,缺点是占空间。
在 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只是一个逻辑单位。
HDFS副本放置策略(机架感知):
HDFS分布式文件系统的内部有一个副本存放策略,默认副本数为3,在这里以副本数=3为例:
第一副本:优先放置到离写入客户端最近的DataNode节点,如果上传节点就是DataNode,则直接上传到该节点,如果是在集群外提交,则随机挑选一台磁盘不太慢,CPU不太忙的节点。
第二个副本:放置在与第一个同机架的不同机器中
第三个副本:放置在另一个机架中, 某一个服务器中
通过机架感知的过程,NameNode可以确定每一个 DataNode所属的机架id。一个简单但没有优化的策略就是将副本存放在不同的机架上(上边介绍的这种),这样可以防止当整个机架失效时数据的丢失,并且允许读数据的时候充分利用多个机架的带宽。这种策略设置可以将副本均匀分布在集群中,有利于当组件失效的情况下的均匀负载。
也就是说, HDFS系统的机架感知策略的优势是防止由于某个机架失效导致数据丢失,并且允许读取数据时充分利用多个机架的带宽。HDFS会尽量让读取任务去读取距离客户端最近的副本数据来减少整体带宽消耗,从而实现降低整体的带宽延时。
对于副本距离的计算公式,HDFS采用如下约定:
- Distance(Rack 1/D1 Rack1/D1)=0 //同一台服务器的距离为0
- Distance(Rack 1/D1 Rack1/D3)=2 //通机架不同服务器的距离为2
- Distance(Rack 1/D1 Rack2/D1)=4 //不同机架服务器距离为4
通常而言,一个Rack共享一个电源,一根网线,一个交换机,HDFS备份通常在同一个Rack上存储一份,在另外一个Rack上存储两份(另外:HDFS以block为单位,备份也要以block为单位)
通过机架感知,处于工作状态的HDFS总是设法确保数据块的三个副本(或者更多)中至少有两个在同一机架,至少有一个处在不同机架。
HDFS的元数据辅助管理
当 Hadoop 的集群当中, NameNode的所有元数据信息都保存在了 FsImage 与 Eidts 文件当中, 这两个文件就记录了所有的数据的元数据信息, 元数据信息的保存目录配置在了 hdfs-site.xml
当中
<property>
<name>dfs.namenode.name.dir</name>
<value>
file:///export/serverss/hadoop2.7.5/hadoopDatas/namenodeDatas</value>
</property>
<property>
<name>dfs.namenode.edits.dir</name>
<value>file:///export/serverss/hadoop-2.7.5/hadoopDatas/nn/edits</value>
</property>>
FsImage和Edits
edits:
edits 是在NameNode启动时对整个文件系统的快照存放了客户端最近一段时间的操作日志
客户端对 HDFS 进行写文件时会首先被记录在 edits文件中edit 修改时元数据也会更新
fsimage:
fsimage是在NameNode启动时对整个文件系统的快照
NameNode 中关于元数据的镜像, 一般称为检查点, fsimage存放了一份比较完整的元数据信息
因为 Fsimage是 NameNode 的完整的镜像, 如果每次都加载到内存生成树状拓扑结构,这是非常耗内存和CPU, 所以一般开始时对 NameNode 的操作都放在 edits 中
fsimage 内容包含了 NameNode 管理下的所有 DataNode 文件及文件 block 及 block 所在的 DataNode 的元数据信息.
随着edits`内容增大, 就需要在一定时间点和 fsimage合并
SecondaryNameNode的作用
SecondaryNameNode的作用是合并fsimage和edits文件。
NameNode的存储目录树的信息,而目录树的信息则存放在fsimage文件中,当NameNode启动的时候会首先读取整个fsimage文件,将信息装载到内存中。
Edits文件存储日志信息,在NameNode上所有对目录的操作,增加,删除,修改等都会保存到edits文件中,并不会同步到fsimage中,当NameNode关闭的时候,也不会将fsimage和edits进行合并。
所以当NameNode启动的时候,首先装载fsimage文件,然后按照edits中的记录执行一遍所有记录的操作,最后把信息的目录树写入fsimage中,并删掉edits文件,重新启用新的edits文件。
SecondaryNameNode出现的原因
但是如果NameNode执行了很多操作的话,就会导致edits文件会很大,那么在下一次启动的过程中,就会导致NameNode的启动速度很慢,慢到几个小时也不是不可能,所以出现了SecondNameNode。
SecondaryNameNode唤醒合并的规则
SecondaryNameNode 会按照一定的规则被唤醒,进行fsimage和edits的合并,防止文件过大。
合并的过程是,将NameNode的fsimage和edits下载到SecondryNameNode 所在的节点的数据目录,然后合并到fsimage文件,最后上传到NameNode节点。合并的过程中不影响NameNode节点的操作
SecondaryNameNode被唤醒的条件可以在core-site.xml中配置:
fs.checkpoint.period:单位秒,默认值3600,检查点的间隔时间,当距离上次检查点执行超过该时间后启动检查点
fs.checkpoint.size:单位字节,默认值67108864,当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执行合并过程。
SecondaryNameNode工作过程
- 第一步:将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进行工作,一直这样循环操作。
fsimage 中的文件信息查看
使用命令 hdfs oiv
cd /export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas
hdfs oiv -i fsimage_0000000000000000864 -p XML -o hello.xml
edits中的文件信息查看
使用命令 hdfs oev
cd /export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas
hdfs oev -i edits_0000000000000000865-0000000000000000866 -p XML -o myedit.xml
NameNode元数据恢复
当NameNode发生故障时,我们可以通过将SecondaryNameNode中数据拷贝到NameNode存储数据的目录的方式来恢复NameNode的数据
操作步骤:
1、杀死NameNode进程
kill -9 NameNode进程号
2、删除NameNode存储的数据
rm /export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas/* -fr
3、拷贝SecondaryNameNode中数据到原NameNode存储数据目录
cd /export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas/
scp -r node2:/export/servers/hadoop-2.7.5/hadoopDatas/snn/name/* ./
3、重新启动NameNode
hadoop-daemon.sh start namenode
HDFS的shell命令
Shell命令行客户端
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作为参数。URI格式为scheme://authority/path。对于HDFS,该scheme是hdfs,对于本地FS,该scheme是file。scheme和authority是可选的。如果未指定,则使用配置中指定的默认方案。
对于HDFS,命令示例如下:
hadoop fs -ls hdfs://namenode:host/parent/child hadoop fs -ls /parent/child
#hdfs-site.xml中的fs.defaultFS中有配置
对于本地文件系统,命令示例如下:
hadoop fs -ls file:///root/
如果使用的文件系统是HDFS,则也可使用hdfs dfs <args>
命令。
Shell命令选项
选项名称 | 使用格式 | 含义 |
---|---|---|
-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路径> | 创建空白文件夹 |
-setrep | -setrep [-R] [-w] <副本数> <路径> | 修改副本数量 |
-touchz | -touchz <文件路径> | 创建空白文件 |
-stat | -stat [format] <路径> | 显示文件统计信息 |
-tail | -tail [-f] <文件> | 查看文件尾部信息 |
-chmod | -chmod [-R] <权限模式> [路径] | 修改权限 |
-chown | -chown [-R] [属主] [:[属组]] 路径 | 修改属主 |
-chgrp | -chgrp [-R] 属组名称 路径 | 修改属组 |
-help | -help [命令选项] | 帮助 |
常用的Shell命令
-ls
- 格式: hadoop fs **-**ls URI
- 作用:类似于Linux的ls命令,显示文件列表 hadoop fs -ls /
-lsr
- 格式 : hdfs dfs **-**lsr URI
- 作用 : 在整个目录下递归执行ls**,** 与UNIX中的ls-R类似
- hadoop fs -lsr /
-mkdir
- 格式 : hdfs dfs [-p] -mkdir
- 作用 : 以中的URI作为参数,创建目录。使用-p参数可以递归创建目录
- hadoop fs -mkdir /dir1
- hadoop fs -mkdir /dir2
- hadoop fs -p -mkdir /aaa/bbb/ccc
-put
- 格式 : hadoop fs -put …
- 作用 : 将单个的源文件src或者多个源文件srcs从本地文件系统拷贝到目标文件系统中(对应的路径),也可以从标准输入中读取输入,写入目标文件系统中
- echo “Hello HDFS” >> /root/1.txt
- hadoop fs -put /root/1.txt /dir1
-moveFromLocal
- 格式: hdfs dfs **-**moveFromLocal <localsrc> <dst>
- 作用**😗* 和put命令类似,但是源文件localsrc拷贝之后自身被删除
- echo “Hello HDFS” >> /root/2.txt
- hdfs dfs -moveFromLocal /root/2.txt /
-moveToLocal
- 未实现
-get
- 格式 hadoop fs -get [-ignorecrc ] [-crc]
- 作用:将文件拷贝到本地文件系统。 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/下有多个文件:log.1, log.2,log.3,… hadoop fs -getmerge /aaa/log.* ./log.sum
-mv
- 格式 : hdfs dfs -mv URI
- 作用: 将hdfs上的文件从原路径移动到目标路径(移动之后文件删除),该命令不能夸文件系统 hdfs dfs -mv /dir1/a.txt /dir2
-rm
- 格式: hadoop fs -rm [-r] 【-skipTrash】 URI 【URI 。。。】
- 作用: 删除参数指定的文件和目录,参数可以有多个,删除目录需要加-r参数 如果指定-skipTrash选项,那么在回收站可用的情况下,该选项将跳过回收站而直接删除文件; 否则,在回收站可用时,在HDFS Shell 中执行此命令,会将文件暂时放到回收站中。
- hadoop fs -rm /2.txt #删除文件
- hadoop fs -rm -r /dir1 #删除目录
-cp
- 格式: hdfs dfs -cp URI [URI …]
- 作用: 将文件拷贝到目标路径中。如果 为目录的话,可以将多个文件拷贝到该目录下。 -f 选项将覆盖目标,如果它已经存在。 -p 选项将保留文件属性(时间戳、所有权、许可、ACL、XAttr)。
- hadoop fs -cp /dir1/1.txt /dir2/2.txt
-cat
- 格式:hadoop fs -cat URI [uri …]
- 作用:将参数所指示的文件内容输出到控制台
- hadoop fs -cat /dir2/2.txt
-du
- 格式:hadoop fs -du URI
- 功能:显示目录中所有文件大小,当只指定一个文件时,显示此文件的大小。
- 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 …
- 作用: 追加一个或者多个文件到hdfs指定文件中.也可以从命令行读取输入.
- cd /export/servers/hadoop2.7.5/etc/hadoop/
- hadoop fs -appendToFile *.xml /big.xml
HDFS的高级使用命令
HDFS的安全模式
安全模式是hadoop的一种保护机制,用于保证集群中的数据块的安全性。当集群启动的时候,会首先进入安全模式。当系统处于安全模式时会检查数据块的完整性。
假设我们设置的副本数(即参数dfs.replication)是3,那么在datanode上就应该有3个副本存在,假设只存在2个副本,那么比例就是2/3=0.666。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 #离开安全模式
HDFS基准测试
实际生产环境当中,hadoop的环境搭建完成之后,第一件事情就是进行压力测试,测试我们的集群的读取和写入速度,测试我们的网络带宽是否足够等一些基准测试
测试写入速度
向HDFS文件系统中写入数据,10个文件,每个文件10MB,文件存放到/benchmarks/TestDFSIO中
hadoop jar /export/servers/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
测试读取速度
测试hdfs的读取文件性能
在HDFS文件系统中读入10个文件,每个文件10M
hadoop jar /export/servers/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
清除测试数据
hadoop jar /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -clean
HDFS的API操作
HDFS的JAVA API操作
HDFS在生产应用中主要是客户端的开发,其核心步骤是从HDFS提供的api中构造一个HDFS的访问客户端对象,然后通过该客户端对象操作(增删改查)HDFS上的文件。
配置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
或者:
java.io.IOException: (null) entry in command string: null chmod 0644
搭建步骤:
第一步:将已经编译好的Windows版本Hadoop解压到到一个没有中文没有空格的路径下面
第二步:在windows上面配置hadoop的环境变量: HADOOP_HOME,并将%HADOOP_HOME%\bin添加到path中
第三步:把hadoop2.7.5文件夹中bin目录下的hadoop.dll文件放到系统盘: C:\Windows\System32 目录下
第四步:关闭windows重启
导入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>
使用文件系统方式访问数据
涉及的主要类
在java中操作HDFS,主要涉及以下Class:
Configuration:该类的对象封转了客户端或者服务器的配置;
FileSystem:该类的对象是一个文件系统对象,可以用该对象的一些方法来对文件进行操作,通过FileSystem的静态方法get获得该对象。
FileSystem fs = FileSystem.get(conf);
get方法从conf中的一个参数 fs.defaultFS的配置值判断具体是什么类型的文件系统。如果我们的代码中没有指定fs.defaultFS,并且工程classpath下也没有给定相应的配置,conf中的默认值就来自于hadoop的jar包中的core-default.xml,默认值为: file:///,则获取的将不是一个DistributedFileSystem的实例,而是一个本地文件系统的客户端对象。
获取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);
}
@Test
public void test01() throws IOException, URISyntaxException, InterruptedException {
/**
* 如何获取一个抽象类的对象:
* 1:通过子类对象来构建
* 2:通过工厂的方式类构建
* 3:通过这个抽象类本身是否具有返回值本身的静态方法
*/
Configuration conf = new Configuration();
// 如果我们什么都不指定,就默认连接本地的文件系统
FileSystem fileSystem1 = FileSystem.get(conf);
System.out.println(fileSystem1.toString());
System.out.println("------------------------");
// 注意:默认情况下,windows操作hsfs,使用的是当前windows的用户名
conf= new Configuration();
conf.set("fs.defaultFS","hdfs://node1:8020");
FileSystem fileSystem2 = FileSystem.get(conf);
System.out.println(fileSystem2.toString());
System.out.println("---------------------");
// 伪装用户的操作
URI uri = new URI("hdfs://node1:8020");
conf = new Configuration();
FileSystem fileSystem3 = FileSystem.get(uri, conf, "root");
System.out.println(fileSystem3.toString());
System.out.println("------------------");
uri = new URI("hdfs://node1:8020");
conf = new Configuration();
FileSystem fileSystem4 = FileSystem.get(uri, conf);
System.out.println(fileSystem4.toString());
}
获取HDFS上某一个路径下的所有文件
// 获取HDFS上某一个路径下的所有文件
@Test
public void test02() throws Exception {
// 获取HDFS的客户端对象
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration(), "root");
// 执行相关的操作(获取某一个路径下的所有文集)
RemoteIterator<LocatedFileStatus> listFiles = fileSystem.listFiles(new Path("/aaa"), true);
while (listFiles.hasNext()){
LocatedFileStatus fileStatus = listFiles.next();
Path path = fileStatus.getPath();
System.out.println(path);
System.out.println(path.getName());
}
// 释放资源
fileSystem.close();
}
在HDFS中创建一个目录
// 在HDFS中创建一个目录
@Test
public void test03() throws Exception {
// 获取一个HDFS的客户端对象
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration(), "root");
//执行相关的操作--在HDFS中创建一个目录
boolean mkdirs = fileSystem.mkdirs(new Path("/test/bbb/test1"));
System.out.println(mkdirs);
// 释放资源
fileSystem.close();
}
在HDFS中创建一个文件
// 在HDFS创建一个文件
@Test
public void test04() throws Exception {
// 获取HDFS的客户端对象
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration(), "root");
// 执行相关词操作-- 向HDFS中写一个文件
FSDataOutputStream outputStream = fileSystem.create(new Path("/test/bbb/test1/test.txt"));
outputStream.write("你好,我是李旭飞".getBytes());
outputStream.flush();
// 释放资源
fileSystem.close();
}
文件下载
// 使用HDFS完成文件的下载的操作
@Test
public void test05() throws IOException {
// 获取HDFS客户端对象
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://node1:8020");
FileSystem fileSystem = FileSystem.get(conf);
// 执行相关的操作
// 参数一:HDFS的地址,参数二:本地的文件路径:一定要加file:///
fileSystem.copyToLocalFile(new Path("/test/bbb/test1/test.txt"),new Path("file:///C:\\Users\\Dell\\Desktop"));
// 释放资源
fileSystem.close();
}
文件的上传
// 完成HDFS文件的上传操作
@Test
public void test06() throws IOException {
// 获取HDFS的客户端对象
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://node1:8020");
FileSystem fileSystem = FileSystem.get(conf);
// 执行相关操作-- 上传文件
fileSystem.copyFromLocalFile(new Path("file:///C:\\Users\\Dell\\Desktop\\bigSchool.txt"),new Path("/test/bbb/test1/"));
// 释放资源
fileSystem.close();
}
合并小文件
由于 Hadoop 擅长存储大文件,因为大文件的元数据信息比较少,如果 Hadoop 集群当中有大量的小文件,那么每个小文件都需要维护一份元数据信息,会大大的增加集群管理元数据的内存压力,所以在实际工作当中,如果有必要一定要将小文件合并成大文件进行一起处理,可以在上传的时候将小文件合并到一个大文件里面去。
// 假设在本地有几个小文件,需要传递到HDFS中,HDFS不推荐传递小文件,将这些个小文件合并为一个大文件,同时上传到HDFS
@Test
public void test07() throws Exception {
// 创建HDFD客户端对象
FileSystem hdfsFileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration());
// 执行相关操作,创建一个文件,获取这个文件的输出流
FSDataOutputStream outputStream = hdfsFileSystem.create(new Path("/test/merge.txt"));
// 获取一个本地文件系统输入流
LocalFileSystem localFileSystem = FileSystem.getLocal(new Configuration());
// 获取某个路径下所有的小文件
RemoteIterator<LocatedFileStatus> locatFileSystem = localFileSystem.listFiles(new Path("file:///C:\\Users\\Dell\\Desktop\\xiaowenjian"), false);
while (locatFileSystem.hasNext()){
LocatedFileStatus fileStatus = locatFileSystem.next();
Path path = fileStatus.getPath();
// FileInputStream fileInputStream = new FileInputStream(path.toString());
FSDataInputStream inputStream = localFileSystem.open(path);
IOUtils.copy(inputStream, outputStream);
IOUtils.closeQuietly(inputStream);
}
outputStream.flush();
hdfsFileSystem.close();
localFileSystem.close();
}
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
-
修改node1机器上的hdfs-site.xml当中的配置文件
vim hdfs-site.xml
<property> <name>dfs.permissions.enabled</name> <value>true</value> </property>
-
修改完成之后配置文件发送到其他机器上面去
scp hdfs-site.xml node2:$PWD scp hdfs-site.xml node3:$PWD
-
重启hdfs集群
start-dfs.sh
-
随意上传一些文件到我们hadoop集群当中准备测试使用
cd /export/servers/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文件的可读,可写权限。
- 使用代码准备下载文件
@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();
}
执行结果如下:
执行成功
HDFS的高可用机制
高可用简介:
在Hadoop 中,NameNode 所处的位置是非常重要的,整个HDFS文件系统的元数据信息都由NameNode 来管理,NameNode的可用性直接决定了Hadoop 的可用性,一旦NameNode进程不能工作了,就会影响整个集群的正常使用。
在典型的HA集群中,两台独立的机器被配置为NameNode。在工作集群中,NameNode机器中的一个处于Active状态,另一个处于Standby状态。Active NameNode负责群集中的所有客户端操作,而Standby充当从服务器。Standby机器保持足够的状态以提供快速故障切换(如果需要)。
组件介绍
ZKFailoverController
是基于Zookeeper的故障转移控制器,它负责控制NameNode的主备切换,ZKFailoverController会监测NameNode的健康状态,当发现Active NameNode出现异常时会通过Zookeeper进行一次新的选举,完成Active和Standby状态的切换
HealthMonitor
周期性调用NameNode的HAServiceProtocol RPC接口(monitorHealth 和 getServiceStatus),监控NameNode的健康状态并向ZKFailoverController反馈
ActiveStandbyElector
接收ZKFC的选举请求,通过Zookeeper自动完成主备选举,选举完成后回调ZKFailoverController的主备切换方法对NameNode进行Active和Standby状态的切换.
DataNode
NameNode包含了HDFS的元数据信息和数据块信息(blockmap),其中数据块信息通过DataNode主动向Active NameNode和Standby NameNode上报
共享存储系统
共享存储系统负责存储HDFS的元数据(EditsLog),Active NameNode(写入)和 Standby NameNode(读取)通过共享存储系统实现元数据同步,在主备切换过程中,新的Active NameNode必须确保元数据同步完成才能对外提供服务
Hadoop的联邦机制(Federation)
背景概述
单NameNode的架构使得HDFS在集群扩展性和性能上都有潜在的问题,当集群大到一定程度后,NameNode进程使用的内存可能会达到上百G,NameNode成为了性能的瓶颈。因而提出了namenode水平扩展方案-- Federation。
Federation中文意思为联邦,联盟,是NameNode的Federation,也就是会有多个NameNode。多个NameNode的情况意味着有多个namespace(命名空间),区别于HA模式下的多NameNode,它们是拥有着同一个namespace。既然说到了NameNode的命名空间的概念,这里就看一下现有的HDFS数据管理架构,如下图所示:
从上图中,我们可以很明显地看出现有的HDFS数据管理,数据存储2层分层的结构.也就是说,所有关于存储数据的信息和管理是放在NameNode这边,而真实数据的存储则是在各个DataNode下.而这些隶属于同一个NameNode所管理的数据都是在同一个命名空间下的.而一个namespace对应一个block pool。Block Pool是同一个namespace下的block的集合.当然这是我们最常见的单个namespace的情况,也就是一个NameNode管理集群中所有元数据信息的时候.如果我们遇到了之前提到的NameNode内存使用过高的问题,这时候怎么办?元数据空间依然还是在不断增大,一味调高NameNode的jvm大小绝对不是一个持久的办法.这时候就诞生了HDFS Federation的机制.
Federation架构设计
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汇报本地存储可用资源情况。
HDFS Federation不足
HDFS Federation并没有完全解决单点故障问题。虽然namenode/namespace存在多个,但是从单个namenode/namespace看,仍然存在单点故障:如果某个namenode挂掉了,其管理的相应的文件便不可以访问。Federation中每个namenode仍然像之前HDFS上实现一样,配有一个secondary namenode,以便主namenode挂掉一下,用于还原元数据信息。
所以一般集群规模真的很大的时候,会采用HA+Federation的部署方案。也就是每个联合的namenodes都是ha的。
HDFS的其他功能
不同集群之间的数据复制
在我们实际工作当中,极有可能会遇到将测试集群的数据拷贝到生产环境集群,或者将生产环境集群的数据拷贝到测试集群,那么就需要我们在多个集群之间进行数据的远程拷贝,hadoop自带也有命令可以帮我们实现这个功能。
集群内部文件拷贝scp
本地复制到远程
方式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/
远程复制到本地
远程复制到本地 与 从本地复制到远程命令类似,不同的是 远程文件作为源文件在前,本地文件作为目标文件在后。
#复制文件-将192.168.88.162的/root目录下的test.txt拷贝到当前主机的/root/目录下,文件名不变
scp root@192.168.88.162:/root/test.txt /root/test.txt
跨集群之间的数据拷贝distcp
DistCp(distributed copy)是一款被用于大型集群间/集群内的复制工具,该命令的内部原理是MapReduce。
cd /export/serverss/hadoop-2.7.5/
bin/hadoop distcp hdfs://node1:8020/jdk-8u241-linux-x64.tar.gz hdfs://cluster2:8020/
Archive档案的使用
HDFS并不擅长存储小文件,因为每个文件最少一个block,每个block的元数据都会在NameNode占用内存,如果存在大量的小文件,它们会吃掉NameNode节点的大量内存。
Hadoop Archives可以有效的处理以上问题,它可以把多个文件归档成为一个文件,归档成一个文件后还可以透明的访问每一个文件。
如何创建Archive
Usage: hadoop archive -archiveName name -p *
其中-archiveName是指要创建的存档的名称。比如test.har,archive的名字的扩展名应该是*.har。 -p参数指定文件存档文件(src)的相对路径。
例如:如果你只想存档一个目录/input下的所有文件:
hadoop archive -archiveName test.har -p /config /outputdir
这样就会在/outputdir目录下创建一个名为test.har的存档文件。
如何查看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/fileinarchive
如果用har uri去访问的话,索引、标识等文件就会隐藏起来,只显示创建档案之前的原文件:
查看归档文件中的小文件,使用har uri
hadoop fs -ls har://hdfs-node1:8020/outputdir/test.har
查看归档文件中的小文件,不使用har uri
hadoop fs -ls har:///outputdir/test.har
查看har归档文件中小文件的内容
hadoop fs -cat har:///outputdir/test.har/core-site.xml
如何解压Archive
hadoop fs -mkdir /config2
hadoop fs -cp har:///outputdir/test.har/* /config2
查看HDFS页面,发现/config2目录中已经有解压后的小文件了
Archive注意事项
-
Hadoop archives是特殊的档案格式。一个Hadoop archive对应一个文件系统目录。Hadoop archive的扩展名是*.har;
-
创建archives本质是运行一个Map/Reduce任务,所以应该在Hadoop集群上运行创建档案的命令,要提前启动Yarn集群;
-
创建archive文件要消耗和原文件一样多的硬盘空间;
-
archive文件不支持压缩,尽管archive文件看起来像已经被压缩过;
-
archive文件一旦创建就无法改变,要修改的话,需要创建新的archive文件。事实上,一般不会再对存档后的文件进行修改,因为它们是定期存档的,比如每周或每日;
-
当创建archive时,源文件不会被更改或删除;
Snapshot快照的使用
快照顾名思义,就是相当于对hdfs文件系统做一个备份,可以通过快照对指定的文件夹设置备份,但是添加快照之后,并不会立即复制所有文件,而是指向同一个文件。当写入发生时,才会产生新文件。
快照使用基本语法
1、开启指定目录的快照功能
hdfs dfsadmin -allowSnapshot 路径
2、禁用指定目录的快照功能(默认就是禁用状态)
hdfs dfsadmin -disallowSnapshot 路径
3、给某个路径创建快照snapshot
hdfs dfs -createSnapshot 路径
4、指定快照名称进行创建快照snapshot
hdfs dfs -createSanpshot 路径 名称
5、给快照重新命名
hdfs dfs -renameSnapshot 路径 旧名称 新名称
6、列出当前用户所有可快照目录
hdfs lsSnapshottableDir
7、比较两个快照的目录不同之处
hdfs snapshotDiff 路径1 路径2
8、删除快照snapshot
hdfs dfs -deleteSnapshot <path> <snapshotName>
快照操作实际案例
1、开启指定目录的快照
hdfs dfsadmin -allowSnapshot /config
2、对指定目录创建快照
注意:创建快照之前,先要允许该目录创建快照
hdfs dfs -createSnapshot /config
通过web浏览器访问快照
http://node1:50070/explorer.html#/config/.snapshot/
指定名称创建快照
hdfs dfs -createSnapshot /config mysnap1
4、重命名快照
hdfs dfs -renameSnapshot /config mysnap1 mysnap2
5、列出当前用户所有可以快照的目录
hdfs ls SnapshottableDir
6、比较快照不同之处
hdfs snapshotDiff /config . .snapshot/s20200522-220535.107
7、删除快照
hdfs dfs -deleteSnapshot /user snap1
HDFS的Trash回收站功能
和Linux系统的回收站设计一样,HDFS会为每一个用户创建一个回收站目录:**/user/**用户名/.Trash/current,每一个被用户通过Shell删除的文件/目录,在系统回收站中都一个周期,也就是当系统回收站中的文件/目录在一段时间之后没有被用户恢复的话,HDFS就会自动的把这个文件/目录彻底删除,之后,用户就永远也找不回这个文件/目录了。
如果检查点已经启用,会定期使用时间戳重命名Current目录。.Trash中的文件在用户可配置的时间延迟后被永久删除。回收站中的文件和目录可以简单地通过将它们移动到.Trash目录之外的位置来恢复。
配置
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>
<property>
<name>fs.trash.checkpoint.interval</name>
<value>0</value>
<description>Number of minutes between trash checkpoints. Should be smaller or equal to fs.trash.interval. If zero, the value is set to the value of fs.trash.interval.</description>
</property>
属性 | 说明 |
---|---|
fs.trash.interval | 分钟数,回收站文件的存活时间, 当超过这个分钟数后文件会被删除。如果为零,回收站功能将被禁用。 |
fs.trash.checkpoint.interval | 检查点创建的时间间隔(单位为分钟)。其值应该小于或等于fs.trash.interval 。如果为零,则将该值设置为fs.trash.interval 的值。 |
检查点
检查点仅仅是用户回收站下的一个目录,用于存储在创建检查点之前删除的所有文件或目录。如果你想查看回收站目录,可以在/user/${username}/.Trash/{timestamp_of_checkpoint_creation}处看到:
最近删除的文件被移动到回收站Current
目录,并且在可配置的时间间隔内,HDFS
会为在Current
回收站目录下的文件创建检查点/user/${username}/.Trash/<``日期>
,并在过期时删除旧的检查点。
恢复回收站数据
hadoop fs -mv /user/root/.Trash/200523093000/hadoop-env.sh /config
清空回收站
首先想到的是只要删除整个回收站目录,将会清空回收站。诚然,这是一个选择。但是我们有更好的选择。`HDFS提供了一个命令行工具来完成这个工作:
hadoop fs -expunge
该命令使NameNode
永久删除回收站中比阈值更早的文件,而不是等待下一个emptier
窗口。它立即从文件系统中删除过期的检查点。
注意点
回收站功能默认是禁用的。对于生产环境,建议启用回收站功能以避免意外的删除操作。启用回收站提供了从用户操作删除或用户意外删除中恢复数据的机会。但是为fs.trash.interval
和fs.trash.checkpoint.interval
设置合适的值也是非常重要的,以使垃圾回收以你期望的方式运作。例如,如果你需要经常从HDFS
上传和删除文件,则可能需要将fs.trash.interval
设置为较小的值,否则检查点将占用太多空间。
当启用垃圾回收并删除一些文件时,HDFS
容量不会增加,因为文件并未真正删除。
回收站功能默认只适用于使用Hadoop shell 删除的文件和目录。使用其他接口(例如Web HDF或 `java API)以编程的方式删除的文件或目录不会移动到回收站,即使已启用回收站,除非程序已经实现了对回收站功能的调用。
有时你可能想要在删除文件时临时禁用回收站,也就是删除的文件或目录不用放在回收站而直接删除,在这种情况下,可以使用-skipTrash
选项运行rm
命令。例如:
hadoop fs -rm -skipTrash /dir1/a.txt
参考资料
1. 传智播客博学谷.大数据课程HDFS笔记
2. 翻译经典 HDFS 原理讲解漫画](https://blog.csdn.net/hudiefenmu/article/details/37655491)
3. HDFS的Trash回收站功能](https://www.cnblogs.com/cyfighting/p/4678384.html)
4. 大讲台大数据研习社.Hadoop大数据技术基础及应用[M].北京:机械工业出版社,2018.12
5. 林子雨. 大数据技术原理与应用(第二版)[M].北京:人民邮电出版社,2017.1