首页 > 代码库 > HDFS概述
HDFS概述
HDFS概述
- HDFS不适合低延迟,小文件多,采用流式访问,一个时间点只有一个写入。HDFS采用主从结构,一个NameNode,多个DataNode。
- Namenode是文件系统元数据的数据存储库,它保存了文件信息,以及两个映射关系(文件与数据块的映射,块与DataNode数据节点的映射关系)。文件名到数据块的映射关系由于只被NameNode独知,因此它不仅需要在NameNode内存存储,还需要序列化到磁盘中,以克服宕机后的元数据恢复工作。
- Datanode是文件存储的实体,它以数据块的形式保存着文件的内容及校验信息。它同时保存着数据块和datanode的映射关系。在datanode启动的时候将映射关系上报给namenode,namenode不序列化到磁盘中。当datanode的数据发生修改时候,它会及时反馈给namenode,namenode根据反馈信息对文件系统的元数据信息以及映射关系进行更新或者修改,使数据保持一致。
- SecondaryNameNode是用于定期合并命名空间镜像和编辑日志的辅助节点。它并不接收HDFS的实时变化,在给定间隔和条件下从NameNode上下载镜像和日志进行合并并上传给NameNode节点,避免NameNode日志过大,恢复过慢
- HDFS客户端是用户与HDFS交互的手段,有命令行接口,各种api等。
HDFS架构框图
HDFS实体接口
ClientProtocol
- ?客户端与名字节点的相关接口
- ?处理文件相关的,添加申请块,放弃块,获取块位置,报告块,以及文件相关的设置权限,创建删除追加等。还有一部分是状态查询相关的。
- ?客户端通过create创建文件,写入数据之前,需要使用addBlock向名字节点申请一个块,申请完毕后,客户端开始使用流接口和数据节点通信,如果此时数据节点崩溃,客户端使用abandonBlock放弃刚申请的块。 客户端还使用fsync将文件持久化到磁盘中,使用complete发起关闭文件写入。
- ?客户端通过renewLease向名字节点申请租约,类似于心跳信息,如果名字节点长时间收不到客户端的租约更新,那么名字节点会关闭文件,防止资源泄露。客户端如果从崩溃中恢复,想继续写入文件,需要使用recoverLease恢复租约,如果文件已经成功关闭,客户端根据返回值使用append重新打开文件写入即可。
- ?客户端使用getBlockLocations获取文件块的地址发起读请求,此方法一次返回多个块的位置信息,降低客户端与名字节点的通信数据。当读取数据发生错误时候,客户端使用reportBadBlocks向名字节点上报错误的块和所在的数据节点。
- ?其余几个方法是关于配额,升级,暂不研究
ClientDatanodeProtocol
- ?客户端与数据节点的相关接口
- ?recoverBlock 写入数据过程中数据节点出现错误,需要使用正常的数据节点进行恢复,此函数负责返回正常工作的数据节点
- ?getBlockInfo
- ?getBlockLocalPathInfo 本地读优化,当前客户度和数据节点位于同一台机器上,直接操作本地文件。
DatanodeProtocol
- ?数据节点和名字节点的相关接口
- ?握手,注册,数据块上报,心跳并接收来自名字节点的相关命令。
- ?DatanodeRegistration 继承于DatanodeID,唯一标识数据节点。用于数据节点注册,它有一个StorageInfo成员,用来保存存储系统的信息,像存储系统唯一标示符,存储系统版本号等。
- ?versionRequest 握手,比对NameNode存储系统版本号
- ?register注册,传递DatanodeRegistration对象
- ?blockReport 上报数据块,信息比较多,使用长整形数组,一般只在启动时候上报一次,返回值是DatanodeCommand数据。
- ?sendHeartbeat 发送心跳,保持与名字节点的连接,同时返回datanode的命令数组。
InterDatanodeProtocol
- ?数据节点之间的接口
- ?只用于处理异常情况。有一个数据节点被选为协调者,使用startBlockRecovery用于获得参与数据块恢复过程中的各个数据节点的数据块信息,它的返回值是BlockRecoveryInfo对象。处于协调者的数据节点根据返回值,计算出数据块恢复后的新长度,和名字节点交换信息后,通过updateBlock通知其他数据节点更新数据块到该长度。
NamenodeProtocol
- ?名字节点与第二名字节点接口
- ?均衡器使用getBlocks和getBlockKeys方法将数据块从一个数据节点移动到另一个数据节点,达到负载平衡
- ?第二名字节点通过使用Namenode.getEditLogSize获取编辑日志的长度,日志长度达到配置值后,通过rollEditLog开始一次合并。第二名字节点使用http接口从namenode节点下载
- ?FSImage和Editlog, namendoe开始启用新日志文件。第二名字节点合并镜像和日志,然后通知名字节点,由名字节点下载合并后的镜像。 下载完成后,第二名字节点使用rollFSImage通知名字节点使用新的镜像和新的日志,完成一次元数据合并。
客户端删除文件
客户端发起delete操作,名字节点执行标记删除,当数据节点向名字节点发送心跳的时候,名字节点以DataCommand的形式将删除命令带回给数据节点,执行删除数据的操作。
客户端读文件
客户端发起open操作打开文件输入流FSDataInputStream(其包装了具体的输入流DFSInputSteam),然后使用read方法发起读数据操作。DFSInputStream对象通过和数据节点的流接口,发起getBlockLocations调用,返回数据块的位置。当一个快读取完毕后,它会关闭当前连接,继续使用getBlockLocations获取下一个数据块的数据节点信息。 由于getBlockLocations不会返回一个文件所有的数据块信息,因此getBlockLocations可能需要被多次调用。读取如果出现错误,客户端会将此错误报告给名字节点。同时尝试从下一个数据节点读取块。
客户端写文件
客户端使用DistributeFIleSystem的create方法创建文件,其中创建了DFSOutputStream,远程调用完毕后DistributeFIleSystem将DFSOutputStream对象包装在FSDataOutputStream中返回给客户端。 当客户端写入数据时候,由于是个空文件,首先DFSOutputStream向名字节点申请数据块,返回LocateBLock对象,通过此对象,DFSOutputStream开始和数据节点通信,写入数据,写入完毕后close关闭流。如果写入过程中数据节点故障,数据流会被关闭,当前正常工作的数据节点上的数据块会被赋予一个新的版本号,旧的不完整的会因为版本号不匹配被删除。
数据节点和名字节点
名字节点和数据节点是主从关系,数据节点不会主动向名字节点发起ipc调用。数据节点向名字节点发送心跳包,如果名字节点有需要数据节点配合的地方,会返回给数据节点DataCommand数组。例如需要删除数据节点的数据时候,名字节点会返回给数据节点DNA_INVALIDATE命令,数据节点删除数据块,释放存储空间。
第二名字节点合并元数据
Hadoop文件系统
- .Hadoop抽象文件系统FileSystem,位于包org.apache.hadoop.fs.FileSystem下。它包含基本的文件目录操作和读写数据接口。
- .基本操作:打开,关闭,创建,关闭,定位,读写文件,获取和设置文件属性。
- .文件目录操作使用FileSystem接口方法处理,读写文件使用基于流的方式读写
Hadoop I/O流
- ?FSDataOutputStream : DataOutputStream, Syncable : FilterOutputStream 它并没有实现Seekable接口,因此并不支持随机写,用户不能在写的过程中定位位置,它通过内部类PostionCache实现了getPos的功能,获取写入的位置。 它还实现了Syncable接口,用于将数据同步到设备中。
- ?Seekable :完成随机读取以及seekNewSource选择下一个数据节点
- ?PositionedReadable:指定位置读取数据,不改变流的位置
- ?FSDataInputStream : DataInputStream, Seekable, PositionedReadable 实现数据类型过滤流。
- ?FSInputStream : InputStream, Seekable, PositionedReadable不改变流的读取位置。
- ?FSInputStream有多个子类,是具体文件系统的具体输入流
Hadoop I/O流总结
- ?FSDataInputStream和FSDataOutputStream都通过装饰者模式,对流进行增强。它们都依赖具体的能够接收和发送的数据流来进行对象的构造。
- ?像前面介绍的FSInputStream就是具体的读数据流,它的子类像DFSInputStream负责hdfs的数据读取工作。
Hadoop网络流
- ?抽象类: URLStreamHandlerFactory,URLStreamHandler,URLConnection。
- ?Factory时工厂类,它负责处理协议模式,例如”hdfs://example/conf.txt”。由其找到具体的handler后,由URLStreamHanler调用openConnection创建URLConnection对象。
- ?URL.openStream中调用URLConnection的getInputSteam,getInputSteam中通过FileStream.openConnection获取输入流返回
HDFS概述