HDFS体系结构

1 分布式文件系统(Distributed File System)

  • 数据量越来越多,在一个操作系统管辖的范围存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,因此迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统
  • 是一种允许文件通过网络在多台主机上分享的文件系统,可让多机器上的多用户分享文件和存储空间
  • 通透性。让实际上是通过网络来访问文件的动作,由程序与用户看来,就像是访问本地的磁盘一般
  • 容错。即使系统中有某些节点脱机,整体来说系统仍然可以持续运作而不会有数据损失
  • 分布式文件管理系统很多,hdfs只是其中一种。适用于一次写入多次查询的情况,不支持并发写情况,小文件不合适

    2 HDFS 结构

    HDFS:Hadoop Distributed File System(Hadoop 分布式文件系统)
  • 主从结构
    • 主节点:只有一个(namenode
    • 从节点:有很多个(datanodes

注意:主节点和从节点都是不同的物理机器

  • namenode 负责:

    • 接收用户操作请求
    • 维护文件系统的目录结构
    • 管理文件与 block 之间关系,block 与 datanode 之间关系
  • datanode 负责:

    • 存储文件
    • 文件被分成 block 存储在磁盘上
    • 为保证数据安全,文件会有多个副本

3 Namenode 结构

  • Namenode:是整个文件系统的管理节点。它维护着整个文件系统的文件目录树,文件/目录的元信息和每个文件对应的数据块列表。接收用户的操作请求
  • 文件包括:
    • fsimage:元数据镜像文件。存储某一时段NameNode内存元数据信息
    • edits:操作日志文件
    • fstime:保存最近一次checkpoint的时间

在 eclipse 中打开 Project 下**src/hdfs/hdfs-default.xml**
首先发现注释:

1
2
3
<!-- Do not modify this file directly.  Instead, copy entries that you -->
<!-- wish to modify from this file into hdfs-site.xml and change them -->
<!-- there. If hdfs-site.xml does not already exist, create it. -->

大概是说,不要在这个文件中修改代码,要先将想修改的代码 copy 到 hdfs-site.xml这个文件中,然后在那里面修改。如果没有hdfs-site.xml这个文件,就创建一个。

3.1 fsimage

hdfs-default.xml文件中查找“dfs.name.dir”,发现一段代码如下(大概在第 148 行):

1
2
3
4
5
6
7
8
<property>
<name>dfs.name.dir</name>
<value>${hadoop.tmp.dir}/dfs/name</value>
<description>Determines where on the local filesystem the DFS name node
should store the name table(fsimage). If this is a comma-delimited list
of directories then the name table is replicated in all of the
directories, for redundancy. </description>
</property>

由 description 可以得知,这段代码是决定 name node 的 name table(fsimage) 也就是文件系统的镜像,在本地文件系统的存储位置
然后发现 value 中有个变量是${hadoop.tmp.dir},在文件hdfs-default.xml中查找,发现没有,然后到文件core-default.xml中查找,发现如下代码(大概在第 13 行):

1
2
3
4
5
<property>
<name>hadoop.tmp.dir</name>
<value>/tmp/hadoop-${user.name}</value>
<description>A base for other temporary directories.</description>
</property>

由 description 可以得知,这是临时目录的基本位置,所以这个值应该会替换上一段代码中的${hadoop.tmp.dir}的值,然而并不是。。。因为我们已经在core-site.xml中修改了hadoop.tmp.dir的值 =_=:

1
2
3
4
5
6
7
8
9
10
11
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://hadoop0:9000</value>
<description>change your own hostname</description>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/usr/local/hadoop/tmp</value>
</property>
</configuration>

所以其实文件hdfs-default.xmldfs.name.dir中的${hadoop.tmp.dir}实际上是/usr/local/hadoop/tmp
于是我们去命令行打开/usr/local/hadoop/tmp/dfs/name(也就是dfs.name.dir的位置)去看一下:

1
2
3
4
5
6
7
8
9
[root@hadoop ~]# cd /usr/local/hadoop/tmp/
[root@hadoop tmp]# ls
dfs mapred
[root@hadoop tmp]# cd dfs/
[root@hadoop dfs]# ls
data name namesecondary
[root@hadoop dfs]# cd name
[root@hadoop name]# ls
current image in_use.lock previous.checkpoint

然后本着好奇心,去看一下in_use.lock这个文件:

1
[root@hadoop name]# more in_use.lock

然后发现里面啥也没有。。。
不过虽然啥也没有,也是很重要的,这个文件的存在就表明这个目录已经被某个进程(Namenode 进程)使用了,所以其实如果直接再启动 Namenode 进程会报错,因为这个目录已经进不来了
那么为什么 Namenode 一定要占用这个目录呢?因为目录下的/current文件夹下存放着 Namenode 存储数据的文件,也就是 Namenode 会编辑这些数据,所以显然不能有多个进程同时编辑这些数据

1
2
3
[root@hadoop name]# cd current/
[root@hadoop current]# ls
edits fsimage fstime VERSION

看到了刚刚说的fsimage,Namenode 的核心数据都存放在这个文件里,所以这个文件比较重要,如果这个文件丢了,这个 Namenode 就不能用了(Datanode 中存放的都是块数据,没有 Namenode 无法读取)
所以会将fsimage备份 :)

再看文件hdfs-default.xmldfs.name.dir的 description(大概在第 148 行):

1
2
3
4
5
6
7
8
<property>
<name>dfs.name.dir</name>
<value>${hadoop.tmp.dir}/dfs/name</value>
<description>Determines where on the local filesystem the DFS name node
should store the name table(fsimage). If this is a comma-delimited list
of directories then the name table is replicated in all of the
directories, for redundancy. </description>
</property>

刚刚只看了 description 的前一句,现在看后一句,大概说的是:如果 value 是一个逗号分隔的目录列表,那么复制进所有的目录中,为了冗余。冗余就是备份,备份为了安全,nice~
注意:如果要改的话,记得复制到hdfs-site.xml中去改,不要用中文逗号,不要随便加空格

3.2 edits

然后我们刚刚在/current目录下还看到了edits文件,所以我们继续本着好奇心,去文件hdfs-default.xml中查找一下,发现如下一段代码(大概在第 157 行):

1
2
3
4
5
6
7
8
9
<property>
<name>dfs.name.edits.dir</name>
<value>${dfs.name.dir}</value>
<description>Determines where on the local filesystem the DFS name node
should store the transaction (edits) file. If this is a comma-delimited list
of directories then the transaction file is replicated in all of the
directories, for redundancy. Default value is same as dfs.name.dir
</description>
</property>

description 中大概说的是:这决定了 Namenode 的事务文件(edits)的存放位置(参见本文第 4 节)

4 SecondaryNameNode

执行过程:从 NameNode 上下载元数据信息(fsimage, edits),然后把二者合并,生成新的 fsimage,在本地保存,并将其推送到 NameNode,同时重置 NameNode 的 edits

注意:SecondaryNameNode 和 Namenode 是两个独立的 Java 进程,它们之间的数据交换是通过网络 HTTP 完成的

所以其实 Namenode 的 fsimage 在 SecondaryNameNode 中也有备份,所以可以从 SecondaryNameNode 中恢复数据,但是有可能会丢失一部分(没来得及从 edits 合并的)(类似于 Windows 下的“还原点”)

5 Datanode

  • 提供真实文件数据的存储服务
  • 文件块(block)最基本的存储单位。对于文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block。HDFS默认Block大小是64MB,以一个256MB文件,共有256/64=4个Block(一个文件的不同 block 不一定存放在一个 Datanode 上)
  • 不同于普通文件系统的是,HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间,而是占用源文件实际大小的空间
  • Replication:多副本,默认是三个

5.1 block

在文件hdfs-default.xml中查找“size”,发现如下一段代码(大概在第 157 行):

1
2
3
4
5
<property>
<name>dfs.block.size</name>
<value>67108864</value>
<description>The default block size for new files.</description>
</property>

67108864 的单位是 byte(字节)
67108864/1024/1024 = 64
所以,67108864 byte = 64 M

在文件hdfs-default.xml中查找“data.dir”,发现如下一段代码(大概在第 157 行):

1
2
3
4
5
6
7
8
9
10
<property>
<name>dfs.data.dir</name>
<value>${hadoop.tmp.dir}/dfs/data</value>
<description>Determines where on the local filesystem an DFS data node
should store its blocks. If this is a comma-delimited
list of directories, then data will be stored in all named
directories, typically on different devices.
Directories that do not exist are ignored.
</description>
</property>

description 中大概说的是:这是 Datanode 存放 block 的位置
在命令行中看一下:

1
2
3
4
5
6
7
8
9
[root@hadoop dfs]# ls
data name namesecondary
[root@hadoop dfs]# cd data/
[root@hadoop data]# ls
blocksBeingWritten current detach in_use.lock storage tmp
[root@hadoop data]# cd current/
[root@hadoop current]# ls
blk_-3705260109245499939 dncp_block_verification.log.curr
blk_-3705260109245499939_1005.meta VERSION

这就是存储的 block,查看一下:

1
2
3
4
5
6
[root@hadoop current]# ll
total 16
-rw-r--r--. 1 root root 4 Nov 20 01:36 blk_-3705260109245499939
-rw-r--r--. 1 root root 11 Nov 20 01:36 blk_-3705260109245499939_1005.meta
-rw-r--r--. 1 root root 289 Nov 21 05:48 dncp_block_verification.log.curr
-rw-r--r--. 1 root root 158 Nov 20 01:35 VERSION

现在有一个 block,.meta表示校验数据
现在上传个文件看看:
再打开一个 PieTTY 终端(为了叙述方便,原来的终端叫做“终端 1”,刚刚打开的叫做“终端 2”),上传文件hadoop-1.1.2.tar.gz到根目录:
终端 2:

1
2
3
4
5
6
7
8
[root@hadoop ~]# cd /usr/local/
[root@hadoop local]# ll
total 143428
drwxr-xr-x. 17 root root 4096 Nov 19 04:48 hadoop
-rw-r--r--. 1 root root 61927560 Nov 19 01:20 hadoop-1.1.2.tar.gz
drwxr-xr-x. 10 root root 4096 Nov 19 01:33 jdk
-rwxr--r--. 1 root root 84927175 Nov 19 01:20 jdk-6u24-linux-i586.bin
[root@hadoop local]# hadoop fs -put hadoop-1.1.2.tar.gz /

再次在终端 1 中查看:

1
2
3
4
5
6
7
8
[root@hadoop current]# ll
total 60972
-rw-r--r--. 1 root root 61927560 Nov 23 03:59 blk_1328932562550095235
-rw-r--r--. 1 root root 483819 Nov 23 03:59 blk_1328932562550095235_1007.meta
-rw-r--r--. 1 root root 4 Nov 20 01:36 blk_-3705260109245499939
-rw-r--r--. 1 root root 11 Nov 20 01:36 blk_-3705260109245499939_1005.meta
-rw-r--r--. 1 root root 385 Nov 23 04:02 dncp_block_verification.log.curr
-rw-r--r--. 1 root root 158 Nov 20 01:35 VERSION

再将它删了,将文件jdk-6u24-linux-i586.bin上传到根目录:
终端 2:

1
2
3
[root@hadoop local]# hadoop fs -rmr /hadoop-*
Deleted hdfs://hadoop:9000/hadoop-1.1.2.tar.gz
[root@hadoop local]# hadoop fs -put jdk-6u24-linux-i586.bin /

在终端 1 中查看:

1
2
3
4
5
6
7
8
9
10
[root@hadoop current]# ll
total 83608
-rw-r--r--. 1 root root 17818311 Nov 23 04:10 blk_2854622546434446315
-rw-r--r--. 1 root root 139215 Nov 23 04:10 blk_2854622546434446315_1008.meta
-rw-r--r--. 1 root root 4 Nov 20 01:36 blk_-3705260109245499939
-rw-r--r--. 1 root root 11 Nov 20 01:36 blk_-3705260109245499939_1005.meta
-rw-r--r--. 1 root root 67108864 Nov 23 04:10 blk_-7192035640884367901
-rw-r--r--. 1 root root 524295 Nov 23 04:10 blk_-7192035640884367901_1008.meta
-rw-r--r--. 1 root root 385 Nov 23 04:02 dncp_block_verification.log.curr
-rw-r--r--. 1 root root 158 Nov 20 01:35 VERSION

发现上传文件hadoop-1.1.2.tar.gz所产生的数据块没有了,上传文件jdk-6u24-linux-i586.bin产生了 2 个数据块(因为文件jdk-6u24-linux-i586.bin大于 64 M)

5.2 replication

Hadoop 默认副本为 3 个,但是用hadoop fs -ls命令查看的时候,发现副本数为 1。这是因为我们已经在文件hdfs-site.xml中修改配置:

1
2
3
4
<property>
<name>dfs.replication</name>
<value>1</value>
</property>

那么为什么要改成 1 呢?因为我配置的是伪分布式环境,只有一个 Datanode。。。

6 使用浏览器查看 HDFS 目录结构

可以在浏览器中访问主机名:50070来查看 HDFS 的目录结构