01 引言
由于接下来需要用到hdfs
的技术,从本篇开始,有关hdfs
的学习笔记都会记录到《HDFS专栏》专栏。
接下来,开始我们愉快的Hdfs
学习之旅!
02 HDFS概述
2.1 HDFS定义
HDFS(Hadoop Distributed File System):它是一个文件系统,用于存储文件,通过目录树来定位;其次,它是分布式的,由很多服务联合起来实现其功能,集群中的服务器有各自的角色。
HDFS使用场景: 适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用。
2.2 HDFS优缺点
HDFS优点:
- 高容错性: 数据自动保存多个副本,它通过增加副本的形式,提高容错性,当某一个副本丢失以后,它可以自动恢复;
- 适合处理大数据:它的数据规模能够处理数据规模达到
GB
,TB
,甚至PB
级别的数据;文件规模能够处理百万规模以上的文件数量,数量相当之大; - 可构建在廉价机器上:通过多副本机制,提高可靠性。
HDFS缺点:
- 不适合低延迟数据访问:比如毫秒级的存储数据,是做不到的;
- 无法高效的对大量小文件进行存储:存储大量小文件的话,他会占用
NameNode
大量的内存来存储文件目录块信息。这样是不可取的,因为NameNode
的内存总是有限的;小文件存储的寻址时间会超过读取时间,它违反了HDFS
的设计目标; - 不支持并发写入,文件随机修改:一个文件只能有一个写,不允许多个线程同时写。仅支持数据
append
(追加),不支持文件的随机修改。
03 HDFS架构
贴上hdfs
官方的架构图:
根据架构图,可以看出HDFS
主要由如下几个部分组成:
- NameNode
- DataNode
- Client
- Secondary NameNode
- Block
下面讲解下。
3.1 NameNode管理者
NameNode: 就是Master
,他是一个主管,管理者。
它主要的作用:
- 管理
HDFS
的名称空间; - 配置副本策略;
- 管理数据块(
Block
)映射信息; - 处理客户端读写请求。
NameNode
主要维护两个文件:
- FsImage:
FsImage
是一个“镜像文件”。它保存了最新的元数据检查点,包含了整个HDFS
文件系统的所有目录和文件的信息。对于文件来说包括了数据块描述信息、修改时间、访问时间等;对于目录来说包括修改时间、访问权限控制信息(目录所属用户,所在组)等; - EditLog:
EditLog
主要是在NameNode
已经启动情况下对HDFS
进行的各种更新操作进行记录,HDFS
客户端执行所有的写操作都会被记录到editlog
中。
3.2 DataNode执行者
DataNode: 就是Slave
,当NameNode
下达命令,DataNode
执行实际的操作。
它的主要作用:
- 存储实际的数据块,所以
DataNode
节点需要较大的磁盘 - 执行数据块的读/写操作;
- 定期向
NameNode
发送心跳,如果NameNode
长时间没有接受到DataNode
发送的心跳,NameNode
就会认为该DataNode
失效,将其剔除集群(心跳参数dfs.heartbeat.interval=3
,默认3秒发送一次心跳); DataNode
会定时上报自己负责的数据块列表。
3.3 Client客户端
Client:就是客户端。
它的主要作用:
- 文件切分,文件上传
HDFS
的时候,Client
将文件切分成一个一个的Block
,然后进行上传; - 与
NameNode
交互,获取文件的位置信息; - 与
Datanode
交互,读取或者写入数据; Client
提供一些命令来管理HDFS
,比如NameNode
格式化;Client
可以通过一些命令来访问HDFS
,比如对HDFS
增删改查操作。
3.4 Secondary NameNode辅助者
Secondary NameNode:并非NameNode
的热备,当NameNode
宕掉的时候,它并不能马上替换NameNode
并提供服务。
它的作用:
- 镜像备份:备份
fsimage
(fsimage
是元数据发送检查点时写入文件); - 日志与镜像的定期合并:将
Namenode
中edits
日志和fsimage
合并,防止如果Namenode
节点故障,Namenode
下次启动的时候,会把fsimage
加载到内存中,应用edit log
,edit log
往往很大,导致操作往往很耗时;
3.5 Block块
block:HDFS
中文件在物理上是分块存储(Block
),块的大小可以通过配置参数(dfs.blocksize
)来规定,默认大小在Hadoop2.x
版本是128M
,在Hadoop1.x
版本中是64M
。
默认大小设置为128M的原因:
- 如果寻址时间为
10ms
,即查找到目标的bolck
的时间为10ms
; - 寻址时间为传输时间的
1%
时,则为最佳状态。因此,传输时间=寻址时间/0.01=10ms/0.01=1000ms=1s - 而目前磁盘的传输速度普遍为
100MB/s
- 因此block的大小为=1s*100MB/s=100M≈128M。
如何设置块大小:
- 块设置太小:会增加寻址时间,呈现一直在找块的开始位置;
- 块设置的太大:从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间,导致程序在处理这块数据时,会非常慢;
- HDFS块的大小设置,主要取决于磁盘传输速度。
举例:
- 如果数据的大小比
HDFS
块大小还要小的话,那么块大小将等于数据的大小 - 如果文件大小是129MB,那么HDFS将创建2个block,一个block的大小是默认值,即128MB,另外一个block就只有1MB,而不是128MB
3.6 机架感知
在大型
Hadoop
集群,为了在读写文件的时候改善网络传输,Namenode
会选择给同一个机架或者最近的机架上的Datanode发送读写请求。NameNode
通过维护每个DataNode
的机架id
来获取机架信息。
HDFS
机架感知:就是基于机架信息选择Datanode
的过程。
机架感知的作用:
- 提升数据的高可用和可靠性。
- 改善集群性能。
- 改善网络带宽。
04 HDFS读写流程
下面来讲解HDFS的操作流程已加深对HDFS的架构理解。
4.1 写流程
比如文件上传流程:
- 客户端发起写文件请求
hadoop fs -put
; NameNode
检查上传文件的命名空间是否存在(就是检测文件目录结构是否存在),创建者是否有权限进行操作,然后返回状态给客户端你可以上传数据;- 客户端按照分块配置大小将文件分块,然后请求
NameNode
我要上传blk1
,副本数是三个,这个文件一共分割了5块。 NameNode
检测自己管理下的DateNodes
是否满足要求,然后返回给客户端三台DateNode
节点信息(存储策略是机架模式);Client
端根据返回的DataNode
信息选择一个离自己最近的一个DataNode
节点,创建pipeLine
(数据传输管道),DataNode1->DataNode2
创建pipeLine
,DataNode2->DataNode3
创建pipeLine
;DataNode3
通过这一串管道传递给client
数据传输管道已经建立完毕;client
端创建Stream
流(以packet
为单位传输数据64kb
)上传数据;DataNode1
接受并保持源源不断的packet
,然后把packet
源源不断的传递给DataNode2
,DataNode2
也做相应的操作。DataNode
也通过pipeLine
发送ACK
认证数据是否接收完毕。- 第一个数据块上传完毕后
client
端开始上传第二个数据块。
写流程Java示例:
Configuration conf = new Configuration(); FileSystem fileSystem = FileSystem.get(conf); // Check if the file already exists Path path = new Path("/path/to/file.ext"); if (fileSystem.exists(path)) { System.out.println("File " + dest + " already exists"); return; } // Create a new file and write data to it. FSDataOutputStream out = fileSystem.create(path); InputStream in = new BufferedInputStream(new FileInputStream(new File(source))); byte[] b = new byte[1024]; int numBytes = 0; while ((numBytes = in.read(b)) > 0) { out.write(b, 0, numBytes); } // Close all the file descripters in.close(); out.close(); fileSystem.close();
4.2 读流程
比如文件的获取流程:
client
发起hadoop fs -get
请求;NameNode
检查该文件的信息,文件的分块信息和每个分块所对应哪个DateNode
,以及备份信息和备份信息所在哪个DataNode
;NameNode
把这些信息返回给client
端。(返回原则也是机架原则,根据网络拓扑将距离最近的DataNode
排在前边返回);- 根据
NameNode
的信息,请求各个文件块对应的DataNode
节点获取文件数据; - 合并下载过来的数据块,形成一个完整的文件。
读流程Java示例:
Configuration conf = new Configuration(); FileSystem fileSystem = FileSystem.get(conf); Path path = new Path("/path/to/file.ext"); if (!fileSystem.exists(path)) { System.out.println("File does not exists"); return; } FSDataInputStream in = fileSystem.open(path); int numBytes = 0; while ((numBytes = in.read(b))> 0) { System.out.prinln((char)numBytes));// code to manipulate the data which is read } in.close(); out.close(); fileSystem.close();
05 文末
本文是通过搜集资料并根据自己的理解整理的,如有疑问的童鞋欢迎留言,谢谢大家的阅读,本文完!
参考文献: