2.4-Hdfs核心原理
简介
HDFS的全称是Hadoop Distributed File System,即Hadoop分布式文件系统,它是一种允许文件通过网络在多台主机上分享的文件系统,可以让多台机器上的多个用户分享文件和存储空间,其实分布式文件管理系统有很多,HDFS只是其中一种实现而已,还有 GFS(谷歌的)、TFS(淘宝的)、S3(亚马逊的)等。
HDFS同时也是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上。它所具有的高容错、高可靠性、高可扩展性、高获得性、高吞吐率等特征,为海量数据提供了不怕故障的存储。
HDFS优劣势分析
优势
1、可构建在廉价机器上,设备成本相对低
2、高容错性,HDFS将数据自动保存多个副本,副本丢失后,自动恢复,防止数据丢失或损坏
3、适合批处理,HDFS适合一次写入、多次查询(读取)的情况,适合在已有的数据进行多次分析,稳定性好
4、适合存储大文件,其中的大表示可以存储单个大文件,因为是分块存储,以及表示存储大量的数据
劣势
1、由于提高吞吐量,降低实时性
2、由于每个文件都会在namenode中记录元数据,如果存储了大量的小文件,会对namenode造成很大的压力 3、不合适小文件处理,在mapreduce的过程中小文件的数量会造成map数量的增大,导致资源被占用,而且速度慢。
4、不适合文件的修改,文件只能追加在文件的末尾,不支持任意位置修改,不支持多个写入者操作
架构
HDFS具有主/从架构
NameNode:管理节点
管理文件系统命名空间的主服务器和管理客户端对文件的访问组成,如打开,关闭和重命名文件和目录。负责管理文件目录、文件和block的对应关系以及block和datanode的对应关系,维护目录树,接管用户的请求。如下图所示:
1、将文件的元数据保存在一个文件目录树中 2、在磁盘上保存为:fsimage 和 edits 3、保存datanode的数据信息的文件,在系统启动的时候读入内存。
DataNode:数据节点
管理连接到它们运行的节点的存储,负责处理来自文件系统客户端的读写请求。DataNodes还执行块创建,删除.
Client:客户端
(客户端)代表用户通过与nameNode和datanode交互来访问整个文件系统,HDFS对外开放文件命名空间并允许用户数据以文件形式存储。用户通过客户端(Client)与HDFS进行通讯交互。
块和复制: 我们都知道linux操作系统中的磁盘的块的大小默认是512,而hadoop2.x版本中的块的大小默认为128M,那为什么hdfs中的存储块要设计这么大呢? 其目的是为了减小寻址的开销。只要块足够大,磁盘传输数据的时间必定会明显大于这个块的寻址时间。
那为什么要以块的形式存储文件,而不是整个文件呢? 1、因为一个文件可以特别大,可以大于有个磁盘的容量,所以以块的形式存储,可以用来存储无论大小怎样的文件。 2、简化存储系统的设计。因为块是固定的大小,计算磁盘的存储能力就容易多了 3、以块的形式存储不需要全部存在一个磁盘上,可以分布在各个文件系统的磁盘上,有利于复制和容错,数据本地化计算
块和副本在hdfs架构中分布如下图所示:
既然namenode管理着文件系统的命名空间,维护着文件系统树以及整颗树内的所有文件和目录,这些信息以文件的形式永远的保存在本地磁盘上,分别问命名空间镜像文件fsimage和编辑日志文件Edits。datanode是文件的工作节点,根据需要存储和检索数据块,并且定期的向namenode发送它们所存储的块的列表。那么就知道namenode是多么的重要,一旦那么namenode挂了,那整个分布式文件系统就不可以使用了,所以对于namenode的容错就显得尤为重要了,hadoop为此提供了两种容错机制:
容错机制:
就是通过对那些组成文件系统的元数据持久化,分别问命名空间镜像文件fsimage(文件系统的目录树)和编辑日志文件Edits(针对文件系统做的修改操作记录)。
磁盘上的映像FsImage就是一个Checkpoint,一个里程碑式的基准点、同步点,有了一个Checkpoint之后,NameNode在相当长的时间内只是对内存中的目录映像操作,同时也对磁盘上的Edits操作,直到关机。下次开机的时候,NameNode要从磁盘上装载目录映像FSImage,那其实就是老的Checkpoint,也许就是上次开机后所保存的映像,而自从上次开机后直到关机为止对于文件系统的所有改变都记录在Edits文件中;将记录在Edits中的操作重演于上一次的映像,就得到这一次的新的映像,将其写回磁盘就是新的Checkpoint(也就是fsImage)。但是这样有很大一个缺点,如果Edits很大呢,开机后生成原始映像的过程也会很长,所以对其进行改进:每当 Edits长到一定程度,或者每隔一定的时间,就做一次Checkpoint,但是这样就会给namenode造成很大的负荷,会影响系统的性能。于是就有了SecondaryNameNode的需要,这相当于NameNode的助理,专替NameNode做Checkpoint。当然,SecondaryNameNode的负载相比之下是偏轻的。所以如果为NameNode配上了热备份,就可以让热备份兼职,而无须再有专职的SecondaryNameNode。所以架构图如下图所示:
SecondaryNameNode工作原理图:
SecondaryNameNode主要负责下载NameNode中的fsImage文件和Edits文件,并合并生成新的fsImage文件,并推送给NameNode,工作原理如下:
1、secondarynamenode请求主namenode停止使用edits文件,暂时将新的写操作记录到一个新的文件中; 2、secondarynamenode从主namenode获取fsimage和edits文件(通过http get) 3、secondarynamenode将fsimage文件载入内存,逐一执行edits文件中的操作,创建新的fsimage文件。 4、secondarynamenode将新的fsimage文件发送回主namenode(使用http post). 5、namenode用从secondarynamenode接收的fsimage文件替换旧的fsimage文件;用步骤1所产生的edits文件替换旧的edits文件。同时,还更新fstime文件来记录检查点执行时间。 6、最终,主namenode拥有最新的fsimage文件和一个更小的edits文件。当namenode处在安全模式时,管理员也可调用hadoop dfsadmin –saveNameSpace命令来创建检查点。
从上面的过程中我们清晰的看到secondarynamenode和主namenode拥有相近内存需求的原因(因为secondarynamenode也把fsimage文件载入内存)。因此,在大型集群中,secondarynamenode需要运行在一台专用机器上。
创建检查点的触发条件受两个配置参数控制。通常情况下,secondarynamenode每隔一小时(有fs.checkpoint.period属性设置)创建检查点;此外,当编辑日志的大小达到64MB(有fs.checkpoint.size属性设置)时,也会创建检查点。系统每隔五分钟检查一次编辑日志的大小。
图解流程
2.5-Hdfs shell
FS shell介绍
调用文件系统(FS)Shell命令应使用:
标准格式:
bin/hadoop fs
cat
将路径指定文件的内容输出到stdout
实例:
- hadoop fs -cat hdfs://host1:port1/file1 hdfs://host2:port2/file2
- hadoop fs -cat file:///file3 /user/hadoop/file4
返回值:
成功返回0,失败返回-1。
chgrp
改变文件所属的组。使用-R将使改变在目录结构下递归进行。
注意:命令的使用者必须是文件的所有者或者超级用户
实例:
- hadoop fs -chgrp -R
chmod
改变文件的权限。使用-R将使改变在目录结构下递归进行
注意:命令的使用者必须是文件的所有者或者超级用户
实例:
- hadoop fs -chmod -R
chown
改变文件的拥有者
注意:命令的使用者必须是超级用户
实例:
- hadoop fs -chown
copyFromLocal
限定源路径是一个本地文件
从本地拷贝文件数据到hdfs
实例:
- hadoop fs -copyFromLocal 本地路径 hdfsUrl
copyToLocal
从hdfs拷贝文件到本地
实例:
- hadoop fs -copyToLocal hdfsUrl 本地路径
cp
将文件从源路径复制到目标路径。
这个命令允许有多个源路径,此时目标路径必须是一个目录。
示例:
- hadoop fs -cp /user/hadoop/file1 /user/hadoop/file2
- hadoop fs -cp /user/hadoop/file1 /user/hadoop/file2 /user/hadoop/dir
返回值:
成功返回0,失败返回-1。
du
使用方法:hadoop fs -du hdfsUrl
显示目录中所有文件的大小,或者当只指定一个文件时,显示此文件的大小。 示例: hadoop fs -du /user/hadoop/dir1 /user/hadoop/file1 hdfs://host:port/user/hadoop/dir1 返回值: 成功返回0,失败返回-1。
get
使用方法:hadoop fs -get
复制文件到本地文件系统。
示例:
- hadoop fs -get /user/hadoop/file localfile
- hadoop fs -get hdfs://host:port/user/hadoop/file localfile
返回值:
成功返回0,失败返回-1。
ls
使用方法:hadoop fs -ls
如果是文件,则按照如下格式返回文件信息: 文件名 <副本数> 文件大小 修改日期 修改时间 权限 用户ID 组ID 如果是目录,则返回它直接子文件的一个列表,就像在Unix中一样。
目录返回列表的信息如下: 目录名 修改日期 修改时间 权限 用户ID 组ID 示例: hadoop fs -ls /user/hadoop/file1 /user/hadoop/file2 hdfs://host:port/user/hadoop/dir1 /nonexistentfile 返回值: 成功返回0,失败返回-1。
lsr
使用方法:hadoop fs -lsr ls命令的递归版本。类似于Linux中的ls -R。
mkdir
使用方法:hadoop fs -mkdir
接受路径指定的uri作为参数,创建这些目录。
其行为类似于Linux的mkdir -p,它会创建路径中的各级父目录。
示例:
- hadoop fs -mkdir /user/hadoop/dir1 /user/hadoop/dir2
- hadoop fs -mkdir hdfs://host1:port1/user/hadoop/dir hdfs://host2:port2/user/hadoop/dir
返回值:
成功返回0,失败返回-1。
mv
使用方法:hadoop fs -mv URI1 URl2
将文件从源路径移动到目标路径。
这个命令允许有多个源路径,此时目标路径必须是一个目录。不允许在不同的文件系统间移动文件。 示例:
- hadoop fs -mv /user/hadoop/file1 /user/hadoop/file2
- hadoop fs -mv hdfs://host:port/file1 hdfs://host:port/file2 hdfs://host:port/file3 hdfs://host:port/dir1
返回值:
成功返回0,失败返回-1。
put
使用方法:hadoop fs -put
从本地文件系统中复制单个或多个源路径到目标文件系统。也支持从标准输入中读取输入写入目标文件系统。
- hadoop fs -put localfile /user/hadoop/hadoopfile
- hadoop fs -put localfile1 localfile2 /user/hadoop/hadoopdir
- hadoop fs -put localfile hdfs://host:port/hadoop/hadoopfile
- hadoop fs -put - hdfs://host:port/hadoop/hadoopfile
- 从标准输入中读取输入。
返回值:
成功返回0,失败返回-1。
rm
使用方法:hadoop fs -rm URI
删除指定的文件。只删除非空目录和文件。请参考rmr命令了解递归删除。 示例:
- hadoop fs -rm hdfs://host:port/file /user/hadoop/emptydir
返回值:
成功返回0,失败返回-1。
rmr
使用方法:hadoop fs -rmr URI
delete的递归版本。 示例:
- hadoop fs -rmr /user/hadoop/dir
- hadoop fs -rmr hdfs://host:port/user/hadoop/dir
返回值:
成功返回0,失败返回-1。
setrep
使用方法:hadoop fs -setrep [-R]
改变一个文件的副本系数。-R选项用于递归改变目录下所有文件的副本系数。
示例:
- hadoop fs -setrep -w 3 -R /user/hadoop/dir1
返回值:
成功返回0,失败返回-1。
stat
使用方法:hadoop fs -stat URI
返回指定路径的统计信息。
示例:
- hadoop fs -stat path
返回值: 成功返回0,失败返回-1。
tail
使用方法:hadoop fs -tail [-f]
将文件尾部1K字节的内容输出到stdout。支持-f选项,行为和Unix中一致。
示例:
- hadoop fs -tail pathname
返回值: 成功返回0,失败返回-1。
test
使用方法:hadoop fs -test -[ezd] URI
选项: -e 检查文件是否存在。如果存在则返回0。 -z 检查文件是否是0字节。如果是则返回0。 -d 如果路径是个目录,则返回1,否则返回0。
示例:
- hadoop fs -test -e filename
text
使用方法:hadoop fs -text
将源文件输出为文本格式。允许的格式是zip和TextRecordInputStream。
touchz
使用方法:hadoop fs -touchz URI [URI …]
创建一个0字节的空文件。
示例:
- hadoop -touchz pathname
返回值: 成功返回0,失败返回-1。
2.6-Hdfs Java Api
创建Maven项目添加依赖
<dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>3.2.0</version> </dependency>
前置代码
//创建一个配置对象 Configuration conf = new Configuration(); //指定HDFS的地址 conf.set("fs.defaultFS","hdfs://bigdata01:9000"); //获取操作HDFS的对象 FileSystem fileSystem = FileSystem.get(conf);
删除文件或目录
private static void delete(FileSystem fileSystem) throws IOException { //删除文件,目录也可以删除 //如果要递归删除目录,则第二个参数需要设置为true //如果删除的是文件或者空目录,第二个参数会被忽略 boolean flag = fileSystem.delete(new Path("/LICENSE.txt"),true); if(flag){ System.out.println("删除成功!"); }else{ System.out.println("删除失败!"); } }
下载文件
private static void get(FileSystem fileSystem) throws IOException { //获取HDFS文件系统中的输入流 FSDataInputStream fis = fileSystem.open(new Path("/README.txt")); //获取本地文件的输出流 FileOutputStream fos = new FileOutputStream("D:\\README.txt"); //下载文件 IOUtils.copyBytes(fis,fos,1024,true); }
上传文件
private static void put(FileSystem fileSystem) throws IOException { //获取本地文件的输入流 FileInputStream fis = new FileInputStream("D:\\user.txt"); //获取HDFS文件系统的输出流 FSDataOutputStream fos = fileSystem.create(new Path("/user.txt")); //上传文件:通过工具类把输入流拷贝到输出流里面,实现本地文件上传到HDFS IOUtils.copyBytes(fis,fos,1024,true); }
上述基础操作基本能够满足在公司中需求,扩展Api参考官方文档
2.7-Hdfs 核心进程剖析
NameNode
功能
NameNode是整个文件系统的管理节点,它主要维护着整个文件系统的文件目录树,文件/目录的信息 和 每个文件对应的数据块列表,并且还负责接收用户的操作请求
- 目录树:表示目录之间的层级关系,就是我们在hdfs上执行ls命令可以看到的那个目录结构信息
- 目录信息:目录的的一些基本信息,所有者 属组 修改时间 文件大小等信息
- 数据块列表:如果一个文件太大,那么在集群中存储的时候会对文件进行切割,这个时候就类似于会给文件分成一块一块的,存储到不同机器上面。所以HDFS还要记录一下一个文件到底被分了多少块,每一块都在哪个节点存储。
- 接收用户的操作请求:我们无论使用命令行,还是相关的Java Api都是与NameNode进行通信之后才去操作数据
文件信息
- fsimage:元数据镜像文件,存储某一时刻NameNode内存中的元数据信息,就类似是定时做了一个快照操作。(元数据:文件目录树、文件/目录的信息、每个文件对应的数据块列表)
- edits:操作日志文件【事务文件】,这里面会实时记录用户的所有操作
- seen_txid:是存放transactionId的文件,format之后是0,它代表的是namenode里面的edits_*文件的尾数,namenode重启的时候,会按照seen_txid的数字,顺序从头跑edits_0000001~到seen_txid的数字。如果根据对应的seen_txid无法加载到对应的文件,NameNode进程将不会完成启动以保护数据一致性
- VERSION:集群的版本信息
SecondaryNameNode
功能
- 定期的把edits文件中的内容合并到fsimage中
- 合并操作称为checkpoint,在合并的时候会对edits中的内容进行转换,生成新的内容保存到fsimage文件中。
- PS:在NameNode的HA架构中没有SecondaryNameNode进程,文件合并操作会由standby NameNode负责实现
所以在Hadoop集群中,SecondaryNameNode进程并不是必须的。
DataNode
功能
- 提供真实文件数据的存储服务
核心店
- Block:HDFS会按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block,HDFS默认Block大小是 128MB,Block块是HDFS读写数据的基本单位,不管你的文件是文本文件 还是视频或者音频文件,针对hdfs而言都是字节。HDFS中,如果一个文件小于一个数据块的大小,那么并不会占用整个数据块的存储空间。
- Replication:副本表示数据有多少个备份,默认这个参数的配置是3,副本只有一个作用就是保证数据安全。副本个数可以配置,在hdfs-site.xml中进行配置的,dfs.replication=副本数
总结
NameNode维护了两份关系
- 第一份关系:File 与Block list的关系,对应的关系信息存储在fsimage和edits文件中,当NameNode启动的时候会把文件中的元数据信息加载到内存中
- 第二份关系:DataNode与Block的关系,对应的关系主要在集群启动的时候保存在内存中,当DataNode启动时会把当前节点上的Block信息和节点信息上报给NameNode
Hdfs回收站
- HDFS会为每一个用户创建一个回收站目录:/user/用户名/.Trash/,每一个被用户在Shell命令行删除的文件/目录,会进入到对应的回收站目录中,在回收站中的数据都有一个生存周期,也就是当回收站中的文件/目录在一段时间之内没有被用户恢复的话,HDFS就会自动的把这个文件/目录彻底删除,之后,用户就永远也找不回这个文件/目录了。
- 默认情况下hdfs的回收站是没有开启的,需要通过一个配置来开启,在core-site.xml中添加如下配置,value的单位是分钟,1440分钟表示是一天的生存周期
- 注意:如果删除的文件过大,超过回收站大小的话会提示删除失败,需要指定参数 -skipTrash ,指定这个参数表示删除的文件不会进回收站
Hdfs安全模式
- 集群刚启动时HDFS会进入安全模式,此时无法执行写操作
- 查看安全模式:hdfs dfsadmin -safemode get
- 离开安全模式:hdfs dfsadmin -safemode leave