HDFS
永久性数据结构
对于管理员来说,深入了解namenode、辅助namenode和datanode等HDFS组件 如何在磁盘上组织永久性数据非常重要。洞悉各文件的用法有助于进行故障诊断和 故障检出。
namenode的目录结构
namenode被格式化之后,将产生如下所示的目录结构:
${dfs.name.dir}/current/VERSION/edits/fsimage/fstime
如第9章所示,dfs.name.dir属性描述了一组目录,各个目录存储的内容相同。 这个机制使系统具备了一定的复原能力,特别是当其中一个目录位于NFS之上时 (推荐配置)。
VERSION文件是一个Java属性文件,其中包含正在运行的HDFS的版本信息。该 文件一般包含以下内容:
#Tue Mar 10 19:21:36 GMT 2009namespaceID=134368441cTime=0storageType=NAME_NODElayoutVersion=-18
属性layoutVersion是一个负整数,描述HDFS永久性数据结构(也称布局)的版 本,但是这个版本号与Hadoop发布包的版本号无关。只要布局变更,版本号便会 递减(例如,版本号-18之后是-19), HDFS也需要升级。否则,磁盘仍然使用旧版 本的布局,新版本的namenode(或datanode)就无法正常工作。
属性namespaceID是文件系统的唯一标识符,是在文件系统首次格式化时设置 的。任何datanode在注册到namenode之前都不知道namespaceID值,因此 namenode可以使用该属性鉴别新建的datanode。
cTime属性标记了 namenode存储系统的创建时间。对于刚刚格式化的存储系统, 这个属性值为0,但在文件系统升级之后,该值会更新到新的时间戳。
storageType属性说明该存储目录包含的是namenode的数据结构。
文件系统映像和编辑曰志
文件系统客户端执行写操作时(例如创建或移动文件),这些操作首先被记录到编辑 日志中。namenode在内存中维护文件系统的元数据,当编辑日志被修改时,相关 元数据信息也同步更新。内存中的元数据可支持客户端的读请求。
在每次执行写操作之后,且在向客户端发送成功代码之前,编辑日志都需要更新和 同步。当namenode向多个目录写数据时,只有在所有写操作均执行完毕之后方可 返回成功代码,以确保任何操作都不会因为机器故障而丢失。
fsimage文件是文件系统元数据的一个永久性检查点。并非每一个写操作都.会更新 这个文件,因为fsimage是一个大型文件(甚至可高达几个GB),如果频繁地执行写 操作,会使系统运行极为缓慢。但这个特性根本不会降低系统的恢复能力,因为如 果namenode发生故障,可以先把/hmage文件载入到内存重构新近的元数据,再 执行编辑日志中记录的各项操作。事实上,namenode在启动阶段正是这样做的。
如前所述,edits文件会无限增长。尽管这种情况对于namen0de的运行没有影响, 但由于需要恢复(非常长的)编辑日志中的各项操作,namenode的重启操作会比较 慢。在这段时间内,将文件系统处于离线状态,显然,这有违用户的期望。解决方案是运行辅助namenode,为主namenode内存中的文件系统元数据创建检查 点。0创建检查点的步骤如下所示(参见图10-1)。
1.辅助namenode请求主namenode停止使用edits文件,暂时将新的写操作记录 到一个新文件中。
2.辅助 namenode 从主 namenode 获取 fsimage 和 edits 文件(采用 HTTP GET)。
3.辅助namenode 将 namenode文件载入内存,逐一执行edits文件中的操作,创建 新的fsimage文件。
4.辅助仙namenode 将新的 namenode文件发送回主namenodeG$ffl HTTPPOST)。
5.主namenode用从辅助namenode接收的fsimage文件替换旧的fsimage文件; 用步骤1所产生的edits文件替换旧的edits文件。同时,还更新fsimage文件来 记录检查点执行的时间。
最终,主namenode拥有最新的fsimage文件和一个更小的edits文件卜出以文件可 能非空,因为在这个过程中主namenode还可能收到一些写请求)。当namenode处 在安全模式时,管理员也可调用hadoop dfsadmin -saveNamespace命令来创建检 查点。
过程清晰地解释了辅助namenode和主namenode拥有相近内存需求的原因(因为辅助namenode 也把fsimage文件载入内存)。因此,在大型集群中,辅助 namenode需要运行在一台专用机器上。
图10-1.创建检査点的过程
创建检查点的触发条件受两个配置参数控制。通常情况下,.辅助namenode每隔一 小时(由fs.checkpoint.period属性设置,以秒为单位)创建检查点,此外,当 编辑日志的大小达到64MB(由fs.checkpoint.size属性设置,以字节为单位) 时,也会创建检查点。系统每隔五分钟检查一次编辑日志的大小。
辅助namenode的目录结构
创建检查点的过程不仅为主namenode创建检查点数据,还使辅助nameno.de最终也有一份检查点数据(存储在previous.checkpoint子目录中)。这份数据可用作namenode元数据的(尽管并非最新)备份:
${fs.checkpoint.dir}/current/VERSION /edits /fsimage /fstime/previous.checkpoint/VERSION /edits /fsimage /fstime
辅助 namenode 的 pr6vious.checkpoint 目录、辅助 namenode 的 current 目录和主 namenode的current目录的布局相同。这种设计方案的好处是,在主namenode发 生故障时(假设没有及时备份,甚至在NFS上也没有),可以从辅助namenode恢复 数据。一种方法是将相关存储目录复制到新的namenode中,另一种方法是使 用-importCheckpoint选项重启辅助namenode守护进程,从而将辅助namenode 用作新的主namenode。借助这个选项,dfs.name.dir属性定义的目录中没有元 数据时,辅助namenode就从fs.checkpoint.dir目录载入最新的检查点数据。 因此,无需担心该操作会覆盖现有的元数据。
datanode的目录结构
和namenode不同的是,datanode的存储目录是启动时自动创建的,不需要额外格式化。datanode的关键文件和目录如下所示:
${dfs.data.din}/cunrent/VERSION/blk_/blk_ .meta/blk_ /blk_ _meta /.../blk_ /blk_ .meta/subdir0//subdirl//.../subdir63/
datanode的VERSION文件与namenode的VERSION文件非常相似,如下所示:
#Tue Man 10 21:32:31 GMT 2009namespaceID=lB4B68441StorageID=DS-5477177B9-172.16.85.1-50010-12B6720751627cTime=0storageType=DATA_NODElayoutVersion=-18
namespaceID属性、cTime属性和layoutVersion属性的值与namenode中的值 相同。实际上,namespaceID是datanode首次访问namenode的时候从namenode 处获取的。各个datanode的storageID都不相同(但对于存储目录来说是相同 的),namenode可用这个属性来识别datanode。storageType表明这个目录是 datanode的存储目录。
datanode的current目录中的其他文件都有blk_前缀,包括两种文件类翌.:HDFS 块文件(仅包含原始数据)和块的元数据文件(含.meta后缀)。块文件包含所存储文件 的原始数据,元数据文件包括头部(含版本和类型信息)和该块各区段的一系列的校 验和。
当目录中数据块的数量增加到一定规模时,datanode会创建一个子目录来存放新的 数据块及其元数据信息„当前目录已经存储64个(通过 dfs.datanode.numblocks属性设置)数据块时,就创建一个子目录。终极目标是 设计一棵髙扇出的树,即使文件系统中的块非常多,也只需要访问少数几个目录级 别就可获取数据。通过这种方式,datanode可以有效管理各个目录中的文件,避免 大多数操作系统遇到的管理难题——即很多(成千上万个)文件放在一个目录之中。
如果dfs.data.dir属性指定了不同磁盘上的多个目录,那么数据块会以“轮 转”的方式写到各个目录中。注意,同一个datanode上的每个磁盘上 的块不会重复,不同datanode之间的块才可能重复。
安全模式
namenode启动时,首先将映像文件的(fstime)载入内存,并执行编辑日志(edits)中的 各项操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个新的fstime文件(这个操作不需要借助辅助的namenode)和一个空的编辑日志。此时, namenode开始监听RPC和HTTP请求。但是此刻,namenode运行在安全模式, 即namenode的文件系统对于客户端来说是只读的。
需要强调的是,系统中数据块的位置并不是由namenode维护的,而是以块列表的 形式存储在datanode中。在系统的正常操作期间,namenode会在内存中保留所有 块位罝的映射信息。在安全模式下,各个datanode会向namenode检査块列表信息 (即向namenode发送块列表的最新情况),namenode 了解到足够多的块位置信息之 后,即可髙效运行文件系统。但如果namenode没有检査到足够多的datanode,则 需要将块复制到其他datanode,而在大多数情况下这都是不必要的(因为只需等待 检查到若干datanode检入),并会极大地浪费集群的资源。实际上,在安全模式 下,namenode并不向datanode发出任何块复制或块删除的指令。
如果满足“最小复本条件” (minimal replication condition), namenode会在30秒钟之 后就退出安全模式。所谓的最小复本条件指的是在整个文件系统中有99.9%的块满 足最小复本级别。
在启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以 namenode不会进入安全模式。
表10-1.安全模式的属性
属性名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
dfs.replication.min | int | 1 | 成功执行写操作所需要创建的最少副本数目(也称为最小复本级别) |
dfs.safemode.threshold.pct | float | 0.999 | 在namenode退出安全模式之前,系统中满足最小复本级别(由 dfs.replication.min 定义)的块的比例。将这项值设为0 或更小会令namenode无法启动安全模式;设为高于1则永远不会退出安全模式 |
dfs.safemode.extension | int | 30000 | 在最小复本条件(由dfs.safemode.threshold.pct定义)满足之后,namenode还需要处于安全模式的时间(以毫秒为单位)。对于小型集群(十几个节点)来说,这项值可以设为0 |
进入和离开安全模式
为了查看namen0de是否处于安全模式,可以像下面这样使用dfsadmin命令:
% hadoop dfsadmin -safemode getSafe mode is ON
HDFS的网页界面也能够显示namenode是否处于安全模式。 有时用户会期望在执行某条命令之前namenode先退出安全模式,特别是在脚本 中。使用wait选项能够达到这个目的:
hadoop dfsadmin -safemode wait#command to read or write a file
管理员随时可以让namenode进入或离开安全模式。这项功能在维护和升级集群时 非常关键,因为需要确保数据在指定时段内是只读的。使用以下指令进入安全模式:
% hadoop dfsadmin -safemode enterSafe mode is ON
前面提到过,namenode在启动阶段会处于安全模式。在此期间也可使用这条命 令,从而确保namenode在启动完毕之后不离开安全模式。另一种使namenode永 远处于安全模式的方法是将属性dfs.safemode.threshold.pct的值设为大于1。
运行以下指令即可离开安全模式:
% hadoop dfsadmin -safemode leaveSafe mode is OFF
曰志审计
HDFS的日志能够记录所有文件系统访问请求,有些组织需要这项特性来进行审 计。对日志进行审计是log4j在INFO级别实现的。在默认配置下,log4j.pwperties 属性文件中的日志阈值被设为WARN,因而此项特性并未启用:
log4j.loggen.ong.apache.hadoop.hdfs.senven.namenode.FSNamesystem.audit=WARN
可以通过将WARN替换成INFO来启动日志审计特性,使每个HDFS事件均在 namenode的日志文件中生成一行日志记录。下例说明如何记录在/user/tom目录执 行的list status命令(列出指定目录下的文件/目录的状态):
2009-03-13 07:11:22,982 INFO org.apache.hadoop.hdfs.senven.namenode.FSNamesystem.audit: ugi=tom,staff,admin ip=/127.0.0.1 cmd=listStatus snc=/usen/tom dst=null penm=null
为了不与namenode的其他日志项混在一起,最好配置log4j,将审计日志写到单独 的文件中。
工具
dfsadmin 工具
dfsadmin 工具是多用途的,既可査找HDFS状态信息,又可在HDFS上执行管理操 作。调用形式是hadoop dfsadmin。仅当用户具有超级用户权限,才可以使用这 个工具修改HDFS的状态。
fsck工具
Hadoop提供fsck工具来检查HDFS中文件的健康状况。该工具会査找那些所有 datanode中均缺失的块以及过少或过多复本的块。下例演示如何检查某个小型集群 的整个文件系统:
% hadoop fsck /Status: HEALTHYTotal size: 511799225 BTotal dins : 10Total files: 22Total blocks (validated): 22 (avg. block size 23263601 B)Minimally neplicated blocks: 22 (100.0 %)Over-replicated blocks: 0 (0.0 %)Unden-neplicated blocks: 0 (0.0 %)Mis-neplicated blocks: 0 (0.0 %)Default replication factor: 3Average block replication: 3.0Corrupt blocks: 0Missing replicas: 0 (0.0 %)Number of data-nodes: 4Number of racks: 1The filesystem under path '/' is HEALTHY
fsck工具从给定路径(本例是文件系统的根目录)开始循环遍历文件系统的命名空 间,并检查它所找到的所有文件。对于检查过的每个文件,都会打印一个点 “.”。在此过程中,该工具获取文件数据块的元数据并找出问题或检查它们是否 一致。注意,fick工具只是从namenode获取信息,并不与任何datanode进行交 互,因此并不真正获取块数据。
fsck输出文件的大部分内容都容易理解,以下仅说明部分信息。
过多复制的块
指那些复本数超出最小复本级别的块。严格意义上讲,这并非一个大问题,HDFS会自动删除多余复本。
仍需复制的块
指那些复本数目低于最小复本级别的块。HDFS会自动为这些块创建新的复 本,直到达到最小复本级别。可以调用hadoop dfsadmin -metasave指令 了解正在复制的(或等待复制的)块的信息。
错误复制的块
是指那些违反块复本放置策略的块。例 如,在最小复本级别为3的多机架集群中,如果一个块的三个复本都存储在一 个机架中,则可认定该块的复本放置错误,因为一个块的复本要分散在至少两 个机架中,以提髙可靠性。
直到本书写就之际,HDFS尚无法自动修复错误复制的块,只好留待用户手动修复 这个纰漏。首先,增加包含该块的文件的最小复本级别(使用hadoop fs -setrep 命令);其次,复制这些文件直到有错误的块已被复制,最后,将文件的最小复本 级别降回到正常值。
损坏的块
指那些所有复本均已损坏的块。如果虽然部分复本损坏,但至少还有一个复本 完好,则该块就未损坏,仙0^如£^将创建新的复本,直到达到最小复本级别。
缺失的复本
是指那些在集群中没有任何复本的块。
损坏的块和丢失的块是最需要考虑的,因为这意味着数据已经丢失了。默认情况 下,fsck不会对这类块进行任何操作,但也可以让fsck执行如下某一项操作。
移动使用-move选项将受影响的文件移到HDFS的/lost+found目录。这些受 影响的文件会分裂成连续的块链表,有助于用户挽回损失。
刪除使用-delete选项删除受影响的文件。在删除之后,这些文件无法恢复。为文件寻找块fask工具能够帮助用户轻松找到属于特定文件的数据块。例如:
% hadoop fsck /user/tom/part-00007 -files -blocks -racks/user/tom/part-00007 25582428 bytes, 1 block(s): 0K0. blk_-3724870485760122836_1035 len=25582428 repl=3 [/default-rack/10.251.43.2:50010,/default-rack/10.251.27.178:50010, /default-rack/10.251.123.163:50010]
输出内容表示文件user/tom/part-00007包含一个块,该块的三个复本存储在不同 datanode。所使用的三个选项的含义如下。
-files选项显示第一行信息,包括文件名称、大小、块数量和健康状况(是否 有缺失的块)。
-blocks选项描述文件中各个块的信息,每个块一行。
-racks选项显示各个块的机架位置和datanode的地址。
如果不指定任何参数,运行Hadoop fsck命令会显示完整的使用说明。
datanode块扫描器
各个datanode运行一个块扫描器,定期检测本节点上的所有块,从而在客户端读 到坏块之前及时地检测和修复坏块。可以依靠DataBlockScanner所维护的块列 表依次扫描块,査看是否存在校验和错误。扫描器还使用节流机制,来维持 datanode的磁盘带宽(换句话说,块扫描器工作时仅占用一小部分磁盘带宽)。
默认情况下,块扫描器毎隔三周(即504小时)就会检测块,以应对可能的磁盘故 障,这个周期由dfs.datanode.scan.period.hours属性设置。损坏的块被报给 namenode,并被及时修复。
均衡器
随着时间推移,各个datanode上的块会分布得越来越不均衡。不均衡的集群会降 低MapReduce的本地性,导致部分datanode相对更为繁忙。应避免出现这种 情况。
均衡器程序是一个Hadoop守护进程,它将块从忙碌的datanode移到相对 空闲的datanode,从而重新分配块。同时坚持块复本放置策略,将复本分散到不同 机架,以降低数据损坏率。它不断移动块,直 到集群达到均衡,即每个datanode的使用率(该节点上已使用的空间与空间容量之 间的比率)和集群的使用率(集群中已使用的空间与集群的空间容量之间的比率)非 常接近,差距不超过给定的阀值。可调用下面指令启动均衡器:
% start-balancer.sh
-threshold参数指定阈值(百分比格式),以判定集群是否均衡。这个标记是可选 的,若不使用,默认阈值是10%。在任何时刻,集群中都只运行一个均衡器。
均衡器会一直运行,直到在集群变均衡;之后,均衡器无法移动任何块,或与 namenode失去联系。均衡器在标准日志目录中创建一个日志文件,记录每次重新 分配过程(每次一行)。以下是针对一个小集群的日志输出:
Time Stamp Iteration# Bytes Already Moved Bytes Left To Move Bytes Being MovedMar 18, 2009 5:23:42 PM 0 0 KB 219.21 MB 150.29 MBMar 18, 2009 5:27:14 PM 1 195.24 MB 22.45 MB 150.29 MBThe cluster is balanced. Exiting...Balancing took 6.072933333333333 minutes
为了降低集群负荷、避免干扰其他用户,均衡器被设计为在后台运行。在不同节点 之间复制数据的带宽也是受限的。默认值是很小的1MB/s,可以通过hdfs-site.xml 文件中的dfs.balance.bandwidthPerSec属性指定(单位是字节)。