HDFS-hadoop的文件系统
hadoop 的文件存储系统成为 hdfs(hadoop distributed file system),它用于解决大数据的存储问题,可以管理 分布在多台服务器中数据。
1. 概述
它具有如下的 优缺点:
优点:
- 多副本存储文件,具有高容错性;
- 分布式存储,适合处理大数据, 并且可将集群构建在廉价机器上。
缺点:
- 不适合低延迟的数据访问;
- 无法高效的对大量小文件进行存储(占用 NameNode 大量的内存来存储文件目录和块信息,并且小文件存储的寻址时间会超过读取时间,违反了 hdfs 的设计目标);
- 不支持并发写入,文件随机修改。
HDFS主要由下面几个部分 组成:
- NameNode: 充当整个集群文件系统的目录功能,存储 文件的元数据信息(metadata, 包括文件名,副本数,权限等)。此外,它还作为整个集群文件的管理者, 管理数据块的映射信息, 处理来自客户端 的读写请求等。
- Secondary NameNode: 它并非 NameNode 的热备(就是说 NameNode 如果挂掉,它并不能马上替换 NameNode 并提供服务)。它的主要工作是辅助 NameNode的工作,包括定期合并
Fsimage
和Edits
文件,并推送给 NameNode。在紧急情况下,可用于恢复部分 NameNode 内容。 - DataNode: 负责实际的数据存储。
- Client: 可请求数据读写。
HDFS 数据 存储块的大小 默认为 128 M(源码中在 hdfs-default.xml
文件中通过参数 dfs.blocksize
),该值主要取决于 系统磁盘读写的速率。
一般地认为,寻址时间为传输时间 1% 为最佳状态,如寻址时间约为 10ms,则可计算出最佳的传输时间为约 1s。若当前磁盘传输速率普遍为 100 MB/s,一个块文件需要一次寻址,则可获得 HDFS 块的推荐大小:1s * 100MB/s = 100 MB
,近似为 128 M。所以,如果磁盘读写速度快(如 SSD),则推荐使用更大的 HDFS 块大小。
2. HDFS的数据读写
2.1 shell 操作
HDFS 提供相关的指令对 文件系统中的文件进行管理(如上传、下载、删除等)。具体可以使用 bin/hadoop fs 具体命令
or bin/hdfs dfs 具体命令
,这两个指令差不多, hadoop fs
相当于是 hdfs dfs
的 “父类”。
1 | hadoop fs -help rm # 查询 rm 指令的功能 |
整体来说,hdfs 的操作指令与 linux 文件的操作非常类似。
2.2 客户端操作
可以在 windows 上建立客户端,然后通过 java 程序来操作 hdfs 的文件。首先需要在 windows 上搭建 hadoop 环境,参考 link。
配置完毕后,可以使用 intellij 新建一个 maven 工程,具体可以参考 github 中的 代码。
使用客户端可以进行对 hdfs 进行读写。其中 写数据 步骤如下:
- 客户端创建 distributed
FileSystem
对象(含有上传到 hdfs 系统中的路径信息),向 NameNode 所在的服务器发送上传请求; - NameNode 检查文件路径等信息,进行一些检查:例如文件是否存在,路径是否合法等。检查完毕后响应客户端的请求;
- 客户端得到可以上传的响应信息后,请求上传第一个 block;
- NameNode 收到该请求后进行分析,返回给客户端上传数据的 DataNode,e.g. dn1, dn2, dn3。数据结点的确定主要根据两个因素:1. 距离近的有限上传;2. 负载轻的优先上传;
- 客户端生成输出流
FSDataOutputStream
,向对应的 DataNode 请求建立 block 的传输通道; - DataNode 应答成功,客户端进行数据传输(一个个的 packets);
- DataNode 服务器中首先将数据放置在内存中,一边序列化到本地硬盘,一边传输到下个结点的内存中。
在上面的第四步中,NameNode 需要寻找存储数据的结点,这一结点的确定遵循距离最近的原则,即上传数据的结点与存储数据的结点距离尽可能近。这里,就需要定义 结点距离:为两个结点到达最近的公共祖先的距离总和。例如:
- 同一结点上的进程:距离 = 0;
- 同一机架上的不同结点(共一个端结点):距离 = 2;
- 同一数据中心不同机架上的结点(同一数据中心的机架端结点接到同一个数据中心结点上):距离 = 4。
除了上述的距离最近原则,具体存储数据时 hadoop 还需考虑数据的安全可靠。对于常见的 3副本设置(参考官网),数据的放置一般首先放置在某一随机的结点(尽量考虑距离近,负载均衡),然后第二个副本放置在同一机架的不同 结点上,而第三个副本则放置在不同的机架上(为了安全可靠性)。
类似于写数据,读数据也需要客户端首先与 NameNode 进行通讯,然后再从具体的 DataNode 上读取数据。步骤如下:
- 客户端创建 distributed
FileSystem
对象(包含 hdfs 文件目录信息),向 NameNode 发送下载请求; - NameNode 返回目标文件的元数据,客户端获得数据存在的 DataNode 位置;
- 客户端创建
FSDataInputStream
对象,并逐块向对应的 DataNode 结点请求数据(如果多块文件在同一个服务器上,可以一次性返回); - 获取完毕数据后本地拼接为完整文件。
3. 文件索引系统
NameNode 和 SecondaryNameNode 共同构成了 HDFS 的文件索引、管理系统。这里对他们的工作机制进行详细的介绍。
3.1 NameNode工作机制
在运行的 HDFS 系统中,NameNode 为实现运行的高效,总是在内存中运行。但内存具有掉电丢失的特点,为了保证数据的可靠性,HDFS 会在在磁盘中使用 FsImage
备份元数据(所谓元数据就是文件属性信息,比如修改日期,权限等)。
但频繁操作存储于磁盘中的数据,会降低系统性能。因此,为减少 FsImage
的修改,当需要更新 元数据时,会 首先 将更新的内容记录到 Edits
文件(也在磁盘中,但只进行追加操作,效率非常高),然后 再在 内存中更新(安全性)。
当 NameNode
服务器上电时,它将编辑日志(edits_inprogress_xxx
)和 镜像文件(Fsimage
) 加载到内存中,进行合并,恢复出整个集群的元数据信息 (通常内存至少128 G, 每个 block 占 150 bytes)。
3.2 SecondaryNameNode工作机制
由于 Edits
文件 不能无限扩大,再它达到一定大小时,需要与 FsImage
文件进行合并。HDFS 使用 SecondaryNameNode,来实现这一功能。具体地,在 SecondaryNameNode 中,会按顺序执行下列操作:
- 请求询问 NameNode 是否需要进行 checkpoint 操作 (即日志和镜像文件合并),当下列两个任一个满足时,会触发 checkpoint:
- 定时时间到(默认是1小时,
hdfs-site.xml
中配置 propertydfs.NameNode.checkpoint.period
修改) - Edits 中的数据条数超过阈值(以轮询方式查询,默认每隔1分钟轮询一次,默认阈值是100万条,
hdfs-site.xml
中,dfs.NameNode.checkpoint.txns
配置阈值,dfs.NameNode.checkpoint.check.period
配置轮询时间间隔);
- 定时时间到(默认是1小时,
- 如果需要 checkpoint 操作,首先将 NameNode 中的
edit_inprogress_001
文件滚动为edits_001
并同时生成 空的edit_inprogress_002
文件,后序修改记录将会添加到edit_inprogress_002
中。 - 然后将
edit_001
和FsImage
文件拷贝到 SecondaryNameNode 中,SecondaryNameNode 在内存中将上述两者进行合并,生成新的FsImage
文件。 - 最后将合并生成的新的
FsImage
文件拷贝回 NameNode 中,替换旧的Fsimage
文件。
3.3 Edit、FsImage 文件
在 NameNode 服务器上,Edit
和 FsImage
文件在 目录 hadoop-2.8.3/data/tmp/dfs/name/current
中。可以使用 hdfs oiv -p XML -i <要转换的fsimage 文件名> -o <输出的文件名.xml>
将 FsImage 转为 xml 文件进行展示。可以看到,在 fsimage 文件中,存放了文件的 文件名,路径,副本数,权限,创建时间 等 meta 信息。类似的,可以使用 hdfs oev -p XML -i <要转换的 edits 文件> -o <输出的文件名.xml>
将 Edits
文件转为 xml 格式进行查看。
需要注意的是,FsImage
文件和 Edits
文件 并没有记录 块所对应的 DataNode。在 HDFS 中,这一信息 (DataNode 上的数据块信息) 将会在在集群启动后 由各个 DataNode 进行 动态上报。具体地,在集群启动时,所有 DataNode 会上报一次他们所持有的数据块信息,然后,后序每隔一段时间 DataNode 会再进行上报。这么做是因为数据块的位置信息可能会因为 DataNode 的状态而变化,因此使用动态的方式获取,保证数据位置信息的准确性和实时性。
3.4 集群的安全模式
根据上述的介绍,我们知道了 HDFS 文件索引系统保存更新索引的方式。在这样的机制下,HDFS 系统在 NameNode 启动时,会有一段特殊的安全模式期。
所谓的 安全模式 是指 NameNode 文件索引系统对于客户端来说是只读的,不允许执行写操作。当 HDFS 系统启动,便处于安全模式。
NameNode 首先将镜像文件 FsImage
载入内存,并执行编辑日志(Edits
) 中的各项操作。合并完成后,创建一个新的 FsImage
文件和一个空的 编辑日志放回磁盘,同时,NameNode 会开始监听 DataNode 的请求。
对于各个 DataNode,他们以块列表的形式记录 各个存储在它们上的数据块。在系统正常操作期间, NameNode 会在内存中保留所有块的位置映射信息。但在 DataNode 和 NameNode 启动时,需由 DataNode 向 NameNode 发送最新的块列表信息。
最后,当 NameNode 完成 FsImage 的 合并操作,并且接收到 足够多的块位置信息 后,才会退出安全模式(达到最小副本条件后30s 退出安全模式)。
所谓 最小副本条件 是指: 整个文件系统中 99.9% 的块满足最小副本级别的要求(默认值:dfs.replication.min=1
)。
最后,在刚刚格式化一个 hdfs 集群的时候,由于系统中还没有任何块,NameNode 不会进入安全模式。
4. 数据结点
DataNode 中存放一个个的 blocks, 数据 block 的内容包括:数据,数据长度,校验和,时间戳。通过上面对 NameNode 的介绍,我们知道数据的存储信息仅放置在 NameNode 内存中(即不做持久化处理),需要 DataNode 进行动态的上报、更新。
具体的,块信息分为 启动时 上报和 运行中 的上报。启动时,DataNode 启动后向 NameNode 注册,报告其中的块信息,注册成功后,NameNode 向 DataNode 返回注册成功信息。运行中, DataNode 会每隔固定时间(1小时)上报一次所有块信息。
4.1 可用性判断
除了数据块信息的上报,NameNode 需要知道 DataNode 的 可用性,即判断相关的 DataNode 网络是否顺畅连通,硬件是否运行正常。这一目标由 DataNode 和 NameNode 之间保持的 心跳通讯 来实现。DataNode 心跳每3秒1次,心跳返回结果带有 NameNode 给该 DataNode 的命令。
通常,如果超过 10 分钟(+30s)没有收到 DataNode 的心跳,NameNode 会认为该结点不可用,从而以后不会再向该 DataNode 中存放任何内容。
上述的 DataNode 的延迟下线时间称为 超时时长。hdfs 默认的超时时长 10分钟 + 30 秒 通过公式 timeout = 2 * dfs.NameNode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval
计算。其中 dfs.NameNode.heartbeat.recheck-interval
默认值为 5分钟(300’00 ms),dfs.heartbeat.interval
默认值为 3秒。
4.2 服役新节点、退役结点
如果想向集群中添加新的 datanode,只需要镜像集群中的一台 datanode 机器,修改 ip 和主机名称,并删除其中的旧数据 和 旧 logs: rm -rf /data /logs
。最后在新的结点上单独启动 DataNode 以及 nodemanager,即可自动并入集群中。
如果想提升安全性,仅让有权限的机器加入到集群中,可以使用 “白名单” 功能(hdfs-site.xml
中添加 dfs.hosts
属性)。此外,还可以使用黑名单方式,强制集群中的某些服务器退出(退出结点上的内容会被拷贝到其他节点上)。
5. 其他
5.1 存档文件
小文件会影响 hdfs 系统的性能。因为每个小文件都占用一个文件块,而每个文件块都需要在 NameNode 中占有一条记录,故每个小文件都会占用 150 字节的记录空间(注意:不影响DataNode,数据实际存储空间仍是文件大小)。因此,有大量小文件时,会大量占用 NameNode 中的索引资源。
一种处理方案是 使用 hdfs 存档文件 或称 har 文件。原理上,hdfs 存档文件对内是一个个独立文件,但是对 NameNode 而言却是一个整体,因为减少了在 NameNode 中内存的占用。
1 | hadoop archive -archivename <归档后的名字-.har 结尾> -p <src文件的路径> <输出文件的路径> |
5.2 快照管理
HDFS 支持快照备份。但 HDFS 快照并不会立即复制所有的文件,在产生快照时,仅对目录做一个复制备份,只有当后序有写入、修改发生时,才会产生新的文件。
1 | 开启指定目录的快照功能 |
参考
- 尚硅谷Hadoop 2.x教程(hadoop框架精讲):https://www.bilibili.com/video/BV1cW411r7c5