HDFS
HDFS
HDFS定义
Hadoop Distributed File System 在数据量不断激增的情况下,一台普通的主机无法存下海量的数据,需要多个主机来储存,但又出现不方便管理与维护的问题,HDFS 是将该集群抽象成一台主机管理该集群上的文件的文件系统,适用于一次写入多次读出的场景。文件在创建、写入和关闭之后就不再需要被修改了。
HDFS 优缺点
优点
- 高容错: 数据自动保存多个副本,提高容错性,当某个副本丢失时,可以自动恢复
- 能够处理海量数据: 1) 能够处理单个文件 GB, TB,PB 级别的数据。 2) 也能处理百万文件数量的数据
- 可以构建在廉价的机器上
缺点
- 不适用于低延迟数据访问: 比如毫秒级的
- 无法高效对大量小文件进行存储: 小文件数量过多,其元数据会大量挤占 NameNode 的内存空间,导致其空间不足或者增加大量的寻址时间
- 不支持并发写入、文件随意修改: 文件只能由一个线程来写,对于修改仅支持追加
HDFS 组成架构
NameNode(nm):HDFS 文件管理的 Master
- 存储文件的元数据 (包括 文件名,文件目录结构, 文件属性(生成时间,权限,副本数等)等)
- 配置副本策略
- 管理文件数据块的映射关系
- 处理客户端的读写请求
DataNode:Slave,执行 NameNode 下达的命令,完成执行的实际操作
- 存储实际的数据块
- 执行数据块的读写操作
Client:
- 文件切分。文件上传到 HDFS 之前, Client 将文件切分成一个一个 Block ,然后上传
- 于 NameNode 交互获取文件位置信息
- 与 DataNode 交互,进行读写操作
- Client 提供一些命令管理 HDFS 如格式化 NameNode
- Client 可以提供一些命令来访问 HDFS, 比如对 HDFS 增删改查
Secondary NameNode:并不是 NameNode 的热备。当 NameNode 挂掉时,它并不能马上替代 NameNode 并提供服务
- 辅助 NameNode, 分担其工作量,并定期合并 Fsimage () 和 Edits ()并推送给 NameNode
- 在紧急情况下,可辅助 NameNode 恢复
HDFS 文件块大小
HDFS 中的文件在物理上是分块储存(Block),块的大小可以通过配置参数(dfs.blocksize)来设定。 Hadoop 3.x 默认 128 M
- 如果寻找时间为 10ms
- 某些行业经验建议:寻找时间为传输时间的 1% 为最佳,则传输时间 = 10ms/0.01 = 1s
- 目前磁盘的传输速率普遍为 100MB/s
- 数据大小一般为 2 的次方 则 128M
为什么块的大小不能太大,也不能太小
- HDFS 块太小会增加寻址时间
- 太大磁盘数据传输时间会明显大于寻找时间,导致获取该数据的时间增大
HDFS块的大小设定主要取决于磁盘的传输速率
HDFS 小文件处理
影响
存储层面
1个文件块占用的 namenode 150 字节
128 G 能存储的文件块数量 128 * 1024* 1024 * 1024 byte /150 = 9 亿个文件块
计算层面
每个小文件都会起一个 MapTask,占用大量计算内存
解决方法
- 采用 har 归档方式,将一个文件下所有文件进行归档,对内还是一个一个小文件,对 NameNode 而言是一个整体,减少 NameNode 的内存
- 使用 CombineTextInputFormat
- 有小文件场景开启 JVM 重用(处理时间远小于启动 JVM 的时间); 如果没有小文件,不要开启,因为会一直占用 task 卡槽, 直至任务完成才释放。
JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间
HDFS 的 shell 操作
hadoop fs + 具体命令 or hdfs dfs + 具体命令
命令
1 |
|
和 Linux 中的 常用 shell 命令很类似
HDFS 读写流程
写流程
- 客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件, NameNode 检查目标文件是否已存在,父目录是否存在
- NameNode 返回是否可以上传
- 客户端请求第一个 Block 上传到哪几个 DataNode 服务器上
- NameNode 返回 3 个 DataNode 节点, 分别为 dn1, dn2, dn3
- 客户端通过 FSDataOutputStream 模块请求 dn1 上传数据,dn 1 收到请求后会继续调用 dn2 ,然后 dn2 调用 dn3, 将这个通信管道建立完成
- dn1, dn2, dn3 逐级应答客户端
- 客户端开始向 dn1 上传第一个 Block (先从磁盘读取数据放到一个本地内存缓存),以 Packet 为单位, dn1 收到一个 Packet 就会传给 dn2, dn2 传给 dn3; dn1 每传一个 packet 会放入一个应答队列等待应答
- 当一个 Block 传输完成之后, 客户端再次请求 NameNode 上传第二个 Block 的服务器(重复 3-7 )
网络拓扑节点副本选择
HDFS 在写数据的过程中,NameNode 会选择距离最近的 DataNode 接受数据。
节点距离:两个节点到达最近的共同祖先的距离总和
距离计算
distance:
同一节点上的进程:0
同一机架上的不同节点:2
同一数据中心不同机架:4
不同数据中心:6
副本选择
- 第一个副本在 Client 所处的节点上,如果客户端在集群外,随机选一个
- 第二个副本在另一个机架上的随机节点
- 第三个副本在第二个副本所在机架的随机节点
读流程
- 客户端通过 DistributedFileSystem 向 NameNode 请求下载文件,NameNode 通过查询元数据,找到文件块所在的 DataNode 地址
- 挑选一台 DataNode (就近原则,然后随机)服务器,请求读取数据
- DataNode 开始传输数据给客户端 (从磁盘里面读取数据输入流,以 Packet 为单位校验)
- 客户端以 Packet 为单位接受,先在本地缓存,然后写入目标文件
NameNode 和 SecondaryNameNode
NameNode 元数据存储位置
- 内存
- 磁盘上的 FsImage:元数据如果放在内存上可以提高访问效率,但是断电就会导致数据丢失。
- 磁盘上的追加写入文件 Edits:追加写效率很高,如果内存元数据更新时又要保证同时更新 FsImage 就会导致效率过低,如果不更新容易出现一致性问题,断电还是会导致数据丢失,所以引入 Edits 文件。
- SecondaryNameNode:如果长时间添加 Edits 文件,当出现断电时恢复数据需要合并 FsImage 和 Edits 文件,此时数据恢复时间会大大增加。因此需要定期合并两个文件,如果发生在同一个 NameNode 上又会导致效率降低。所以 SecondaryNameNode 用来处理此事务。
Fsimange: HDFS 文件系统元数据的一个永久性的检查点,包含HDFS 文件系统的所有目录和文件 inode 的序列化信息
Edits:存放HDFS 所有更新操作的路径。
第一阶段:NameNode 启动
- 第一次启动 NameNode 格式化后, 创建 FsImage 和 Edits 文件。如果不是第一次启动,直接加载两个文件到内存。
- 客户端对元数据进行增删该的请求。
- NameNode 记录操作日志,更新滚动日志(Edits)。
- NameNode 在内存中对元数据进行增删改。
第二阶段:Secondary NameNode (SNN) 工作
- Secondary NameNode 询问 NameNode 是否需要 CheckPoint。
- Secondary NameNode 请求执行 Check Point
- NameNode 滚动写 Edits 日志
- 滚动前的日志和 FsImage 拷贝到 SNN
- SNN 加载 Edits 和 FsImage 到内存并合并
- 生成新的 fsimage.chkpoint。
- 拷贝 fsimage.chkpoint 到NameNode
- NameNode 将 fsimage.chkpoint 重命名为 fsimage
CheckPoint 时间设置
- 通常情况下,Secondary NameNode 每个一小时执行一次 (hdfs-default.xml 中的 dfs.namenode.checkpoint.period 进行修改)
- 一分钟检查一次操作次数,当操作次数达到一百万时,Secondary NameNode 执行一次
DataNode
DataNode 工作机制
- 一个数据块在 DataNode 上以文件形式存储在磁盘上,包括两个文件,一个是文件本身,一个是元数据包括数据块长度,数据块的校验和,以及时间戳
- DataNode 启动之后向 NameNode 注册,通过之后,周期性(6小时)向 NameNode 上报所有的块信息。
- 心跳是每 3 秒一次,心跳返回结果带有 NameNode 给该 DataNode 的命令如复制块数据到另一台机器,或者删除某个数据块。如果超过 10 分钟没有收到某个 DataNode 的心跳 则认为该节点不可用。
- 集群运行中可以安全加入和删除一些机器
定义超时时间为TimeOut,则超时时长的计算公式为:
TimeOut = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval。
而默认的dfs.namenode.heartbeat.recheck-interval 大小为5分钟, dfs.heartbeat.interval默认为3秒。
保证数据完整性
- 当 DataNode 读取 Block 的时候,它会计算 CheckSum
- 如果计算后的CheckSum,与 Blocl 创建时的值不一样,说明损坏
- Client 读取其他 DataNode 上的 Block
- DataNode 在其文件创建后周期性验证 CheckSum
心跳并发配置
Hadoop3.x系列,配置NameNode内存是动态分配的,NameNode内存最小值1G,每增加100万个block,增加1G内存。
需要给NameNode 配置多少线程
企业经验:dfs.namenode.handler.count=
$$
20×log_e^{Cluster Size}
$$
,比如集群规模(DataNode台数)为3台时,此参数设置为21。
纠删码原理
cpu 资源换存储空间
HDFS 默认情况下,一个文件有 3 个副本,这样提高了数据的可靠性,但也带来了 2 倍的冗余开销。 Hadoop3.x 引入了纠删码, 采用计算的方式, 可以节省约 50%左右的存储空间。
例如以前存放 3 个副本每一个假设 3k 共 9k,则现在存放 3 个数据单元共 3k,2 个校验单元假设一个 1k 共 2k 总共 5k 相较于以前节省了存储空间
异构存储
存储类型
RAM_DISK:(内存镜像文件系统)
SSD:(SSD固态硬盘)
DISK:(普通磁盘,在HDFS中,如果没有主动声明数据目录存储类型默认都是DISK)
ARCHIVE:(没有特指哪种存储介质,主要的指的是计算能力比较弱而存储密度比较高的存储介质,用来解决数据量的容量扩增的问题,一般用于归档)
存储策略
说明:从 Lazy_Persist 到 Cold ,分别代表了设备的访问速度从快到慢
策略****ID | 策略名称 | 副本分布 | 说明 |
---|---|---|---|
15 | Lazy_Persist | RAM_DISK:1,DISK:n-1 | 一个副本保存在内存RAM_DISK中,其余副本保存在磁盘中。 |
12 | All_SSD | SSD:n | 所有副本都保存在SSD中。 |
10 | One_SSD | SSD:1,DISK:n-1 | 一个副本保存在SSD中,其余副本保存在磁盘中。 |
7 | Hot(default) | DISK:n | Hot:所有副本保存在磁盘中,这也是默认的存储策略。 |
5 | Warm | DSIK:1,ARCHIVE:n-1 | 一个副本保存在磁盘上,其余副本保存在归档存储上。 |
2 | Cold | ARCHIVE:n | 所有副本都保存在归档存储上。 |