一、基本概述
1、定义
HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目
录树来定位文件; 其次,它是分布式的。HDFS 的使用场景:适合一次写入,多次读出的场景。 一个文件经过创建、写入和关闭之后就不需要改变。2、优缺点优点:1) 高容错性2)适合处理大数据3) 可 构建在廉价机器上 ,通过多副本机制,提高可靠性缺点:1) 不适合低延时数据访问 ,比如毫秒级的存储数据,是做不到的2) 无法高效的对大量小文件进行存储。➢ 存储大量小文件的话,它会占用NameNode 大量的内存来存储文件目录和块信息。这样是不可取的,因为NameNode 的内存总是有限的;➢ 小文件存储的寻址时间会超过读取时间,它违反了 HDFS 的设计目标3) 不支持并发写入、文件随机修改➢ 一个文件只能有一个写,不允许多个线程同时写;➢ 仅支持数据 append (追加), 不支持文件的随机修改。3、Hdfs组成1 ) NameNode ( nn ):类似 一个主管、管理者。( 1 )管理 HDFS 的名称空间;( 2 )配置副本策略;( 3 )管理数据块( Block )映射信息;( 4 )处理客户端读写请求。2 ) DataNode : NameNode 下达命令,DataNode 执行实际的操作。( 1 )存储实际的数据块;( 2 )执行数据块的读 / 写操作。3 ) Client :就是客户端。( 1 )文件切分。文件上传 HDFS 的时候, Client 将文件切分成一个一个的 Block ,然后进行上传;( 2 )与 NameNode 交互,获取文件的位置信息;( 3 )与 DataNode 交互,读取或者写入数据;( 4 ) Client 提供一些命令来管理 HDFS ,比如 NameNode 格式化;( 5 ) Client 可以通过一些命令来访问 HDFS ,比如对 HDFS 增删查改操作;4 ) Secondary NameNode :并非 NameNode 的热备。当 NameNode 挂掉的时候,它并不能马上替换 NameNode 并提供服务。( 1 )辅助 NameNode ,分担其工作量,比如定期合并 Fsimage 和 Edits ,并推送给 NameNode ;( 2 )在紧急情况下,可辅助恢复 NameNode 。4、HDFS 文件块大小HDFS 中的文件在物理上是分块存储( Block ),块的大小可以通过配置参数 ( dfs.blocksize)来规定, 默认大小在 Hadoop2.x/3.x 版本中是 128M。思考:为什么块的大小不能设置太小,也不能设置太大?( 1 ) HDFS 的块设置 太小 , 会增加寻址时间 ,程序一直在找块的开始位置;( 2 )如果块设置的 太大 ,从 磁盘传输数据的时间 会明显 大于定位这个块开始位置所需的时间 。导致程序在处理这块数据时,会非常慢。总结: HDFS 块的大小设置主要取决于磁盘传输速率。
二、
HDFS
的
Shell
操作
1、先启动hadoop集群[atguigu@hadoop102 hadoop-3.1.3]$ sbin/start-dfs.sh[atguigu@hadoop103 hadoop-3.1.3]$ sbin/start-yarn.sh2、常用命令1)、上传剪切上传: hadoop fs -put ./wuguo.txt /hadoop/sanguo复制上传:hadoop fs -moveFromLocal ./shuguo.txt /hadoop/sanguo追加一个文件到已经存在的文件末尾:hadoop fs -appendToFile liubei.txt /hadoop/sanguo/shuguo.txt2)、下载hadoop fs -get /hadoop/shuguo.txt ./shuguo2.txt3、其他命令1 ) -ls: 显示目录信息[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -ls /sanguo2 ) -cat :显示文件内容[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -cat /sanguo/shuguo.txt3 ) -chgrp 、 -chmod 、 -chown : Linux 文件系统中的用法一样,修改文件所属权限[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -chmod 666/sanguo/shuguo.txt[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -chown atguigu:atguigu/sanguo/shuguo.txt4 ) -mkdir :创建路径[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mkdir /jinguo5 ) -cp :从 HDFS 的一个路径拷贝到 HDFS 的另一个路径[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -cp /sanguo/shuguo.txt/jinguo6 ) -mv :在 HDFS 目录中移动文件[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mv /sanguo/wuguo.txt /jinguo[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mv /sanguo/weiguo.txt/jinguo7 ) -tail :显示一个文件的末尾 1kb 的数据[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -tail /jinguo/shuguo.txt8 ) -rm :删除文件或文件夹[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -rm /sanguo/shuguo.txt9 ) -rm -r :递归删除目录及目录里面内容[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -rm -r /sanguo10 ) -du 统计文件夹的大小信息[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -du -s -h /jinguo27 81 /jinguo[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -du -h /jinguo14 42 /jinguo/shuguo.txt7 21 /jinguo/weiguo.txt6 18 /jinguo/wuguo.tx说明: 27 表示文件大小; 81 表示 27*3 个副本; /jinguo 表示查看的目录11 ) -setrep :设置 HDFS 中文件的副本数量[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -setrep 10 /jinguo/shuguo.txt这里设置的副本数只是记录在 NameNode 的元数据中,是否真的会有这么多副本,还得看 DataNode 的数量。因为目前只有 3 台设备,最多也就 3 个副本,只有节点数的增加到 10台时,副本数才能达到 10 。
三、HDFS
的
API
操作
1、配置本地hadoop环境下载windows版hadoop并配置环境变量2、创建一个maven项目pom文件:<dependencies> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>3.1.3</version> </dependency> </dependencies>
创建客户端进行api操作:
package com.hadoop; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.*; import java.io.IOException; import java.net.URI; import java.util.Arrays; public class HdfsClient { public static void main(String[] args) throws Exception { //----------1、获取配置类对象(可以用配置对象设置hdfs对应的配置) // 配置优先级:(1)客户端代码中设置的值 >(2)ClassPath 下的用户自定义配置文件 >(3)然后是服务器的自定义配置(xxx-site.xml)>(4)服务器的默认配置(xxx-default.xml)) Configuration configuration = new Configuration(); configuration.set("dfs.replication", "2"); //----------2、获取hdfs文件系统对象(记得要配置用户,不然默认是windows的用户名则会报错) FileSystem fileSystem = FileSystem.get(new URI("hdfs://hadoop102:8020"), configuration, "root"); //----------3、进行相应api操作 //1)、创建目录 fileSystem.mkdirs(new Path("/aaa")); //2)、下载 // boolean delSrc 指是否将原文件删除 // Path src 指要下载的文件路径 // Path dst 指将文件下载到的路径 // boolean useRawLocalFileSystem 是否开启文件校验 fileSystem.copyToLocalFile(false, new Path("/xiyou/huaguoshan/sunwukong.txt"), new Path("d:/sunwukong2.txt"), true); //3)、上传 fileSystem.copyFromLocalFile(new Path("d:/sunwukong.txt"), new Path("/xiyou/huaguoshan")); //4)、修改文件名称 fileSystem.rename(new Path("/xiyou/huaguoshan/sunwukong.txt"), new Path("/xiyou/huaguoshan/meihouwang.txt")); // 5)、 执行删除 fileSystem.delete(new Path("/xiyou"), true); // 6)、 获取文件详情 RemoteIterator<LocatedFileStatus> listFiles = fileSystem.listFiles(new Path("/"), true); while (listFiles.hasNext()) { LocatedFileStatus fileStatus = listFiles.next(); System.out.println("========" + fileStatus.getPath() + "========="); System.out.println(fileStatus.getPermission()); System.out.println(fileStatus.getOwner()); System.out.println(fileStatus.getGroup()); System.out.println(fileStatus.getLen()); System.out.println(fileStatus.getModificationTime()); System.out.println(fileStatus.getReplication()); System.out.println(fileStatus.getBlockSize()); System.out.println(fileStatus.getPath().getName()); // 获取块信息 BlockLocation[] blockLocations = fileStatus.getBlockLocations(); System.out.println(Arrays.toString(blockLocations)); } // 7)、判断是文件还是文件夹 FileStatus[] listStatus = fileSystem.listStatus(new Path("/")); for (FileStatus fileStatus : listStatus) { // 如果是文件 if (fileStatus.isFile()) { System.out.println("f:"+fileStatus.getPath().getName()); }else { System.out.println("d:"+fileStatus.getPath().getName()); } } //-----------4、操作完后关闭资源 fileSystem.close(); } }
注意:配置优先级:(1)客户端代码中设置的值 >(2)ClassPath 下的用户自定义配置文件 >(3)然后是服务器的自定义配置(xxx-site.xml)>(4)服务器的默认配置(xxx-default.xml)) 注意获取文件系统操作对象时要设置操作用户,否则默认会用windos系统用户,此时就会出现用户权限不足等报错现象
四、
HDFS
的读写流程(面试重点)
一、写流程(1)客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件,NameNode 检查目标文件是否已存在,父目录是否存在。
(2) NameNode 返回是否可以上传。(3)客户端请求第一个 Block 上传到哪几个 DataNode 服务器上。(4) NameNode 返回 3 个 DataNode 节点,分别为 dn1 、 dn2 、 dn3 。(5)客户端通过 FSDataOutputStream 模块请求 dn1 上传数据, dn1 收到请求会继续调用 dn2,然后 dn2 调用 dn3 ,将这个通信管道建立完成。(6) dn1 、 dn2 、 dn3 逐级应答客户端。(7)客户端开始往 dn1 上传第一个 Block (先从磁盘读取数据放到一个本地内存缓存), 以 Packet 为单位, dn1 收到一个 Packet 就会传给 dn2 , dn2 传给 dn3 ; dn1 每传一个 packet会放入一个应答队列等待应答 。(8)当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器。(重复执行 3-7 步)。网络拓扑-节点距离计算
在 HDFS 写数据的过程中, NameNode 会选择距离待上传数据最近距离的 DataNode 接 收数据。那么这个最近距离怎么计算呢?节点距离:两个节点到达最近的共同祖先的距离总和。例如,假设有数据中心 d1 机架 r1 中的节点 n1 。该节点可以表示为 /d1/r1/n1 。利用这种 标记,这里给出四种距离描述。大家算一算每两个节点之间的距离。机架感知(副本存储节点选择)
现在要将文件存储在3个节点上,此时我们找到了最近的一个集群了,此时三个节点如何选择?
二、读数据流程
( 1 )客户端通过 DistributedFileSystem 向 NameNode 请求下载文件, NameNode 通过查 询元数据,找到文件块所在的 DataNode 地址。(2)挑选一台 DataNode (就近原则,然后随机)服务器,请求读取数据。(3) DataNode 开始传输数据给客户端(从磁盘里面读取数据输入流,以 Packet 为单位 来做校验)。(4)客户端以 Packet 为单位接收,先在本地缓存,然后写入目标文件。
五、NameNode
和
SecondaryNameNode
一、NameNode和SecondaryNameNode的工作机制思考: NameNode 中的元数据是存储在哪里的?首先,我们做个假设,如果存储在 NameNode 节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。 因此产生在磁盘中备份元数据的 FsImage。这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新 FsImage ,就会导 致效率过低,但如果不更新,就会发生一致性问题,一旦 NameNode 节点断电,就会产生数据丢失。 因此,引入 Edits 文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到 Edits 中。 这样,一旦 NameNode 节点断电,可以通过 FsImage 和 Edits 的合并,合成元数据。但是,如果长时间添加数据到 Edits 中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行 FsImage 和 Edits 的合并,如果这个操作由 NameNode 节点完成,又会效率过低。 因此,引入一个新的节点 SecondaryNamenode ,专门用于 FsImage 和 Edits 的合并。
1 )第一阶段: NameNode 启动( 1 )第一次启动 NameNode 格式化后,创建 Fsimage 和 Edits 文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。(2)客户端对元数据进行增删改的请求。(3) NameNode 记录操作日志,更新滚动日志。(4) NameNode 在内存中对元数据进行增删改。2 )第二阶段: Secondary NameNode 工作( 1 ) Secondary NameNode 询问 NameNode 是否需要 CheckPoint 。直接带回 NameNode 是否检查结果。(2) Secondary NameNode 请求执行 CheckPoint 。(3) NameNode 滚动正在写的 Edits 日志。(4)将滚动前的编辑日志和镜像文件拷贝到 Secondary NameNode 。(5) Secondary NameNode 加载编辑日志和镜像文件到内存,并合并。(6)生成新的镜像文件 fsimage.chkpoint 。(7)拷贝 fsimage.chkpoint 到 NameNode 。(8) NameNode 将 fsimage.chkpoint 重新命名成 fsimage 。二、Fsimage 和 Edits 解析NameNode 被格式化之后,将在 /opt/module/hadoop-3.1.3/data/tmp/dfs/name/current 目录中产生如下文件fsimage_0000000000000000000fsimage_0000000000000000000.md5seen_txidVERSION( 1 ) Fsimage 文件: HDFS 文件系统元数据的一个 永久性的检查点 ,其中包含 HDFS 文件系统的所有目 录和文件inode 的序列化信息。( 2 ) Edits 文件:存放 HDFS 文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先 会被记录到Edits 文件中。( 3 ) seen_txid 文件保存的是一个数字,就是最后一个 edits_ 的数字( 4 )每 次 NameNode 启动的时候 都会将 Fsimage 文件读入内存,加 载 Edits 里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成 NameNode 启动的时候就将 Fsimage 和 Edits 文件进行了合并。1、用oiv命令 查看 Fsimage 文件案例实操[atguigu@hadoop102 current]$ pwd/opt/module/hadoop-3.1.3/data/dfs/name/current[atguigu@hadoop102 current]$ hdfs oiv -p XML -ifsimage_0000000000000000025 -o /opt/module/hadoop-3.1.3/fsimage.xml[atguigu@hadoop102 current]$ cat /opt/module/hadoop-3.1.3/fsimage.xml将显示的 xml 文件内容拷贝到 Idea 中创建的 xml 文件中,并格式化。部分显示结果如 下。<inode> <id>16386</id> <type>DIRECTORY</type> <name>user</name> <mtime>1512722284477</mtime> <permission>atguigu:supergroup:rwxr-xr-x</permission> <nsquota>-1</nsquota> <dsquota>-1</dsquota> </inode> <inode> <id>16387</id> <type>DIRECTORY</type> <name>atguigu</name> <mtime>1512790549080</mtime> <permission>atguigu:supergroup:rwxr-xr-x</permission> <nsquota>-1</nsquota> <dsquota>-1</dsquota> </inode> <inode> <id>16389</id> <type>FILE</type> <name>wc.input</name> <replication>3</replication> <mtime>1512722322219</mtime> <atime>1512722321610</atime> <perferredBlockSize>134217728</perferredBlockSize> <permission>atguigu:supergroup:rw-r--r--</permission> <blocks> <block> <id>1073741825</id> <genstamp>1001</genstamp> <numBytes>59</numBytes> </block> </blocks> </inode >
思考:可以看出, Fsimage 中没有记录块所对应 DataNode ,为什么?在集群启动后,才要求 DataNode 上报数据块信息(所以一开始没有记录),并间隔一段时间后再次上报。2、 oev 查看 Edits 文件[atguigu@hadoop102 current]$ hdfs oev -p XML -iedits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop- 3.1.3/edits.xml[atguigu@hadoop102 current]$ cat /opt/module/hadoop-3.1.3/edits.xml思考: NameNode 如何确定下次开机启动的时候合并哪些 Edits ?3、 CheckPoint 时间设置1 )通常情况下, SecondaryNameNode 每隔一小时执行一次。[hdfs-default.xml]<property> <name>dfs.namenode.checkpoint.period</name> <value>3600s</value> </property>
2)一分钟检查一次操作次数,当操作次数达到 1 百万时,SecondaryNameNode 执行一次。
<property> <name>dfs.namenode.checkpoint.txns</name> <value>1000000</value> <description>操作动作次数</description> </property> <property> <name>dfs.namenode.checkpoint.check.period</name> <value>60s</value> <description> 1 分钟检查一次操作次数</description> </property>
六、
DataNode
一、工作机制( 1 )一个数据块在 DataNode 上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。(2) DataNode 启动后向 NameNode 注册,通过后,周期性(6 小时)的向 NameNode 上 报所有的块信息。DN 向 NN 汇报当前解读信息的时间间隔,默认 6 小时;
<property> <name>dfs.blockreport.intervalMsec</name> <value>21600000</value> <description>Determines block reporting interval in milliseconds.</description> </property>
DN 扫描自己节点块信息列表的时间,默认 6 小时<property> <name>dfs.datanode.directoryscan.interval</name> <value>21600s</value> <description>Interval in seconds for Datanode to scan data directories and reconcile the difference between blocks in memory and onthe disk.Support multiple time unit suffix(case insensitive), as described in dfs.heartbeat.interval.</description> </property>
(3)心跳是每 3 秒一次,心跳返回结果带有 NameNode 给该 DataNode 的命令如复制块数据到另一台机器,或删除某个数据块。如果超过 10 分钟没有收到某个 DataNode 的心跳,则认为该节点不可用。(4)集群运行中可以安全加入和退出一些机器。二、 数据完整性思考:如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号(1)和绿灯信号(0), 但是存储该数据的磁盘坏了,一直显示是绿灯,是否很危险?同理 DataNode 节点上的数据损坏了,却没有发现,是否也很危险,那么如何解决呢?如下是 DataNode 节点保证数据完整性的方法。( 1 )当 DataNode 读取 Block 的时候,它会计算 CheckSum 。(2)如果计算后的 CheckSum ,与 Block 创建时值不一样,说明 Block 已经损坏。(3) Client 读取其他 DataNode 上的 Block 。(4)常见的校验算法 crc (32), md5 (128), sha1 ( 160 )(5) DataNode 在其文件创建后周期验证 CheckSum 。
三、 掉线时限参数设置需要注意的是 hdfs-site.xml 配置文件中的 heartbeat.recheck.interval 的单位为 毫秒 , dfs.heartbeat.interval 的单位为 秒 。
<property> <name>dfs.namenode.heartbeat.recheck-interval</name> <value>300000</value> </property> <property> <name>dfs.heartbeat.interval</name> <value>3</value> </property>