HDFS
1. HDFS体系结构
HDFS支持大文件,以流的方式访问数据,数据分布在数据节点(Data Node),文件的元数据保存在名字节点(Name Node)。名字节点的内存大小,决定了HDFS文件系统可保存的文件数量,所以大量小文件会影响名字节点的性能(尽管名字节点内存都较大)。
1.1 数据块Block
默认Block最大为64MB,Block的概念可以使HDFS支持保存比单一磁盘大的文件。
Block包含三个属性:blockId(唯一标识)、numBytes(块大小)、generationStamp(版本号、时间戳)
其中generationStamp用于数据一致性检查,每当数据块后成功添加数据后,都会更新generationStamp,blockId一样,但generationStamp不一样的,表示数据块有无效的。
blockId如果是12345,那么数据库名为blk_12345。
1.2 名字节点和第二名字节点
NameNode存储文件目录树,文件/目录的元信息及文件的数据块索引———NameNode第一关系。
- 命名空间镜像(File System Image,FSImage):保存某一特定时刻HDFS的NameNode状态。
- 命名空间镜像的编辑日志(Edit Log):存储FSImage后续的信息改动。
第二名字节点(Secondary NameNode,SNN)用于定期合并FSImage和Edit Log的辅助守护进程。合并好的FSImage会替换NameNode上的FSImage并清空Edit Log。
1.3 数据节点
DataNode守护进程:将HDFS Block写入Linux实际文件系统中,or 读取实际文件到HDFS Block。
对于类DatanodeID包含以下成员变量:
- name:字符串,ip(or主机名)与端口号对
- storageID:数据节点的存储标识,在NameNode注册时用。
- infoPort:WWW服务器的监听端口。
- ipcPort:IPC服务器监听端口,对于客户端而言,该接口提供了ClientDatanodeProtocol服务。
NameNode----(握手、注册、数据块上报、心跳)----DataNode
- 握手:DataNodeProtocol.versionRequest()
- 注册:DataNodeProtocol.register()
- 上报:DataNodeProtocol.blockReport()
- 心跳:DataNodeProtocol.sendHeartbeat()
1.4 客户端
包括命令行接口、Java API等。
与客户端相关的接口:ClientProtocol(NameNode)和ClientDatanodeProtocol。
2. 过程调用
网络文件系统(NFS)无论是对文件/目录API还是读写文件数据,都是采用的远程过程调用(RPC)。HDFS对文件/目录API的访问采用RPC,但是对文件数据的读写采用的是非RPC的方法。
2.1 名字节点上的非IPC接口
NameNode提供了基于HTTP的流式接口,内建HTTP服务器,通过GET操作获取数据,同样的NameNode也通过GET操作从SecondNameNode获取合并后的FSImage。
2.2 数据节点上的非IPC接口
提供读写Block的TCP流失接口,以及Block替换、拷贝、检验等接口。
写Block采用了数据流管道的概念,即客户端----DataNode1----DataNode2----DataNode3
2.3 客户端读文件
客户端通过调用DistributedFileSystem.open获取FSDataInputStream(内含DFSInputStream),然后通过ClientProtocol.getBlockLocations调用名字节点,返回保存数据库的DataNode节点地址(按客户端与DataNode的距离简单排序),然后客户端调用FSDataInputStream.read方法与最近的DataNode建立连接读取数据,当此DataNode发生错误,客户端会记录此DataNode,避免徒劳无益的尝试,当获取的Block发生校验错误,Client会告知NameNode,当第一块Block处理完成,会再次调用ClientProtocol.getBlockLocations获取第二块Block的名字节点列表,重复上述操作,直到结束。
2.4 客户端写文件
Client调用DistributedFileSystem.creat创建文件,NameNode执行同名操作,通过各种检查后,得到DFSOutputStream返回给Client。调用ClientProtocol.addBlock向NameNode申请数据块,然后Client与NameNode建立联系,建立数据流管道,当客户端收到确认包是,将对应的数据包从内部队列中移除,如果内部队列中还有等待传输的数据,则再次调用addBlock重复上述操作,直到没有数据。
如果在传输过程中,数据节点故障,数据流通道会被关闭,已经发往通道但还没收到确认包的数据包,会重新添加到内部队列。
写租约
客户端写入一个文件时,会被授予一个独占的写租约,该租约会周期性的过期,周期由软限制和硬限制来限定。
软限制:软限制过期,而没有更新租约的(向nameNode发送心跳),其他client可以抢占租约。
硬限制:一小时过期,而没有更新租约的,HDFS认为客户端已经退出,并自动替写入者关闭文件,恢复租约。