HDFS概述
Hadoop的分布式文件系统
hadoop的三大核心子项目(HDFS,YARN,MapReduce)之一,用来解决海量数据存储问题
优点:
- 海量数据存储,典型文件大小GB~TB,百万以上文件数量,PB以上数据规模(文件切分分散存储,128M)
- 高容错(多副本策略),高可用(HA,安全模式),高可扩展(10K节点规模)
- 构建成本低(构建在廉价商用机器上),安全可靠(提供容错机制)
- 适合大规模离线批处理(流式数据访问,数据位置暴露给计算框架,如MR,Spark)
缺点:(不适合的场景)
- 不适合低延迟的数据访问(文件拆分,存储,副本,位置记录等等,写延迟高,读取时需要寻址,获取数据后合并)
- 不适合大量小文件存储(元数据占用NameNode大量空间,移动计算时任务数量增加)
- 不支持并发写入(写入失败的话维护成本高)
- 不支持文件随机修改,仅支持追加写入(多个节点的副本修改压力大)
系统架构
- 典型的主从架构,主节点NameNode,从节点DataNode,NameNode存储元数据信息,触发容灾备份,DataNode存储Block
- DataNode每隔3s需要向NameNode发送心跳,报告节点状态和数据块的信息
- 文件切分在客户端完成
- NameNode存储文件切分后的block信息,这部分信息会存储在内存中,且持久化到文件;block的位置信息只在内存中存储,因为DataNode会定时发送心跳汇报
数据存储Block
- Block是HDFS的最小存储单元
- Block和元数据分开存储,Block存储在DataNode中,元数据存储在NameNode中
如何设置Block的大小?
- 目标:最小化寻址开销,当前多数磁盘的读写速度是130-190MB/s,默认大小是128M
- 两面性:块太大,增加了寻址开销,作业执行时间长,块太小,任务数太多,作业调度时间长
多副本
- 默认副本数是3,可更改,但不建议
- 自动机架感知,将副本存储到不同的DataNode上,实现数据的高容错
- 副本均匀分布,提高访问带宽和读取性能,实现负载均衡
Block文件
- Block文件是DataNode本地磁盘中命名为blk_blockId的linux文件
- DataNode在启动时自动创建存储目录,无需格式化
- DataNode的current目录下的文件名都以blk_为前缀
- Block元数据文件(*.meta)由一个包含版本,类型信息的头文件和一系列的校验值组成
Block副本放置策略(3.x开始)
节点选择:同等条件下,优先选择空闲节点
- 副本1:优先找离client网络位置最近的,空闲的DataNode节点,如果client在DataNode节点,则直接放在当前节点
- 副本2:放在不同的机架节点上(2.x的副本2是选择当前机架上的不同节点,3.x是优先选择跨机架的节点)
- 副本3:放在与第二个副本同一个机架的不同的节点上
- 副本N:随机选择
metaData的存储与合并
元数据
- 存放在NameNode内存中
- 包含HDFS中文件及目录的基本属性信息(如文件的owner,权限信息,创建时间等),文件由哪些block构成,block的位置存放信息
元数据信息的持久化
- fsimage文件,是文件系统的元数据的持久性检查点文件(类似于flink的checkpoint吧),文件名上会记录对应的transactionId,不包含block的位置信息
- edits(编辑日志文件)---磁盘文件形式,后续对元数据的修改,以日志的形式追加到edits文件中,因为直接频繁修改fsimage,压力大
- 文件系统客户端执行写操作的时候,首先会被记录在edit log中,通过前后缀记录当前的transactionId,记录后则认为是一次成功的操作
- edits文件不能过大,需要定期合并到fsimage中
- 通过fsimage+edits可以恢复某个时间点的元数据
edits与fsimage的合并机制
读写操作
写操作:
1、客户端请求上传文件,NameNode检查目录和权限,返回能否上传
2、客户端接收到允许上传,将文件切分为块
3、客户端上传block文件,NameNode检查DataNode信息池,返回要写入的DataNode列表
4、客户端请求建立block传输通道,传输管道依次建立
5、客户端以packet为单位发送数据,DataNode接收到数据后写入磁盘并分发给下一个DataNode
6、按照建立的管道顺序,依次返回写入成功直到第一个DataNode汇总,返回给客户端写入成功
7、重复3-6,直到所有的block传输完成,客户端向NameNode报告文件写入成功,NameNode记录元数据信息
注意:NameNode是在文件全部上传成功之后才会记录元数据信息,假设在block只有一部分写入成功,那么这部分block在发送心跳时,NameNode检查发现这部分是没有元数据信息记录的,视为脏数据,这部分数据就会被删掉
读操作:
1、客户端请求读取文件,NameNode检查目录树和权限
2、NameNode查询文件对应的block块信息,以及block块与DataNode的映射关系,按照DataNode与客户端的距离由近到远返回给客户端
3、客户端与最近的DataNode建立连接,读取block数据;每个block块重复同样的操作
4、客户端将组成文件的block的文件拼装成一个文件