HDFS源码分析(3):datanode存储

March 15, 2012 / datanode, Hadoop, HDFS, source, storage

前提

Hadoop版本:hadoop-0.20.2

概述

datanode的存储结构如下所示:

 ${dfs.data.dir}/current/VERSION
                        /blk_<id_1>
                        /blk_<id_1>.meta
                        /blk_<id_1>
                        /blk_<id_1>.meta
                        /...
                        /blk_<id_64>
                        /blk_<id_64>.meta
                        /subdir0/
                        /subdir1/
                        /...
                        /subdir63/
                /previous/
                /detach/
                /tmp/
                /in_use.lock
                /storage

datanode的存储大体上可以分为两部分:与Storage相关的类从宏观上刻画了每个存储目录的组织结构,管理由HDFS属性dfs.data.dir指定的目录,如current、previous、detach、tmp、storage等目录和文件,并定义了对整个存储的相关操作;与Dataset相关的类描述了块文件及其元数据文件的组织方式,如current目录中的文件组织结构,以及对块文件的相关操作。因为namenode也会用到Storage,而namenode并不存储块文件,因而将存储分成这两部分。

本文中将简单分析这两部分内容,所涉及到的类的包结构如下所示:

Storage

与Storage相关的类描述了存储的信息、类型、状态、目录,类图如下所示:

存储的信息由类StorageInfo来表示,该类有3个属性:

Storage类管理着所有的存储目录,存储目录由StorageDirectory类来表示,通过DirIterator这个类来遍历存储目录,主要有两个属性:

StorageDirectory是一个重要的类,描述了存储目录的组织结构及其状态,首先,我们来看看存储目录的状态。

StorageState表示存储的状态,与存储目录的结构、升级、回滚、做checkpoint息息相关,存储目录的所有状态如下:

存储目录的结构如下所示:

VERSION文件的例子如下所示:

#Tue Mar 13 17:22:19 CST 2012
namespaceID=1845340702
storageID=DS-641781551-*.*.*.*-50010-1330961440921
cTime=0
storageType=DATA_NODE
layoutVersion=-19

StorageDirectory与状态和目录结构相关的方法是doRecover,用于恢复系统状态,根据系统当前的状态,完成的操作如下:

StorageDirectory还有一个重要的方法是analyzeStorage,用于在启动namenode或datanode时检查存储目录的一致性,并返回系统当前的状态

DataStorage是与datanode相关的存储类,定义了几种文件的前缀和datanode的几个操作,linkBlocks方法用于创建硬链接,recoverTransitionRead方法用于将系统恢复到正常状态,在有必要时升级系统。

3种文件前缀:

4种操作:

Dataset

与块相关的操作由Dataset相关的类处理,存储结构由大到小是卷(FSVolume)、目录(FSDir)和文件(Block和元数据等),类图如下所示:

Block是datanode的基本数据结构,表示一个数据块的信息,每个Block都有1个数据文件和1个元数据文件。与Block相关的类有DatanodeBlockInfo,该类有3个属性:volume是块所属的卷;file是块对应的数据文件;detached表示块是否完成copy-on-write。DatanodeBlockInfo有一个重要方法detachFile用于分离文件,先将指定文件拷贝到临时目录,再将临时文件替换原来的文件,这样使得所有到原文件的硬链接被删除。

FSDir用来表示文件的组织结构,默认情况下,每个目录下最多有64个子目录,最多能存储64个块。在初始化一个目录时,会递归扫描该目录下的目录和文件,从而形成一个树状结构。addBlock方法用来添加块到当前目录,如果当前目录不能容纳更多的块,那么将块添加到一个子目录中,如果没有子目录,则创建子目录。getBlockInfo和getVolumeMap方法用于递归扫描当前目录下所有块的信息。clearPath方法用于删除文件时,更新文件路径中所有目录的信息。

FSVolume用来管理块文件,统计存储目录的使用情况,有如下6个属性:

FSVolume在初始化时会恢复detach和tmp目录中的文件,如果detach或tmp不存在,则创建目录。createTmpFile方法用于创建临时文件。createDetachFile方法创建用于copy-on-write的文件。addBlock方法用于在当前卷中添加块。

FSVolumeSet类封装了多个FSVolume,提供获得所有容量、剩余空间、dfs使用空间和块信息的方法。getNextVolume方法采用round-robin策略选择下一个FSVolume,达到负载均衡的效果,将IO负载分到多个磁盘上,提高IO处理能力。

FSDataset类封装了FSVolumeSet,实现FSDatasetInterface接口,向外提供获得DFS使用情况及操作块的方法。

FSDatasetInterface接口应实现的方法如下:

FSDataset有以下几个主要属性:

FSDataset在创建输出流或位于特定位置的输入流时,使用RandomAccessFile,这样可以随机寻址,可以得到或设置流的位置。当完成块的写操作时,将块添加到volumeMap,并从ongoingCreates中删除。比较复杂的方法是writeToBlock,其处理过程如下所示:

后记

文中若有错误或疏漏之处,烦请批评指正。