今日内容:1) HDFS基本的概念 架构中相关的机制 -- 理解2) HDFS的shell命令的操作: --唯一的操作 3) HDFS的基本原理: 4) hdfs的工作机制: --- 记忆 (能够拿自己的话出来) hdfs的写数据的流程 hdfs的读数据的流程5) hdfs的元数据辅助管理机制 --- 记忆
1) hdfs的基本概念: HDFS是 分布式文件存储系统
分布式文件存储系统: 一般有多台能够存储数据的节点(服务器) + 一台去管理这些存储节点的服务器(主节点) 整个分布式文件存储系统: 容量大小 你凑五毛 我凑五毛 我们共同凑一台过程
HDFS就是一个hadoop的分布式文件存储系统, 是大数据中专门用来存储海量数据的容器,支持存储上TB/PB级别以上的数据
2) HDFS的应用场景: 适用场景: 1) 存储大文件 (单个文件比较大) 2) 一次写入、多次读取 不支持随机修改一个文件内容 3) 构建HDFS, 有廉价的服务器即可满足数据存储 4) 对数据提供扩展能力,保证数据不丢失 5) 对实时性要求不高的场景 不适用场景: 1) 低延时的数据访问 对延时要求在毫秒级别的应用 2) 大量小文件, 也不适合使用HDFS 小文件也需要管理 namenode多了增大消耗 3) 需要对文件内容进行随机修改的场景
3) HDFS的架构: HDFS的client: hdfs的客户端 作用: 发起请求 负责文件块的切分操作 和 合并过程 hdfs的主节点: namenode 可以有多个的, 最多只有2个 作用: 存储元数据信息(内存的) 管理众多的从节点 接收客户端发送过来请求, 并向datanode下达命令 hdfs的从节点: datanode 可以有多个的 作用: 负责数据的存储 负责数据的最终读写操作 datanode要主动和namenode保持心跳连接 hdfs的辅助接点: secondnamenode 作用: 赋值namenode进行元数据的管理
副本机制: hdfs将文件会拆分多个block块的, 默认情况下, 一个block大小为128M 每个block可以构建多个副本, 副本数量最多和datanode的节点数量是相等的 默认情况下 为 3个
注意: block本质上是一个逻辑架构, 并不是真实占用空间, 一个块具体占用多大的磁盘空间 取决于块中文件数据的大小,最多为128M 负载均衡机制: namenode在分配块放置在那些节点的时候, 会尽可能保证让每个datanode块是均衡得 心跳机制: datanode每隔3秒 会给namenode发送一次心跳包, 报告自己的状态, 如果在一定时间(10分钟+30s)范围内 没有发送心跳包, 那么namenode会认为当前这个datanode是否已经宕机了
4) HDFS的机架感知原理: 描述当有多个机架的时候, 副本如何放置的问题 第一副本:优先放置到离写入客户端最近的DataNode节点,如果上传节点就是DataNode,则直接上传到该节点,如果是集群外提交,则随机挑选一台磁盘不太慢,CPU不太忙的节点。 第二个副本:放置在另一个机架中, 某一个服务器中 不用机架为了安全 第三个副本:放置在与第二个同机架的不同机器中 同机架 为了效率
5) HDFS的shell命令的操作: hadoop中hdfs的提供的命令客户端格式: hadoop fs <args> 是在hadoop1.0版本就已经在开始使用了 hdfs dfs <args> 是hadoop2.0出现新的操作hdfs的命令
如果操作的时候 hdfs的, 建议采用 hdfs dfs 操作 选项名称 使用格式 含义 -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 [命令选项] 帮助
hdfs的常见命令: hdfs dfs -ls [-R] path 查看hdfs的目录结构 hadoop fs -mkdir -p path 在hdfs中创建目录 hdfs dfs -put localFile hdfsPath 将linux本地文件上传到HDFS中 本地依然是存在的 hdfs dfs -moveFromLocal localFile hdfsPath 将linux本地文件移动hdfs的指定目录下 hdfs dfs -get hdfsFile localPath 将 hdfs的文件下载到本地 hdfs dfs -getmerge hdfsFile.... localPath 合并下载 hdfs dfs -mv hdfsPath hdfsPath 将文件从hdfs的某一个路径 移动到hdfs的另一个路径下 hdfs dfs -rm -r [-skipTrash] hdfsPath 删除hdfs中文件或者目录的操作 hdfs dfs -cp -r hdfsPath hdfsPath 将文件从hdfs的某一个路径 复制到hdfs的另一个路径下 hdfs dfs -cat hdfsPath 查看文件的内容 hdfs dfs -du hdfsPath 查看文件的大小 hdfs dfs -chmod -R 权限信息 hdfsPath 设置hdfs的目录或者文件的权限 hdfs的权限管理原则: 只能防止好人做错事, 不能防止坏人做坏事 hdfs dfs -appendToFile localFile hdfsFile 将本地的某一个文件内容, 追加到hdfs的某一个文件尾部
如果想要将按照目录从 /export/servers 移动到 /export/server下 : 可选项 仅仅是建议 第一步: 创建一个 /export/server mkdir -p /export/server 第二步: 进入 servers目录下, 执行移动操作: cd /export/servers mv * ../server rm -rf /export/servers 前二步 是三台机子都要干的
第三步: 修改 hadoop的配置文件: hadoop-env.sh core-site.xml hdfs-site.xml 修改点: 将所有的servers的目录更换为server 第四步: 修改后, 将这个三个文件发送到第二台和第三台 cd /export/server/hadoop-2.7.5/etc/hadoop scp -r hadoop-env.sh core-site.xml hdfs-site.xml node2:$PWD scp -r hadoop-env.sh core-site.xml hdfs-site.xml node3:$PWD 第五步: 修改zookeeper的conf目录下的 zoo.cfg 修改一个目录结构 改后后, 通过scp命令发送给 node2 和 node3 第六步:修改 /etc/profile的环境变量: 三台都要改 改 jdk的目录 和 hadoop的目录
改了之后记得 source /etc/profile
6) hdfs的安全模式: hdfs的安全模式是hdfs的一种保护机制 主要目的是为了保证hdfs中文件块的有效率 1) 在刚刚启动hadoop的时候, hdfs会首先进入安全模式下, 在这个模式下, 要求datanode向namenode报告块信息, 有namenode来检测 块的副本数量是否完整(99.9%)以上, 认为是块是完整的, 在这个过程中, 如果发现某一个块不足, 会自动通知datanode添加副本块 如果副本块多个, 就会通知datannode删除指定块副本操作 如果都ok, 安全模式将在30s 自动退出, 如果发现有问题 直到所有所有副本解决了, 才会自动退出 2) 在运行过程中, 也在定时检测, 如果发现有问题, 自动进行安全模式 安全模式的相关的命令: hdfs dfsadmin -safemode get #查看安全模式状态 hdfs dfsadmin -safemode enter #进入安全模式 hdfs dfsadmin -safemode leave #离开安全模式 注意: 当后期发现迟迟无法退出安全模式, 可以尝试使用 hdfs dfsadmin -safemode leave强制离开安全模式 离开之后, hdfs主页面就会报错, 报错中会显示那个数据的块存在问题
解决方案: 常规解决方案 1) 可以尝试先将这个数据下载下来 2) 将hdfs的对应的出现问题的数据进行删除 3) 重新上传上去即可 如果数据不重要: 直接删除即可7) hdfs的压力检测(吞吐量检测) 第一步: 写入测试 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 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 jar /export/server/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -clean
8) hdfs的数据写入流程: 1. 客户端发送写入请求给namenode 2. namenode接收到请求, 然后首先判断当前操作的用户是否具有写入的权限, 如果没有,直接报错 如果有权限, 接着判断要写入的数据目录下是否 存在这个文件, 如果存在, 直接报错, 如果不存在, 此时就会给客户端返回可以写入的状态 3. 当客户端获取可以写入的状态后, 开始对文件执行切割操作, 默认情况下, 会按照128M方式来切割文件 4. 客户端拿着第一个block再次请求namenode, 让namenode为这个blcok分配datanode地址列表 5. namenode会根据datanode的块信息,以及根据 机架感知原理, 网络拓扑关系 和 副本信息 来挑选出最合适的datanode地址, 将这些地址按照 由近到远的顺序放置到列表中返回客户端 6. 客户端根据列表中第一个地址连接指定的datanode, 然后由这个datanode连接下一次, 然后由下一个连接下一个依次类推,由此 形成一个pipeline的管道 , 同时反向还会形成一条ack的校验管道 7. 客户端开始写入. 数据以数据包的形成进行传输, 一个数据包为64kb, 当第一个datanode接收到, 接着传输给下一个, 依次类推 同时,每一个接收到数据后, 都要在ack校验通道中进行记录 8. 第一个datanode, 将ack中校验信息收集起来, 统计发送给客户端,由客户端校验此数据包是否全部都接收到了 9. 客户端一次次的开始传输, 一次次进行校验, 直到将第一个block传输完成, 接下来拿的第二个block再次请求namenode, 获取block要存储在那些datanode上, 接下来执行第6~8 , 直到将所有的block传输完成, 到此写入流程结束了
![](https://i-blog.csdnimg.cn/blog_migrate/6fc535f1790c343539b77fbffd1f03aa.png)
9) hdfs的数据读取流程 1) 客户端发起数据读取的请求 2) namenode接收到数据读取的请求, 首先判断要读取的文件是否存在, 如果不存在, 直接报错, 如果存在, 接着会判断当前操作的用户是否具备 读取数据的权限, 如果没有 直接报错, 如果有权限, namenode 会根据 block信息, 机架感知原理, 网络拓扑关系, 副本信息 ,本地原则, 返回这个文件部分或者全部的block的地址 3) 客户端拿到block部分或者全部地址, 接下来, 采用并行读取策略, 将block数据全部读取到客户端 4) 如果namenode之前返回的部分的block地址, 此时客户端接着再次请求namenode, 获取下一批的block地址,执行第四步 以此类推, 直到将所有的block全部的读取到客户端 5) 客户端将读取到block数据按照顺序, 依次拼接 形成最终的文件 返回给用户
![](https://i-blog.csdnimg.cn/blog_migrate/da1086a972d2a87ab8e606aa36cc65f5.png)
10) SNN的数据写入的流程 第一步:通知namenode将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进行工作,一直这样循环操作。
今日内容:1) HDFS的javaAPI的操作 ---作业 操作2) HDFS不同的集群之间数据拷贝 --了解即可3) HDFS的归档文件操作 --知道作用, 以及进行相关的操作4) HDFS的数据快照功能 --了解即可5) HDFS的垃圾桶的机制 -- 知道作用6) HDFS的高可用机制 -- 能够参考课件 将其搭建成功即可7) HDFS的联邦机制 -- 了解
1) HDFS的 java API的操作:1.1: window的hadoop环境准备工作 mac可以先不做
2) HDFS不同的集群之间数据拷贝: 2.1: 服务器之间数据拷贝操作: scp命令 从本地服务器将数据发送给远端服务器 方式1:指定用户名,命令执行后需要再输入密码; scp -r local_folder remote_username@remote_ip:remote_folder
方式2:没有指定用户名,命令执行后需要输入用户名和密码; scp -r local_folder remote_ip:remote_folder 注意,如果实现了ssh免密登录之后,则不需要输入密码即可拷贝。
从远端服务器中将数据发送给本地服务器: 用的不是特别多 方式1:指定用户名,命令执行后需要再输入密码; scp -r remote_username@remote_ip:remote_folder local_folder
方式2:没有指定用户名,命令执行后需要输入用户名和密码; scp -r remote_ip:remote_folder local_folder 注意,如果实现了ssh免密登录之后,则不需要输入密码即可拷贝。
2.2: 集群之间的数据拷贝的工作: 数据迁移 hadoop distcp hdfs://node1:8020/jdk-8u241-linux-x64.tar.gz hdfs://cluster2:8020/ 底层执行MR 完成此处操作
3: HDFS的归档文件操作: 能够会使用 作用: 用来进行小文件合并的操作
方式一: 通过 javaAPI操作 实现小文件合并 使用场景: 同类型的文本数据合并工作 弊端: 多个文件数据合并在一个文件中, 导致后续进行拆分出现问题
方式二: 归档文件 一种类似于window中 zip方案, 将多个文件合并在一个文件中, 后续也可以将文件在解压还原出来
1. 如何创建归档文件: hadoop archive -archiveName name -p <parent> <src>* <dest> 例如: hadoop archive -archiveName test.har -p /config /outputdir 描述: 创建一个归档文件为 test.har 将这个文件放置到 outputdir目录下, 归档文件中内容为 config目录下内容 2. 如何查看归档文件中内容: 看一下 归档中主要构成: hadoop fs -ls /outputdir/test.har 两个索引文件 一个合成文件 查看归档文件中, 原来文件内容: hadoop fs -ls har://hdfs-node1:8020/outputdir/test.har 上述可以简写为: hadoop fs -ls har:///outputdir/test.har
3. 如何将归档文件原有数据解压出来: hadoop fs -mkdir /config2 hadoop fs -cp har:///outputdir/test.har/* /config2
相关的注意事项: 1.Hadoop archives是特殊的档案格式。一个Hadoop archive对应一个文件系统目录。Hadoop archive的扩展名是*.har; 2.创建archives本质是运行一个Map/Reduce任务,所以应该在Hadoop集群上运行创建档案的命令,要提前启动Yarn集群; 3.创建archive文件要消耗和原文件一样多的硬盘空间; 4.archive文件不支持压缩,尽管archive文件看起来像已经被压缩过;解压过程是复制 5.archive文件一旦创建就无法改变,要修改的话,需要创建新的archive文件。事实上,一般不会再对存档后的文件进行修改,因为它们是定期存档的,比如每周或每日; 6.当创建archive时,源文件不会被更改或删除;
4. HDFS的数据快照功能: 实际生产中使用较少 主要是对HDFS的文件夹 进行拍摄快照, 提供一种备份的操作
HDFS的数据快照功能 主要是采用的差异化快照: 首先对某一个文件夹拍摄快照, 此时在快照文件中不会进行任何记录操作, 只有当这个拍摄快照文件夹中 进行相关的操作, 此时快照中才会记录修改的内容即可
默认情况: 文件夹不支持拍摄快照 注意: 快照只能给文件夹拍摄, 不允许给文件拍摄快照 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>
5) HDFS的垃圾桶的机制: 为什么文件系统需要有垃圾桶呢? 给一个反悔机会
hdfs的回收站, 默认情况下 7天之后, 自动删除掉 此时间也可以在 core-site.xml中进行修改配置的 <property> <name>fs.trash.interval</name> <value>10080</value> </property> /*单位为分钟*/ 如果想对回收站进行还原, 只需要进入回收站, 将对应数据移动到原有目录下即可还原操作
如果想要手动清空回收站: 此操作慎用 一般不做此操作 hadoop fs -expunge
注意: 如果使用 java API的中 delete操作, 直接跳过回收站, 直接删除数据
6) HDFS的高可用: node1: 7个进程 包含 jps node2: 8个进程 node3: 7个进程
测试准备切换...
-----------------------------------------------------------------------------------------------------------笔记完毕
HDFS分布式文件系统
1. HDFS概述
在现代的企业环境中,单机容量往往无法存储大量数据,需要跨机器存储。统一管理分布在集群上的文件系统称为分布式文件系统 。
HDFS(Hadoop Distributed File System)是 Apache Hadoop 项目的一个子项目. Hadoop 非常适于存储大型数据 (比如 TB 和 PB), 其就是使用 HDFS 作为存储系统. HDFS 使用多台计算机存储文件, 并且提供统一的访问接口, 像是访问一个普通文件系统一样使用分布式文件系统.
分布式文件系统解决的问题就是大数据存储。它们是横跨在多台计算机上的存储系统。分布式文件系统在大数据时代有着广泛的应用前景,它们为存储和处理超大规模数据提供所需的扩展能力。
![](https://i-blog.csdnimg.cn/blog_migrate/c6d2051b5ea19e531069e02e9ea8ad78.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7bba955fd390e2ee5fa4a16b30b339b5.png)
2. HDFS发展历史
1、Doug Cutting 在做 Lucene 的时候, 需要编写一个爬虫服务, 这个爬虫写的并不顺利, 遇到 了一些问题, 诸如: 如何存储大规模的数据, 如何保证集群的可伸缩性, 如何动态容错等。
2、2003年的时候, 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. 适合的应用场景
l 存储非常大的文件:这里非常大指的是几百M、G、或者TB级别,需要高吞吐量,对延时没有要求。
l 采用流式的数据访问方式: 即一次写入、多次读取,数据集经常从数据源生成或者拷贝一次,然后在其上做很多分析工作 ,且不支持文件的随机修改。
l 正因为如此,HDFS适合用来做大数据分析的底层存储服务,并不适合用来做.网盘等应用,因为,修改不方便,延迟大,网络开销大,成本太高。
l 运行于商业硬件上: Hadoop不需要特别贵的机器,可运行于普通廉价机器,可以处节约成本
l 需要高容错性
l 为数据存储提供所需的扩展能力
4.2. 不适合的应用场景
l 低延时的数据访问 对延时要求在毫秒级别的应用,不适合采用HDFS。HDFS是为高吞吐数据传输设计的,因此可能牺牲延时
l 大量小文件 文件的元数据保存在NameNode的内存中, 整个文件系统的文件数量会受限于NameNode的内存大小。 经验而言,一个文件/目录/文件块一般占有150字节的元数据内存空间。如果有100万个文件,每个文件占用1个文件块,则需要大约300M的内存。因此十亿级别的文件数量在现有商用机器上难以支持。
l 多方读写,需要任意的文件修改 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、Client:就是客户端。
l 文件切分。文件上传 HDFS 的时候,Client 将文件切分成 一个一个的Block,然后进行存储
l 与 NameNode 交互,获取文件的位置信息。
l 与 DataNode 交互,读取或者写入数据。
l Client 提供一些命令来管理 和访问HDFS,比如启动或者关闭HDFS。
2、NameNode:就是 master,它是一个主管、管理者。
l 管理 HDFS 的名称空间
l 管理数据块(Block)映射信息
l 配置副本策略
l 处理客户端读写请求。
3、DataNode:就是Slave。NameNode 下达命令,DataNode 执行实际的操作。
l 存储实际的数据块。
l 执行数据块的读/写操作。
4、Secondary NameNode:并非 NameNode 的热备。当NameNode 挂掉的时候,它并不能马上替换 NameNode 并提供服务。
l 辅助 NameNode,分担其工作量。
l 定期合并 fsimage和fsedits,并推送给NameNode。
l 在紧急情况下,可辅助恢复 NameNode。
6. HDFS的副本机制
6.1. HDFS文件副本机制
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.2. HDFS副本放置策略(机架感知):
HDFS分布式文件系统的内部有一个副本存放策略,默认副本数为3,在这里以副本数=3为例:
第一副本:优先放置到离写入客户端最近的DataNode节点,如果上传节点就是DataNode,则直接上传到该节点,如果是集群外提交,则随机挑选一台磁盘不太慢,CPU不太忙的节点。
第二个副本:放置在另一个机架中, 某一个服务器中
第三个副本:放置在与第二个同机架的不同机器中
7. HDFS的Shell命令行使用
7.1. 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>命令。
7.2. 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 [命令选项] | 帮助 |
7.3. 常用的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 <paths> 作用 : 以<paths>中的URI作为参数,创建目录。使用-p参数可以递归创建目录 hadoop fs -mkdir /dir1 hadoop fs -mkdir /dir2 hadoop fs -p -mkdir /aaa/bbb/ccc |
-put
cd 格式 : hadoop fs -put <localsrc > ... <dst> 作用 : 将单个的源文件src或者多个源文件srcs从本地文件系统拷贝到目标文件系统中(<dst>对应的路径)。也可以从标准输入中读取输入,写入目标文件系统中 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] <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/下有多个文件:log.1, log.2,log.3,... hadoop fs -getmerge /aaa/log.* ./log.sum |
-mv
格式 : hdfs dfs -mv URI <dest> 作用: 将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 ...] <dest> 作用: 将文件拷贝到目标路径中。如果<dest> 为目录的话,可以将多个文件拷贝到该目录下。 -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的所属用户和所属用户组修改为hadoophadoop 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.1. 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 #离开安全模式 |
8.2. HDFS基准测试
实际生产环境当中,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 jar /export/server/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -clean |
9. HDFS基本原理
9.1. NameNode
1、概念
NameNode在内存中保存着整个文件系统的名称空间和文件数据块的地址映射
整个HDFS可存储的文件数受限于NameNode的内存大小
1、NameNode元数据信息 文件名,文件目录结构,文件属性(生成时间,副本数,权限)每个文件的块列表。 以及列表中的块与块所在的DataNode之间的地址映射关系 在内存中加载文件系统中每个文件和每个数据块的引用关系(文件、block、datanode之间的映射信息) 数据会定期保存到本地磁盘(fsImage文件和edits文件)
2、NameNode文件操作 NameNode负责文件元数据的操作 DataNode负责处理文件内容的读写请求,数据流不经过NameNode,会询问它跟那个DataNode联系
3、NameNode副本文件数据块到底存放到哪些DataNode上,是由NameNode决定的,NameNode根据全局情况做出放置副本的决定
4、NameNode心跳机制全权管理数据块的复制,周期性的接受心跳和块的状态报告信息(包含该DataNode上所有数据块的列表) 若接受到心跳信息,NameNode认为DataNode工作正常,如果在10分钟后还接受到不到DataNode的心跳,那么NameNode认为DataNode已经宕机 ,这时候NN准备要把DN上的数据块进行重新的复制。 块的状态报告包含了一个DataNode上所有数据块的列表,blocks report 每个6小时发送一次.
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的工作机制
NameNode负责管理整个文件系统元数据;DataNode负责管理具体文件数据块存储;Secondary NameNode协助NameNode进行元数据的备份。
HDFS的内部工作机制对客户端保持透明,客户端请求访问HDFS都是通过向NameNode申请来进行。
10.1. HDFS写数据流程 阿善背诵
详细步骤解析:
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/server/hadoop2.7.5/hadoopDatas/namenodeDatas</value> </property> <property> <name>dfs.namenode.edits.dir</name> <value>file:///export/server/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 中
fsimage 内容包含了 NameNode 管理下的所有 DataNode 文件及文件 block 及 block 所在的 DataNode 的元数据信息.
随着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文件。
11.3. SecondaryNameNode出现的原因
但是如果NameNode执行了很多操作的话,就会导致edits文件会很大,那么在下一次启动的过程中,就会导致NameNode的启动速度很慢,慢到几个小时也不是不可能,所以出现了SecondNameNode。
11.4. 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执行合并过程。
11.5. 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进行工作,一直这样循环操作。
注意:SecondaryNameNode 在合并 edits 和 fsimage 时需要消耗的内存和 NameNode 差不多, 所以一般把 NameNode 和 SecondaryNameNode 放在不同的机器上
11.6. fsimage 中的文件信息查看
使用命令 hdfs oiv
cd /export/server/hadoop2.7.5/hadoopDatas/namenodeDatas hdfs oiv -i fsimage_0000000000000000864 -p XML -o hello.xml |
11.7. edits中的文件信息查看
使用命令 hdfs oev
cd /export/server/hadoop2.7.5/hadoopDatas/namenodeDatas hdfs oev -i edits_0000000000000000865-0000000000000000866 -p XML -o myedit.xml |
11.8. 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/* ./ |
3、重新启动NameNode
hadoop-daemon.sh start namenode |
12. HDFS的API操作
12.1. HDFS的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 = FileSystem.get(conf); |
get方法从conf中的一个参数 fs.defaultFS的配置值判断具体是什么类型的文件系统。如果我们的代码中没有指定fs.defaultFS,并且工程classpath下也没有给定相应的配置,conf中的默认值就来自于hadoop的jar包中的core-default.xml,默认值为: file:///,则获取的将不是一个DistributedFileSystem的实例,而是一个本地文件系统的客户端对象。
12.4.2. 获取FileSystem方式
第一种方式
@Testpublic 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());} |
第二种方式
@Testpublic void getFileSystem2() throws Exception{ FileSystem fileSystem = FileSystem.get(new URI("hdfs://node1:8020"), new Configuration()); System.out.println("fileSystem:"+fileSystem);} |
12.4.3. 遍历HDFS中所有文件
@Testpublic 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.4. HDFS上创建文件夹
@Testpublic 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. 下载文件
@Testpublic 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. 上传文件
@Testpublic 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 集群当中有大量的小文件,那么每个小文件都需要维护一份元数据信息,会大大的增加集群管理元数据的内存压力,所以在实际工作当中,如果有必要一定要将小文件合并成大文件进行一起处理,可以在上传的时候将小文件合并到一个大文件里面去
@Testpublic void mergeFile() throws Exception{ //获取分布式文件系统 FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.52.250: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 |
- 重启hdfs集群
start-dfs.sh |
- 随意上传一些文件到我们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文件的可读,可写权限。
- 使用代码准备下载文件
@Testpublic 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用户的身份去访问文件
@Testpublic 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并不擅长存储小文件,因为每个文件最少一个block,每个block的元数据都会在NameNode占用内存,如果存在大量的小文件,它们会吃掉NameNode节点的大量内存。
Hadoop Archives可以有效的处理以上问题,它可以把多个文件归档成为一个文件,归档成一个文件后还可以透明的访问每一个文件。
13.4.1. 如何创建Archive
Usage: hadoop archive -archiveName name -p <parent> <src>* <dest>
其中-archiveName是指要创建的存档的名称。比如test.har,archive的名字的扩展名应该是*.har。 -p参数指定文件存档文件(src)的相对路径。
例如:如果你只想存档一个目录/input下的所有文件:
hadoop archive -archiveName test.har -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/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 |
13.4.3. 如何解压Archive
hadoop fs -mkdir /config2 hadoop fs -cp har:///outputdir/test.har/* /config2 |
查看HDFS页面,发现/config2目录中已经有解压后的小文件了
13.4.4. Archive注意事项
- Hadoop archives是特殊的档案格式。一个Hadoop archive对应一个文件系统目录。Hadoop archive的扩展名是*.har;
- 创建archives本质是运行一个Map/Reduce任务,所以应该在Hadoop集群上运行创建档案的命令,要提前启动Yarn集群;
- 创建archive文件要消耗和原文件一样多的硬盘空间;
- archive文件不支持压缩,尽管archive文件看起来像已经被压缩过;
- archive文件一旦创建就无法改变,要修改的话,需要创建新的archive文件。事实上,一般不会再对存档后的文件进行修改,因为它们是定期存档的,比如每周或每日;
- 当创建archive时,源文件不会被更改或删除;
13.5. Snapshot快照的使用
快照顾名思义,就是相当于对hdfs文件系统做一个备份,可以通过快照对指定的文件夹设置备份,但是添加快照之后,并不会立即复制所有文件,而是指向同一个文件。当写入发生时,才会产生新文件。
13.5.1. 快照使用基本语法
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> |
13.5.2. 快照操作实际案例
1、开启指定目录的快照
hdfs dfsadmin -allowSnapshot /config |
2、对指定目录创建快照
注意:创建快照之前,先要允许该目录创建快照
hdfs dfs -createSnapshot /config |
通过web浏览器访问快照
http://node1:50070/explorer.html#/config/.snapshot/
3、指定名称创建快照
hdfs dfs -createSnapshot /config mysnap1 |
4、重命名快照
hdfs dfs -renameSnapshot /config mysnap1 mysnap2 |
5、列出当前用户所有可以快照的目录
hdfs lsSnapshottableDir |
6、比较快照不同之处
hdfs snapshotDiff /config . .snapshot/s20200522-220535.107 |
7、删除快照
hdfs dfs -deleteSnapshot /user snap1 |
13.6. HDFS的Trash回收站功能 阿善看到
和Linux系统的回收站设计一样,HDFS会为每一个用户创建一个回收站目录:/user/用户名/.Trash/current,每一个被用户通过Shell删除的文件/目录,在系统回收站中都一个周期,也就是当系统回收站中的文件/目录在一段时间之后没有被用户恢复的话,HDFS就会自动的把这个文件/目录彻底删除,之后,用户就永远也找不回这个文件/目录了。
如果检查点已经启用,会定期使用时间戳重命名Current目录。.Trash中的文件在用户可配置的时间延迟后被永久删除。回收站中的文件和目录可以简单地通过将它们移动到.Trash目录之外的位置来恢复。
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> <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的值。 |
13.6.2. 检查点
检查点仅仅是用户回收站下的一个目录,用于存储在创建检查点之前删除的所有文件或目录。如果你想查看回收站目录,可以在/user/${username}/.Trash/{timestamp_of_checkpoint_creation}处看到:
最近删除的文件被移动到回收站Current目录,并且在可配置的时间间隔内,HDFS会为在Current回收站目录下的文件创建检查点/user/${username}/.Trash/<日期>,并在过期时删除旧的检查点。
13.6.3. 恢复回收站数据
hadoop fs -mv /user/root/.Trash/200523093000/hadoop-env.sh /config |
13.6.4. 清空回收站
首先想到的是只要删除整个回收站目录,将会清空回收站。诚然,这是一个选择。但是我们有更好的选择。HDFS提供了一个命令行工具来完成这个工作:
hadoop fs -expunge |
该命令使NameNode永久删除回收站中比阈值更早的文件,而不是等待下一个emptier窗口。它立即从文件系统中删除过期的检查点。
13.6.5. 注意点
回收站功能默认是禁用的。对于生产环境,建议启用回收站功能以避免意外的删除操作。启用回收站提供了从用户操作删除或用户意外删除中恢复数据的机会。但是为fs.trash.interval和fs.trash.checkpoint.interval设置合适的值也是非常重要的,以使垃圾回收以你期望的方式运作。例如,如果你需要经常从HDFS上传和删除文件,则可能需要将fs.trash.interval设置为较小的值,否则检查点将占用太多空间。
当启用垃圾回收并删除一些文件时,HDFS容量不会增加,因为文件并未真正删除。
回收站功能默认只适用于使用Hadoop shell删除的文件和目录。使用其他接口(例如WebHDFS或Java API)以编程的方式删除的文件或目录不会移动到回收站,即使已启用回收站,除非程序已经实现了对回收站功能的调用。
有时你可能想要在删除文件时临时禁用回收站,也就是删除的文件或目录不用放在回收站而直接删除,在这种情况下,可以使用-skipTrash选项运行rm命令。例如:
hadoop fs -rm -skipTrash /dir1/a.txt |
14. HDFS的高可用机制
14.1. HDFS高可用介绍
在Hadoop 中,NameNode 所处的位置是非常重要的,整个HDFS文件系统的元数据信息都由NameNode 来管理,NameNode的可用性直接决定了Hadoop 的可用性,一旦NameNode进程不能工作了,就会影响整个集群的正常使用。
在典型的HA集群中,两台独立的机器被配置为NameNode。在工作集群中,NameNode机器中的一个处于Active状态,另一个处于Standby状态。Active NameNode负责群集中的所有客户端操作,而Standby充当从服务器。Standby机器保持足够的状态以提供快速故障切换(如果需要)。
14.2. 组件介绍
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必须确保元数据同步完成才能对外提供服务
14.3. 高可用集群环境搭建
关于集群搭建步骤,可以参考2_HDFS高可用集群搭建.docx 文档
15. Hadoop的联邦机制(Federation)
15.1. 背景概述
单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的机制.
15.2. 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汇报本地存储可用资源情况。
15.3. HDFS Federation不足
HDFS Federation并没有完全解决单点故障问题。虽然namenode/namespace存在多个,但是从单个namenode/namespace看,仍然存在单点故障:如果某个namenode挂掉了,其管理的相应的文件便不可以访问。Federation中每个namenode仍然像之前HDFS上实现一样,配有一个secondary namenode,以便主namenode挂掉一下,用于还原元数据信息。
所以一般集群规模真的很大的时候,会采用HA+Federation的部署方案。也就是每个联合的namenodes都是ha的。