Hadoop - HDFS
1. HDFS介绍
1.1 定义
HDFS是一个分布式文件系统,适合一次写入,多次读出的场景
-
数据可以保存在多个副本当中,可以通过增加副本的数量来增加容错
-
不适用于低延时数据访问的场景
-
不能高效的对小文件进行存储
因为会占用NameNode的大量内存,而NameNode的内存是有限的
小文件存储的寻址时间会超过读取时间
- 不支持并发写入和文件的随机修改
一个文件只能有一个写,不允许多个线程同时写入
仅支持数据的追加操作
1.2 组成架构
1.2.1 NameNode
是一个管理者,负责管理HDFS的元数据、数据块映射信息
处理客户端的读写请求
1.2.2 DataNode
针对NameNode下达的命令,DataNode执行实际的操作
存储实际的数据块
执行数据块的读写操作
1.2.3 Client
客户端
文件上传HDFS上时,client将文件切分成block进行上传
与NameNode进行交互,获取文件的存储位置
与DataNode进行交互,读取或者写入数据
通过一些命令来管理和访问HDFS
1.2.4 Secondary NameNode
辅助NameNode来管理元数据
每隔一段时间获取NameNode的快照
定期合并Fsimage和Edis并返回给NameNode
NameNode出现故障,可辅助恢复NameNode
1.3 文件块大小
HDFS中的文件分块进行存储,2.x和3.x默认为128M,1.x默认为64M
文件块大小主要取决于磁盘的传输速率
寻址时间为查找到目标block所需要的时间
寻址时间为传输时间的1%为最佳状态
如果寻址时间为10ms,传输时间就为1s
磁盘传输速率为100M/s
则block大小:100M
如果block设置的太小,会增加寻址时间,程序一直在寻找块开始的位置
如果block设置的太大,传输时间会明显大于寻址时间,导致处理数据非常慢
2 HDFS的读写流程
2.1写数据流程
- client通过DistributedFIleSystem(分布式文件系统)向NameNode请求上传文件,NameNode检查目标文件是否存在,父目录是否存在,返回是否可以上传
- client请求第一个block该上传到哪些DataNode上
- NameNode根据配置文件中的备份数量和机架感知返回可以用DataNode的地址
- client通过FSDataOutputStream(数据输出流),向其中一个DataNode :A 请求上传数据,A收到请求之后会继续调用B,B调用C,逐级返回client(本质就是RPC调用,建立pipeline)
- client开始向A上传以一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位(默认64kb),A收到一个packet就会传给B,B传给C,A每传一个packet会放入一个应答队列等待应答
- 在pipeline的反方向上,会逐个发送ack,最终由A将ack发送给client
- 一个bloeck传输完成之后,重复2,继续传输下一个block
2.2 网路拓扑
NameNode会选择距离上传数据最近距离的DataNode接收数据
节点距离:两个节点到达共同祖先的距离总和
2.3 机架感知
第一个 block 副本放在 Client 所在的服务器,如果 client 不在集群服务器中,则这第一个 DataNode 会随机选择。
第二个副本放置在与第一个节点不同的机架中的节点中,保证机架间的高可用。
第三个有不同机房则跨机房随机放置在某个节点上;只有一个机房则和第二副本在同一个机架,随机放在不同的节点中。
更多的副本,则继续随机放置,需要注意的是一个节点最多放置一个副本。
2.4 读数据流程
- client通过DisributedFileSystem向NameNode请求下载文件
- NameNode会返回文件的部分或者全部的block列表,对于每个block。NameNode都会返回含有该block的DataNode地址,通过网络拓扑得出DataNode与client的距离,进行排序,网络拓扑中距离client近的靠前,心跳机制超时汇报的靠后
- client选择排序考前的DataNode来读取block,如果client本身就是DataNode,就直接从本地获取数据
- 底层本质是建立Socket Stream(FsDataInputStream),重复调用父类的DataInputStream的read方法,知道这个块上的数据读取完毕
- 读取完毕之后,会继续向NameNode获取下一批的block列表
- 读取完一个block都会进行checksum验证,如果获取DataNode出现错误,client会通知NameNode,向下一个拥有该bloeck的DataNode继续读取
- read方法并行读取block信息,不是一块一块的读取
- 最终读取的所有的block会合并成一个完整的文件
3. NameNode工作机制及元数据管理
3.1 NameNode工作机制
3.1.1 NameNode启动
- 第一次启动NameNode格式化之后,创建Fsimage和Edis文件,如果不是第一次启动,则直接加载编辑日志和镜像文件
- client对元数据进行增删改的请求
- NameNode记录操作日志,更新滚动日志
- NameNode在内存对元数据进行增删改
3.1.2 Secondary NameNode工作
- Secondary NameNode询问NameNode是否需要CheckPoint,直接返回NameNode的检查结果
- Secondary NameNode请求执行checkpoint
- NameNode滚动当前写的edits日志
- 将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode
- Secondary NameNode加载编辑日志和镜像文件到内存,并进行合并
- 生成新的镜像文件fsimage.chkpoint
- 拷贝fsimage.chkpoint到NameNode
- NameNode将fsimage.chkpoint重新命名成fsimage
3.2 Fsimage和Edits
Fsimage:NameNode中元数据的镜像,包含HDFS的所有目录和文件inode的序列化信息
Edis:存放HDFS中所有更新操作的路径,client执行的所有操作会先被记录到Edits中
seen_txid:保存最后一个edits_的数字
NameNode每次启动都会将Fsimage读入内存,加载Edits里面的操作,保证内存中的元数据是最新的
4 DataNode
4.1 DataNode工作机制
- 数据块在DataNode以文件的形式存储在磁盘上,包括两个文件,一个是数据本身,另一个是元数据。包括数据块的长度、校验和、时间戳
- DataNode启动之后向NameNode进行注册,成功之后,周期性(默认6小时)的向NameNode上报所有的块信息
- 心跳每三秒进行一次,心跳返回带有NameNode给DataNode的命令,如果超过10分钟没有收到某个DataNode的心跳,就会认为这个DataNode不可用
- 集群在运行的过程中可以加入和退出一些机器
4.2 数据完整性
- 当DataNode读取block的时候,会计算checkSum(校验和)
- 如果计算之后的CheckSum与创建时的不同,说明block已经损坏
- client读取其他DataNode上的block
- DataNode在文件创建之后周期性验证checkSum