前言
前段日子处理了一个公司hdfs客户端读写抛错的问题,复习了下hdfs的文件读写,感觉网上可接收的材料很单一,大部分还是靠hdfs的官方文档和源代码,有些博客也太乱,要不贴代码,要不从一两篇博客上扒的,对新手不是很友好,这里总结普及一下。
目录
前言
一,从hdfs架构开始
二,hdfs读写流程
三,hdfs特性
一,从hdfs架构开始
hdfs具有主/从体系结构,通常支持HA(高可用)的集群具有:
1. 两个NameNode
一个是active的状态,负责所有的客户端动作和datanode的分配,使整个集群的心脏;另一个是standby状态,负责namenode的高可用。NameNode存放着所有hdfs仓库的元信息,包括文件名,数据块id,数据块存放路径等。主从namenode之间可以通过节点里的editlog相当于事务日志记录,共享元信息的更改,而所有文件系统以及命名空间被保存在FsImage中
2. journey node
提供namenode的数据共享服务,用于两个namenode的高可用,当active状态的namenode挂了之后,给另一个namenode提供集群实时热备功能 让整个集群不间断服务。Active namenode写在editlog的操作会发送给journey node,Standby namenode将会从JouralNode中读取这些edits,并持续关注它们对日志的变更。JouralNode开的是轻量级的守护进程,它们可以和hadoop的其他进程部署在一起,部署个数往往是3或以上的奇数保证形成高可用容错的多数派。当failover发生时,Standby将会在提升自己为Active之前,确保能够从JNS中读取所有的edits;
3. datanode
数据块真正存储的地方,hdfs存储的数据以加密后数据块形式存在datanode中。
4. client客户端
用户执行fs shell命令操作hdfs的地方,包含hadoop的各种镜像和执行文件脚本,通过安全认证就可以操作
5. zookeeper
接收心跳,用于NameNode节点之间互相的错误感知和选主
HDFS各个节点基本职能就是这样,高可用架构大致如下:
fig.1 HDFS HA架构(图片来源网络)
二,hdfs读写流程
首先可以复习一些fs shell操作的基本命令
当我们在client端输入hadoop指令操作hdfs存储的资料时,到底发生了什么?
读操作
1. 客户端fs shell执行完指令的解析后,如果缓存没有响应,会调用FileSystem对象的open方法,创建DistributedFileSystem的实例,执行文件系统初始化。
2. 创建一个DFSclient,通过这个DFSclient执行代理的功能于NameNode交互。这个时候如果是HA方式也会创建standby namenode的proxy,如果active NN挂了保证下一个RPC可以直接打到备用namenode。最后通过RPC拿到namenode记录的数据块位置。
3. 执行open向InoutStream请求读,InputStream根据返回的检查自身节点保存的数据块,如果不存在向datanode发送数据请求
4. 如果比较近的datanode返回数据块失败或超时
5. 会向距离比较远的datanode发送读请求返回数据块,确保服务的高可用
当一个块结束时,DFSInputStream将关闭与数据节点的连接,然后为下一个块找到最佳的数据节点。从客户端的角度来看,这只是读取连续的流。客户端完成读取后,在FSDataInputStream上调用close()。
fig.2 HDFS读过程
写操作
1. 判断文件系统初始化,在DistributedFileSystem上调用create()
2. 与NameNode进行通信以在文件系统的命名空间中创建一个新文件,而没有与之关联的块。如果该文件尚不存在,并且客户端具有正确的权限,则NameNode将创建该文件;否则,文件创建将失败,并且客户端将引发IOException。
3. DistributedFileSystem返回FSDataOutputStream供客户端开始向其写入数据。
4. 客户端写入数据时,在DFSOutputStream内部将其拆分为数据包,然后将其写入内部的数据队列。在内部的data streamer会通过选择合适的datanode来存储namenode要求分配的新块和副本并形成一个列表。DataStreamer将数据包流式传输到datanode互连的管道中的第一个数据节点,后者存储数据包并将其转发到管道中的第二个数据节点,依此类推。
5. DFSOutputStream还维护等待数据节点确认的内部数据包队列,称为ack队列。在与datanode联系以表明文件已完成之前等待确认,并将所有剩余的数据包刷新到datanode管道。当管道中的所有datanode都已确认包后,将其从ack队列中删除。
6. 客户端完成数据写入后,将在流上调用close()。
7. namenode通过Data Streamer要求分配块的信息已经获取到数据块在datanode的存储信息,因此它仅需等待最小复制块即可成功返回。
fig.3 HDFS写过程
三,hdfs特性
我们从以上反推hdfs特性,会给我们更深的印象:
1. Hardware Failure
一份数据分布式存储三份,通过namenode来记录元信息,各个节点再实现高可用,可以说比传统的数据库信息保存做的好得多了。
2. Streaming Data Access
所有的操作在client端是不感知的,不过这里的hdfs还是针对于文件批处理,支持数据高吞吐,没有保证很好的低延迟特性,也是后来spark streaming和flink等流计算处理后来居上的原因吧
3. Large Data Sets
hadoop一大特点是datanode可以设置很多,而且不需要很高的性能,这就让hadoop有了超强的数据收纳能力,扩展带宽,加上算法的加持适合大数据集的操作。
4. Simple Coherency Model
hdfs一写多读的特性指一个文件创建写入之后,关闭并不会改变文件,在高吞吐的数据处理中始终保持一致性。而且当我们删除一个文件时,文件会暂时保存在/trash的文件夹内,等过配置垃圾清理时间才会被清除
5. “Moving Computation is Cheaper than Moving Data”
大数据处理如果在应用中移动数据进行运算将会耗费很多资源和时间,所以hdfs采用把计算移动到数据靠近的位置来避免网络拥挤等因素带来的损耗,体现在数据块的分配及查找算法中。
6. Portability Across Heterogeneous Hardware and Software Platforms
hadoop项目使用java写的,所以可以采用jar包的方式进行配置部署,达到一次编译处处运行,可跨平台,移植性好。
参考:
1. 官方文档:https://hadoop.apache.org/docs/r1.2.1/hdfs_design.pdf
2. 浅析hdfs读写: https://blog.csdn.net/yangjjuan/article/details/72875990
3. JN的作用:https://www.cnblogs.com/muhongxin/p/9436765.html