HDFS
体系结构
前面我们掌握了
HDFS
的基本使用,下面我们来详细分析一下
HDFS
深层次的内容
HDFS
支 持 主 从 结 构 , 主 节 点 称 为
NameNode
, 是 因 为 主 节 点 上 运 行 的 有
NameNode
进 程 ,
NameNode
支持多个,目前我们的集群中只配置了一个
从节点称为
DataNode
,是因为从节点上面运行的有
DataNode
进程,
DataNode
支持多个,目前我们的
集群中有两个
HDFS
中还包含一个
SecondaryNameNode
进程,这个进程从字面意思上看像是第二个
NameNode
的意
思,其实不是,一会我们会详细分析。
在这大家可以这样理解:
公司
BOSS
:
NameNode
秘书:
SecondaryNameNode
员工:
DataNode
接着看一下这张图,这就是
HDFS
的体系结构,这里面的
TCP
、
RPC
、
HTTP
表示是不同的网络通信方式,
通 过 这 张 图 是 想 加 深 大 家 对
HDFS
体 系 结 构 的 理 解 , 我 们 前 面 配 置 的 集 群
NameNode
和
SecondaryNameNode
进程在同一台机器上面,在这个图里面是把它们分开到多台机器中了。
NameNode
介绍
首先是
NameNode
,
NameNode
是整个文件系统的管理节点
它主要维护着整个文件系统的文件目录树,文件
/
目录的信息 和 每个文件对应的数据块列表,并且还负责
接收用户的操作请求
(namenode所包含信息)
*文件
/
目录的信息:表示文件
/
目录的的一些基本信息,所有者 属组 修改时间 文件大小等信息
*每个文件对应的数据块列表:如果一个文件太大,那么在集群中存储的时候会对文件进行切割,这个 时候就类似于会给文件分成一块一块的,存储到不同机器上面。所以HDFS
还要记录一下一个文件到 底被分了多少块,每一块都在什么地方存储着
![](https://img-blog.csdnimg.cn/36419a8d6b20482fa021f8f4f9965f63.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAc29uZ19xdWFuXw==,size_12,color_FFFFFF,t_70,g_se,x_16)
上传hdfs显示文件块信息,文件小的时候只有一块,默认切块是128Mb。
*接收用户的操作请求:其实我们在命令行使用
hdfs
操作的时候,是需要先和
namenode
通信 才能开 始去操作数据的。
Namenode包含哪些主要文件
![](https://img-blog.csdnimg.cn/e14354081ee04453a43b7a6c1cfba631.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAc29uZ19xdWFuXw==,size_18,color_FFFFFF,t_70,g_se,x_16)
这些文件所在的路径是由
hdfs-default.xml
的
dfs.namenode.name.dir
属性控制的
hdfs-default.xml
文件在哪呢?
它在
hadoop-3.2.0\share\hadoop\hdfs\hadoop-hdfs-3.2.0.jar
中,这个文件中包含了
HDFS
相关的所有 默认参数,咱们在配置集群的时候会修改一个hdfs-site.xml
文件,
hdfs-site.xml
文件属于
hdfs
default.xml
的一个扩展,它可以覆盖掉
hdfs-default.xml
中同名的参数。
那我们来看一下这个文件中的
dfs.namenode.name.dir
属性
<property>
<name>dfs.namenode.name.dir</name>
<value>file://${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>
这个属性的值是由
hadoop.tmp.dir
属性控制的,这个属性的值默认在
core-default.xml
文件中。大家还有
没 有 印 象 , 我 们 在 修 改
core-site.xml
的 时 候 设 置 的 有
hadoop.tmp.dir
属 性 的 值 , 值
是
/data/hadoop_repo
,所以说
core-site.xml
中的
hadoop.tmp.dir
属性会覆盖掉
core-default.xml
中的值
最终
dfs.namenode.name.dir
属性的值就是:
/data/hadoop_repo/dfs/name
进入到
/data/hadoop_repo/dfs/name
目录下
发现这个下面会有一个
current
目录,表示当前的意思,还有一个
in_use.lock
这个只是一个普通文件,
但是它其实有特殊的含义,你看他的文件名后缀值
lock
表示是锁的意思,文件名是
in_use
表示这个文件
现在正在使用,不允许你再启动
namenode
。
当我们启动
namonde
的时候 会判断这个目录下是否有
in_use.lock
这个相当于一把锁,如果没有的话,
才可以启动成功,启动成功之后就会加一把锁, 停止的时候会把这个锁去掉
[root@bigdata01 name]# cd /data/hadoop_repo/dfs/name
[root@bigdata01 name]# ll
total 8
drwxr-xr-x. 2 root root 4096 Apr 8 21:31 current
-rw-r--r--. 1 root root 14 Apr 8 20:30 in_use.lock
[root@bigdata01 name]# cd current
[root@bigdata01 current]# ll
total 4152
-rw-r--r--. 1 root root 42 Apr 7 22:17 edits_0000000000000000001-000000
-rw-r--r--. 1 root root 1048576 Apr 7 22:17 edits_0000000000000000003-000000
-rw-r--r--. 1 root root 42 Apr 7 22:22 edits_0000000000000000004-000000
-rw-r--r--. 1 root root 1048576 Apr 7 22:22 edits_0000000000000000006-000000
-rw-r--r--. 1 root root 42 Apr 8 14:53 edits_0000000000000000007-000000
-rw-r--r--. 1 root root 1644 Apr 8 15:53 edits_0000000000000000009-000000
-rw-r--r--. 1 root root 1523 Apr 8 16:53 edits_0000000000000000032-000000
-rw-r--r--. 1 root root 42 Apr 8 17:53 edits_0000000000000000052-000000
-rw-r--r--. 1 root root 1048576 Apr 8 17:53 edits_0000000000000000054-000000
-rw-r--r--. 1 root root 42 Apr 8 20:31 edits_0000000000000000055-000000
-rw-r--r--. 1 root root 523 Apr 8 21:31 edits_0000000000000000057-000000
-rw-r--r--. 1 root root 1048576 Apr 8 21:31 edits_inprogress_000000000000000
-rw-r--r--. 1 root root 652 Apr 8 20:31 fsimage_0000000000000000056
-rw-r--r--. 1 root root 62 Apr 8 20:31 fsimage_0000000000000000056.md5
-rw-r--r--. 1 root root 661 Apr 8 21:31 fsimage_0000000000000000065
-rw-r--r--. 1 root root 62 Apr 8 21:31 fsimage_0000000000000000065.md5
-rw-r--r--. 1 root root 3 Apr 8 21:31 seen_txid
-rw-r--r--. 1 root root 219 Apr 8 20:30 VERSION
里面有
edits
文件 和
fsimage
文件
fsimage
文件有两个文件名相同的,有一个后缀是
md5 md5
是一种加密算法,这个其实主要是为了做
md5
校验的,为了保证文件传输的过程中不出问题,相同内容的
md5
是一样的,所以后期如果我把这个
fsimage
和对应的
fsimage.md5
发给你 然后你根据
md5
对
fsimage
的内容进行加密,获取一个值 和
fsimage.md5
中的内容进行比较,如果一样,说明你接收到的文件就是完整的。
我们在网站下载一些软件的时候 也会有一些
md5
文件,方便验证下载的文件是否完整。
在这里可以把
fsimage
拆开
fs
是文件系统
fifilesystem image
是镜像
说明是文件系统镜像,就是给文件照了一个像,把文件的当前信息记录下来
我们可以看一下这个文件,这个文件需要使用特殊的命令进行查看
-i
输入文件
-o
输出文件
[root@bigdata01 current]# hdfs oiv -p XML -i fsimage_0000000000000000056 -o f
2020-04-08 22:23:32,851 INFO offlineImageViewer.FSImageHandler: Loading 4 str
2020-04-08 22:23:32,916 INFO namenode.FSDirectory: GLOBAL serial map: bits=29
2020-04-08 22:23:32,916 INFO namenode.FSDirectory: USER serial map: bits=24 m
2020-04-08 22:23:32,916 INFO namenode.FSDirectory: GROUP serial map: bits=24
2020-04-08 22:23:32,916 INFO namenode.FSDirectory: XATTR serial map: bits=24
里面最外层是一个
fsimage
标签,看里面的
inode
标签,
这个
inode
表示是
hdfs
中的每一个目录或者文件信息
例如这个:
<inode><id>16393</id><type>FILE</type><name>LICENSE.txt</name><replication>2<
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
id
:唯一编号
type
:文件类型
replication
:文件的副本数量
mtime
:修改时间
atime
:访问时间
preferredBlockSize
:推荐每一个数据块的大小
permission
:权限信息
blocks
:包含多少数据块【文件被切成数据块】
block
:内部的
id
表示是块
id
,
genstamp
是一个唯一编号,
numBytes
表示当前数据块的实际大小,
storagePolicyId
表示是数据的存储策略
这个文件中其实就维护了整个文件系统的文件目录树,文件
/
目录的元信息和每个文件对应的数据块列
表,所以说
fsimage
中存放了
hdfs
最核心的数据。
下面我们来看一下
edits
文件,这些文件在这称之为事务文件,为什么呢?
当我们上传一个文件的时候,上传一个
10G
的文件,假设传到
9G
的时候上传失败了,这个时候就需要重
新传,那
hdfs
怎么知道这个文件失败了呢?这个是在
edits
文件中记录的。
当我们上传大文件的时候,一个大文件会分为多个
block
,那么
edits
文件中就会记录这些
block
的上传状
态,只有当全部
block
都上传成功了以后,这个时候
edits
中才会记录这个文件上传成功了,那么我们执行
hdfs dfs -ls
的时候就能查到这个文件了,
所以当我们在
hdfs
中执行
ls
命令的时候,其实会查询
fsimage
和
edits
中的内容
为什么会有这两个文件呢?
首先
,
我们固化的一些文件内容是存储在
fsimage
文件中,当前正在上传的文件信息是存储在
edits
文件
中。
这个时候我们来查看一下这个
edits
文件的内容,挑一个
edits
文件内容多一些的文件
[root@bigdata01 current]# hdfs oev -i edits_0000000000000000057-000000000000
分析生成的
edits.xml
文件,这个地方注意,可能有的
edits
文件生成的
edits.xml
为空,需要多试几个。
这个
edits.xml
中可以大致看一下,里面有很多
record
。每一个
record
代表不同的操作,
例如
OP_ADD,OP_CLOSE
等等,具体挑一个实例进行分析。
OP_ADD
:执行上传操作
OP_ALLOCATE_BLOCK_ID
:申请
block
块
id
OP_SET_GENSTAMP_V2
:设置
GENSTAMP
OP_ADD_BLOCK
:添加
block
块
OP_CLOSE
:关闭上传操作
<RECORD>
<OPCODE>OP_ADD</OPCODE>
<DATA>
<TXID>58</TXID>
<LENGTH>0</LENGTH>
<INODEID>16396</INODEID>
<PATH>/user.txt</PATH>
<REPLICATION>3</REPLICATION>
<ATIME>1586349095694</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME>DFSClient_NONMAPREDUCE_-1768454371_1</CLIENT_NAME>
<CLIENT_MACHINE>192.168.182.1</CLIENT_MACHINE>
<OVERWRITE>true</OVERWRITE>
<PERMISSION_STATUS>
<USERNAME>yehua</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
<ERASURE_CODING_POLICY_ID>0</ERASURE_CODING_POLICY_ID>
<RPC_CLIENTID>1722b83a-2dc7-4c46-baa9-9fa956b755cd</RPC_CLIENTID>
<RPC_CALLID>0</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
<DATA>
<TXID>59</TXID>
<BLOCK_ID>1073741830</BLOCK_ID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
<DATA>
<TXID>60</TXID>
<GENSTAMPV2>1006</GENSTAMPV2>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD_BLOCK</OPCODE>
<DATA>
<TXID>61</TXID>
<PATH>/user.txt</PATH>
<BLOCK>
<BLOCK_ID>1073741830</BLOCK_ID>
<NUM_BYTES>0</NUM_BYTES>
<GENSTAMP>1006</GENSTAMP>
</BLOCK>
<RPC_CLIENTID/>
<RPC_CALLID>-2</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_CLOSE</OPCODE>
<DATA>
<TXID>62</TXID>
<LENGTH>0</LENGTH>
<INODEID>0</INODEID>
<PATH>/user.txt</PATH>
<REPLICATION>3</REPLICATION>
<MTIME>1586349096480</MTIME>
<ATIME>1586349095694</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME/>
<CLIENT_MACHINE/>
<OVERWRITE>false</OVERWRITE>
<BLOCK>
<BLOCK_ID>1073741830</BLOCK_ID>
<NUM_BYTES>17</NUM_BYTES>
<GENSTAMP>1006</GENSTAMP>
</BLOCK>
<PERMISSION_STATUS>
<MODE>420</MODE>
</PERMISSION_STATUS>
</DATA>
</RECORD>
这里面的每一个
record
都有一个事务
id
,
txid
,事务
id
是连续的,其实一个
put
操作会在
edits
文件中产生
很多的
record
,对应的就是很多步骤,这些步骤对我们是屏蔽的。
注意了,根据我们刚才的分析,我们所有对
hdfs
的增删改操作都会在
edits
文件中留下信息,那么
fsimage
文件中的内容是从哪来的?
其实是这样的,
edits
文件会定期合并到
fsimage
文件中。
有同学可能有疑问了,
edits
文件和
fsimage
文件中的内容是不一样的,这怎么能是合并出来的呢?
注意,这个其实是框架去做的,在合并的时候会对
edits
中的内容进行转换,生成新的内容,其实
edits
中保存的内容是不是太细了,单单一个上传操作就分为了好几步,其实上传成功之后,我们
只需要保存文件具体存储的
block
信息就行了把,所以在合并的时候其实是对
edits
中的内容进行了
精简。
他们具体合并的代码我们不用太过关注,但是我们要知道是那个进程去做的这个事情,
其实就是我们之前提到的
secondarynamenode
这个进程就是负责定期的把
edits
中的内容合并到
fsimage
中。他只做一件事,这是一个单独的进程,在实
际工作中部署的时候,也需要部署到一个单独的节点上面。
current
目录中还有一个
seen_txid
文件,
HDFS format
之后是
0
,它代表的是
namenode
里面的
edits_*
文
件的尾数
,namenode
重启的时候,会按照
seen_txid
的数字,顺序从头跑
edits_0000001~
到
seen_txid
的
数字。如果根据对应的
seen_txid
无法加载到对应的文件,
NameNode
进程将不会完成启动以保护数据一 致性。
[root@bigdata01 current]# cat seen_txid
66
最后这个
current
目录下面还有一个
VERSION
文件
[root@bigdata01 current]# cat VERSION
#Wed Apr 08 20:30:00 CST 2020
namespaceID=498554338
clusterID=CID-cc0792dd-a861-4a3f-9151-b0695e4c7e70
cTime=1586268855170
storageType=NAME_NODE
blockpoolID=BP-1517789416-192.168.182.100-1586268855170
layoutVersion=-65
这里面显示的集群的一些信息、当重新对
hdfs
格式化 之后,这里面的信息会变化。
之前我们说过 在使用
hdfs
的时候只格式化一次,不要格式化多次,为什么呢?
一会在讲
datanode
的时候会详细解释、
最后做一个总结:
fsimage:
元数据镜像文件,存储某一时刻
NameNode
内存中的元数据信息,就类似是定时做了一个快照
操作。【这里的元数据信息是指文件目录树、文件
/
目录的信息、每个文件对应的数据块列表】
edits:
操作日志文件【事务文件】,这里面会实时记录用户的所有操作
seen_txid:
是存放
transactionId
的文件,
format
之后是
0
,它代表的是
namenode
里面的
edits_*
文件的
尾数
,namenode
重启的时候,会按照
seen_txid
的数字,顺序从头跑
edits_0000001~
到
seen_txid
的数
字。如果根据对应的
seen_txid
无法加载到对应的文件,
NameNode
进程将不会完成启动以保护数据一致
性。
VERSION:
保存了集群的版本信息