大数据HDFS体系结构


1 HDFS 概述

1.1 HDFS 产出背景及定义

1)HDFS 产生背景

随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS 只是分布式文件管理系统中的一种。

2)HDFS 定义
HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS 的使用场景:适合一次写入,多次读出的场景。一个文件经过创建、写入和关闭
之后就不需要改变。
我们前面已经知道了HDFS是一个分布式的文件系统,具体这个分布式文件系统是如何实现的呢?

我们来举个例子分析一下。

小明租房:

小明同学呢,今年是大四,需要离校去实习了,出去实习首要解决的是住宿的问题,目前软件行业很少包住宿的,反正我是没听说过,但是小明呢,有一个特点,就是懒,还穷,天天出去住酒店肯定是住不起的,那只能租房了,租房呢他还不想自己去找房子,嫌麻烦,所以就随便在路边找了一个二房东贴的广告,单间出租,拎包入住,无中介费,押一付一,一月300,小明一看,可以,还不错,所以就直接打电话过去看房子办手续了,这样就解决了住宿的问题。

紧接着小明的同学看他这么快就搞定了住宿问题,房租也挺便宜,都问他要二房东的电话,小明就把二房东的电话发到了他们的年级群里,上千人啊,结果二房东的手机就被打爆了,最后只能关机了,人太多了,实在搞不定了。

因为目前有租房需求的学员太多了,全部都去找这一个二房东,他是搞不定的,因为他每天带看的人数是有限的。

那这个时候怎么办呢?

小明同学还是比较热心的,发现二房东解决不了这么大的需求,然后他正发愁呢,结果一抬头看到了一个中介公司,小明露出了满嘴的大白牙。

然后他就顺利搞到了这个中介公司的电话,赶紧把这个电话发到了年级群里面,这个时候,当再有学员有租房需求的时候,直接打中介公司的电话,然后中介公司会让具体的工作人员直接联系这个学员,负责他的租房需求,每一个工作人员最多负责5个人,因为中介公司里面是有很多工作人员的,这样一分流,就很轻松的解决了这个问题。

这个时候针对中介公司而言,它只负责管理房源和工作人员就行了,具体干活的是工作人员。

这样就算同时过来很多人,中介公司也是可以扛得住的,因为具体看房租房的流程是直接和工作人员对接的,不会造成阻塞。

ok 这就是小明租房的一个案例,那这个案例和我们要讲的HDFS有什么关系呢?

不要着急,我们来往下面看。

假设让我们来设计一个分布式的文件系统,我们该如何设计呢?

Hadoop

这里的客户端可以理解为安装HDFS的机器,或者连接操作这台机器API

看这个图片,用户在写入数据和读取数据的时候会通过一个文件系统,这个文件系统后面会有很多台服务器,所以我们的数据就可以存储在多台服务器上面。后期服务器增加或者减少,对我们用户而言,不用关注,这个统一由文件系统进行管理,我们只需要和文件系统进行交互就可以了。

这样是不是就实现了分布式存储了,这种方案在实际应用中可行吗?

在这里就可以把文件系统理解为二房东,服务器理解为房子,这种设计架构会存在一个问题,假设同时过来很多人都需要租房子,那么一个二房东是忙不过来的,就会造成阻塞。

那继续往下面看

Hadoop

现在这种设计是,我们去找一个中介公司,这里的主节点就可以理解为一个中介公司

这里的从节点就可以理解为是房源,中介公司会在每块房源都安排一个工作人员,当我们找房子的时候,先联系中介公司,中介公司会告诉我们哪里有房子,并且把对应工作人员的信息告诉我们,我们就可以直接去找对应的工作人员去租房子。这样对于中介公司而言,就没什么压力了。

中介公司只负责管理房源和工作人员信息,具体干活的是工作人员。相当于nn

这样就算同时过来很多人,中介公司也是可以扛得住的,因为具体看房租房的流程是我们直接和工作人员联系的,不会造成阻塞。

所以对应到我们的分布式存储设计上面:

用户请求查看数据时候会请求主节点,主节点上面会维护所有数据的存储信息,

主节点会把对应数据所在的节点信息返回给用户,

然后用户根据数据所在的节点信息去对应的节点去读取数据,这样压力就不会全部在主节点上面。

这个就是HDFS这个分布式文件系统的设计思想。

1.2 HDFS 优缺点

HDFS的全称是Hadoop Distributed File System ,Hadoop的 分布式 文件 系统

它是一种允许文件通过网络在多台主机上分享的文件系统,可以让多台机器上的多个用户分享文件和存储空间

其实分布式文件管理系统有很多,HDFS只是其中一种实现而已

还有 GFS(谷歌的)、TFS(淘宝的)、S3(亚马逊的)

为什么会有多种分布式文件系统呢?这样不是重复造轮子吗?

不是的,因为不同的分布式文件系统的特点是不一样的,HDFS是一种适合大文件存储的分布式文件系统,不适合小文件存储,什么叫小文件,例如,几KB,几M的文件都可以认为是小文件

在这里插入图片描述
在这里插入图片描述

1.3 新框架的学习方法

在这里插入图片描述

2 HDFS体系结构

前面我们掌握了HDFS的基本使用,下面我们来详细分析一下HDFS深层次的内容

HDFS支持主从结构,主节点称为 NameNode ,是因为主节点上运行的有NameNode进程,NameNode支持多个,目前我们的集群中只配置了一个

从节点称为 DataNode ,是因为从节点上面运行的有DataNode进程,DataNode支持多个,目前我们的集群中有两个

HDFS中还包含一个 SecondaryNameNode 进程,这个进程从字面意思上看像是第二个NameNode的意思,其实不是,一会我们会详细分析。

在这大家可以这样理解:

公司BOSS:NameNode

秘书:SecondaryNameNode

员工:DataNode

接着看一下这张图,这就是HDFS的体系结构,这里面的TCP、RPC、HTTP表示是不同的网络通信方式,通过这张图是想加深大家对HDFS体系结构的理解,我们前面配置的集群NameNode和SecondaryNameNode进程在同一台机器上面,在这个图里面是把它们分开到多台机器中了。

在这里插入图片描述
那接下来我们就详细分析这里面的每一个进程。

官方描述:HDFS has a master/slave architecture. An HDFS cluster consists of a single NameNode, a master server that manages the file system namespace and regulates access to files by clients. In addition, there are a number of DataNodes, usually one per node in the cluster, which manage storage attached to the nodes that they run on. HDFS exposes a file system namespace and allows user data to be stored in files. Internally, a file is split into one or more blocks and these blocks are stored in a set of DataNodes. The NameNode executes file system namespace operations like opening, closing, and renaming files and directories. It also determines the mapping of blocks to DataNodes. The DataNodes are responsible for serving read and write requests from the file system’s clients. The DataNodes also perform block creation, deletion, and replication upon instruction from the NameNode.

翻译:
HDFS具有主/从体系结构。HDFS集群由一个NameNode组成,它是一个主服务器,管理文件系统名称空间并管理客户端对文件的访问。此外,还有许多数据节点,通常是群集中每个节点一个,用于管理连接到它们运行的节点的存储。HDFS公开了一个文件系统名称空间,并允许用户数据存储在文件中。在内部,文件被分割成一个或多个块,这些块存储在一组数据节点中。NameNode执行文件系统名称空间操作,如打开、关闭和重命名文件和目录。它还确定块到数据节点的映射。DataNodes负责为来自文件系统客户端的读写请求提供服务。DataNodes还根据NameNode的指令执行块创建、删除和复制

在这里插入图片描述

在这里插入图片描述

2.1 NameNode介绍

首先是NameNode,NameNode是整个文件系统的管理节点,它主要维护着整个文件系统的文件目录树,文件/目录的信息 和 每个文件对应的数据块列表,并且还负责接收用户的操作请求

在这里插入图片描述

  • 目录树:表示目录之间的层级关系,就是我们在hdfs上执行ls命令可以看到的那个目录结构信息。
  • 文件/目录的信息:表示文件/目录的的一些基本信息,所有者 属组 修改时间 文件大小等信息
  • 每个文件对应的数据块列表:如果一个文件太大,那么在集群中存储的时候会对文件进行切割,这个时候就类似于会给文件分成一块一块的,存储到不同机器上面。所以HDFS还要记录一下一个文件到底被分了多少块,每一块都在什么地方存储着

我们现在可以到集群的9870界面查看一下,随便找一个文件看一下,点击文件名称,可以看到Block information 但是文件太小,只有一个块 叫Block 0

Hadoop

我们试着上传一个大一点的文件,找一个200M左右的文件。

[root@bigdata01 hadoop-3.2.0]# cd /data/soft/
[root@bigdata01 soft]# hdfs dfs -put hadoop-3.2.0.tar.gz  /

这个时候再去看 就能看到分成了多个Block块,一个文件对应有多少个Block块信息 是在namenode里面保存着的

Hadoop

  • 接收用户的操作请求:其实我们在命令行使用hdfs操作的时候,是需要先和namenode通信 才能开始去操作数据的。

为什么呢?

因为文件信息都在namenode上面存储着的

namenode是非常重要的,它的这些信息最终是会存储到文件上的,那接下来我们来看一下NameNode中包含的那些文件

NameNode主要包括以下文件:
Hadoop

在这里插入图片描述

在这里插入图片描述

这些文件所在的路径是由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

那我们到bigdata01节点上看一下

进入到/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-0000000000000000002
-rw-r--r--. 1 root root 1048576 Apr  7 22:17 edits_0000000000000000003-0000000000000000003
-rw-r--r--. 1 root root      42 Apr  7 22:22 edits_0000000000000000004-0000000000000000005
-rw-r--r--. 1 root root 1048576 Apr  7 22:22 edits_0000000000000000006-0000000000000000006
-rw-r--r--. 1 root root      42 Apr  8 14:53 edits_0000000000000000007-0000000000000000008
-rw-r--r--. 1 root root    1644 Apr  8 15:53 edits_0000000000000000009-0000000000000000031
-rw-r--r--. 1 root root    1523 Apr  8 16:53 edits_0000000000000000032-0000000000000000051
-rw-r--r--. 1 root root      42 Apr  8 17:53 edits_0000000000000000052-0000000000000000053
-rw-r--r--. 1 root root 1048576 Apr  8 17:53 edits_0000000000000000054-0000000000000000054
-rw-r--r--. 1 root root      42 Apr  8 20:31 edits_0000000000000000055-0000000000000000056
-rw-r--r--. 1 root root     523 Apr  8 21:31 edits_0000000000000000057-0000000000000000065
-rw-r--r--. 1 root root 1048576 Apr  8 21:31 edits_inprogress_0000000000000000066
-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 是文件系统 filesystem image是镜像

说明是文件系统镜像,就是给文件照了一个像,把文件的当前信息记录下来

我们可以看一下这个文件,这个文件需要使用特殊的命令进行查看

-i 输入文件 -o 输出文件

[root@bigdata01 current]# hdfs oiv -p XML -i fsimage_0000000000000000056 -o fsimage56.xml
2020-04-08 22:23:32,851 INFO offlineImageViewer.FSImageHandler: Loading 4 strings
2020-04-08 22:23:32,916 INFO namenode.FSDirectory: GLOBAL serial map: bits=29 maxEntries=536870911
2020-04-08 22:23:32,916 INFO namenode.FSDirectory: USER serial map: bits=24 maxEntries=16777215
2020-04-08 22:23:32,916 INFO namenode.FSDirectory: GROUP serial map: bits=24 maxEntries=16777215
2020-04-08 22:23:32,916 INFO namenode.FSDirectory: XATTR serial map: bits=24 maxEntries=16777215

把fsimage56.xml这个文件拉取到window上,查看比较方便

<?xml version="1.0"?>
<fsimage><version><layoutVersion>-65</layoutVersion><onDiskVersion>1</onDiskVersion><oivRevision>e97acb3bd8f3befd27418996fa5d4b50bf2e17bf</oivRevision></version>
<NameSection><namespaceId>498554338</namespaceId><genstampV1>1000</genstampV1><genstampV2>1005</genstampV2><genstampV1Limit>0</genstampV1Limit><lastAllocatedBlockId>1073741829</lastAllocatedBlockId><txid>56</txid></NameSection>
<ErasureCodingSection>
<erasureCodingPolicy>
<policyId>5</policyId><policyName>RS-10-4-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
<codecName>rs</codecName><dataUnits>10</dataUnits><parityUnits>4</parityUnits></ecSchema>
</erasureCodingPolicy>

<erasureCodingPolicy>
<policyId>2</policyId><policyName>RS-3-2-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
<codecName>rs</codecName><dataUnits>3</dataUnits><parityUnits>2</parityUnits></ecSchema>
</erasureCodingPolicy>

<erasureCodingPolicy>
<policyId>1</policyId><policyName>RS-6-3-1024k</policyName><cellSize>1048576</cellSize><policyState>ENABLED</policyState><ecSchema>
<codecName>rs</codecName><dataUnits>6</dataUnits><parityUnits>3</parityUnits></ecSchema>
</erasureCodingPolicy>

<erasureCodingPolicy>
<policyId>3</policyId><policyName>RS-LEGACY-6-3-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
<codecName>rs-legacy</codecName><dataUnits>6</dataUnits><parityUnits>3</parityUnits></ecSchema>
</erasureCodingPolicy>

<erasureCodingPolicy>
<policyId>4</policyId><policyName>XOR-2-1-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
<codecName>xor</codecName><dataUnits>2</dataUnits><parityUnits>1</parityUnits></ecSchema>
</erasureCodingPolicy>

</ErasureCodingSection>

<INodeSection><lastInodeId>16395</lastInodeId><numInodes>4</numInodes><inode><id>16385</id><type>DIRECTORY</type><name></name><mtime>1586332531935</mtime><permission>root:supergroup:0755</permission><nsquota>9223372036854775807</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16393</id><type>FILE</type><name>LICENSE.txt</name><replication>2</replication><mtime>1586332513657</mtime><atime>1586332513485</atime><preferredBlockSize>134217728</preferredBlockSize><permission>root:supergroup:0644</permission><blocks><block><id>1073741827</id><genstamp>1003</genstamp><numBytes>150569</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16394</id><type>FILE</type><name>NOTICE.txt</name><replication>2</replication><mtime>1586332522962</mtime><atime>1586332522814</atime><preferredBlockSize>134217728</preferredBlockSize><permission>root:supergroup:0644</permission><blocks><block><id>1073741828</id><genstamp>1004</genstamp><numBytes>22125</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16395</id><type>FILE</type><name>README.txt</name><replication>2</replication><mtime>1586332531932</mtime><atime>1586332531689</atime><preferredBlockSize>134217728</preferredBlockSize><permission>root:supergroup:0644</permission><blocks><block><id>1073741829</id><genstamp>1005</genstamp><numBytes>1361</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
</INodeSection>
<INodeReferenceSection></INodeReferenceSection><SnapshotSection><snapshotCounter>0</snapshotCounter><numSnapshots>0</numSnapshots></SnapshotSection>
<INodeDirectorySection><directory><parent>16385</parent><child>16393</child><child>16394</child><child>16395</child></directory>
</INodeDirectorySection>
<FileUnderConstructionSection></FileUnderConstructionSection>
<SecretManagerSection><currentId>0</currentId><tokenSequenceNumber>0</tokenSequenceNumber><numDelegationKeys>0</numDelegationKeys><numTokens>0</numTokens></SecretManagerSection><CacheManagerSection><nextDirectiveId>1</nextDirectiveId><numDirectives>0</numDirectives><numPools>0</numPools></CacheManagerSection>
</fsimage>

里面最外层是一个fsimage标签,看里面的inode标签,

这个inode表示是hdfs中的每一个目录或者文件信息

例如这个:

<inode><id>16393</id><type>FILE</type><name>LICENSE.txt</name><replication>2</replication><mtime>1586332513657</mtime><atime>1586332513485</atime><preferredBlockSize>134217728</preferredBlockSize><permission>root:supergroup:0644</permission><blocks><block><id>1073741827</id><genstamp>1003</genstamp><numBytes>150569</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>

id:唯一编号

type:文件类型

name:文件名称

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-0000000000000000065  -o edits.xml

分析生成的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>
      <MTIME>1586349095694</MTIME>
      <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>
        <USERNAME>yehua</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <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:保存了集群的版本信息

2.2 SecondaryNameNode介绍

刚才在分析edits日志文件的时候我们已经针对SecondaryNameNode做了介绍,在这里再做一个总结,以示重视。

在这里插入图片描述

SecondaryNameNode主要负责定期的把edits文件中的内容合并到fsimage中

这个合并操作称为checkpoint,在合并的时候会对edits中的内容进行转换,生成新的内容保存到fsimage文件中。

在这里插入图片描述

注意:在NameNode的HA架构中没有SecondaryNameNode进程,文件合并操作会由standby NameNode负责实现

所以在Hadoop集群中,SecondaryNameNode进程并不是必须的。

2.3 DataNode介绍

DataNode是提供真实文件数据的存储服务

在这里插入图片描述

冗余度其实就是副本数,针对datanode主要掌握两个概念,一个是block,一个是replication

首先是block

HDFS会按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block,HDFS默认Block大小是 128MB

Blokc块是HDFS读写数据的基本单位,不管你的文件是文本文件 还是视频 或者音频文件,针对hdfs而言 都是字节。

我们之前上传的一个user.txt文件,他的block信息可以在fsimage文件中看到,也可以在hdfs webui上面看到, 里面有block的id信息,并且也会显示这个数据在哪个节点上面

Hadoop

这里显示在bigdata02和bigdata03上面都有,那我们过去看一下,datanode中数据的具体存储位置是由dfs.datanode.data.dir来控制的,通过查询hdfs-default.xml可以知道,具体的位置在这里

<property>
  <name>dfs.datanode.data.dir</name>
  <value>file://${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. The directories should be tagged
  with corresponding storage types ([SSD]/[DISK]/[ARCHIVE]/[RAM_DISK]) for HDFS
  storage policies. The default storage type will be DISK if the directory does
  not have a storage type tagged explicitly. Directories that do not exist will
  be created if local filesystem permission allows.
  </description>
</property>

那我们连接到bigdata02这个节点上去看一下

[root@bigdata02 ~]# cd /data/hadoop_repo/dfs/data/
[root@bigdata02 data]# ll
total 4
drwxr-xr-x. 3 root root 72 Apr  7 22:21 current
-rw-r--r--. 1 root root 14 Apr  8 20:30 in_use.lock

然后进入current目录,继续一路往下走

[root@bigdata02 data]# cd current/
[root@bigdata02 current]# ll
total 4
drwx------. 4 root root  54 Apr  8 20:30 BP-1517789416-192.168.182.100-1586268855170
-rw-r--r--. 1 root root 229 Apr  8 20:30 VERSION
[root@bigdata02 current]# cd BP-1517789416-192.168.182.100-1586268855170/
[root@bigdata02 BP-1517789416-192.168.182.100-1586268855170]# ll
total 4
drwxr-xr-x. 4 root root  64 Apr  8 20:25 current
-rw-r--r--. 1 root root 166 Apr  7 22:21 scanner.cursor
drwxr-xr-x. 2 root root   6 Apr  8 20:30 tmp
[root@bigdata02 BP-1517789416-192.168.182.100-1586268855170]# cd current/
[root@bigdata02 current]# ll
total 8
-rw-r--r--. 1 root root  20 Apr  8 20:25 dfsUsed
drwxr-xr-x. 3 root root  21 Apr  8 15:34 finalized
drwxr-xr-x. 2 root root   6 Apr  8 22:13 rbw
-rw-r--r--. 1 root root 146 Apr  8 20:30 VERSION
[root@bigdata02 current]# cd finalized/
[root@bigdata02 finalized]# ll
total 0
drwxr-xr-x. 3 root root 21 Apr  8 15:34 subdir0
[root@bigdata02 finalized]# cd subdir0/
[root@bigdata02 subdir0]# ll
total 4
drwxr-xr-x. 2 root root 4096 Apr  8 22:13 subdir0
[root@bigdata02 subdir0]# cd subdir0/
[root@bigdata02 subdir0]# ll
total 340220
-rw-r--r--. 1 root root     22125 Apr  8 15:55 blk_1073741828
-rw-r--r--. 1 root root       183 Apr  8 15:55 blk_1073741828_1004.meta
-rw-r--r--. 1 root root      1361 Apr  8 15:55 blk_1073741829
-rw-r--r--. 1 root root        19 Apr  8 15:55 blk_1073741829_1005.meta
-rw-r--r--. 1 root root        17 Apr  8 20:31 blk_1073741830
-rw-r--r--. 1 root root        11 Apr  8 20:31 blk_1073741830_1006.meta
-rw-r--r--. 1 root root 134217728 Apr  8 22:13 blk_1073741831
-rw-r--r--. 1 root root   1048583 Apr  8 22:13 blk_1073741831_1007.meta
-rw-r--r--. 1 root root 134217728 Apr  8 22:13 blk_1073741832
-rw-r--r--. 1 root root   1048583 Apr  8 22:13 blk_1073741832_1008.meta
-rw-r--r--. 1 root root  77190019 Apr  8 22:13 blk_1073741833
-rw-r--r--. 1 root root    603055 Apr  8 22:13 blk_1073741833_1009.meta

这里面就有很多的block块了,

注意: 这里面的.meta文件也是做校验用的。

根据前面看到的blockid信息到这对应的找到文件,可以直接查看,发现文件内容就是我们之前上传上去的内容。

[root@bigdata02 subdir0]# cat blk_1073741830
jack
tom
jessic
[root@bigdata02 subdir0]#

注意:这个block中的内容可能只是文件的一部分,如果你的文件较大的话,就会分为多个block存储,默认 hadoop3中一个block的大小为128M。根据字节进行截取,截取到128M就是一个block。如果文件大小没有默认的block块大,那最终就只有一个block。

HDFS中,如果一个文件小于一个数据块的大小,那么并不会占用整个数据块的存储空间

Hadoop

size是表示我们上传文件的实际大小,blocksize是指文件的最大块大小。

注意;这个block块是hdfs产生的,如果我们直接把文件上传到这个block文件所在的目录,这个时候hdfs是不识别的,没有用的

假设我们上传了两个10M的文件 又上传了一个200M的文件

问1:会产生多少个block块? 4个

问2:在hdfs中会显示几个文件?3个

下面看一下副本,副本表示数据有多少个备份

我们现在的集群有两个从节点,所以最多可以有2个备份,这个是在hdfs-site.xml中进行配置的,dfs.replication

默认这个参数的配置是3。表示会有3个副本。

副本只有一个作用就是保证数据安全。

2.4 NameNode总结

注意:block块存放在哪些datanode上,只有datanode自己知道,当集群启动的时候,datanode会扫描自己节点上面的所有block块信息,然后把节点和这个节点上的所有block块信息告诉给namenode。这个关系是每次重启集群都会动态加载的【这个其实就是集群为什么数据越多,启动越慢的原因】

咱们之前说的fsimage(edits)文件中保存的有文件和block块之间的信息。

这里说的是block块和节点之间的关系,这两块关联在一起之后,就可以根据文件找到对应的block块,再根据block块找到对应的datanode节点,这样就真正找到了数据。

所以说 其实namenode中不仅维护了文件和block块的信息 还维护了block块和所在的datanode节点的信息。

可以理解为namenode维护了两份关系:

第一份关系:file 与block list的关系,对应的关系信息存储在fsimage和edits文件中,当NameNode启动的时候会把文件中的元数据信息加载到内存中

第二份关系:datanode与block的关系,对应的关系主要在集群启动的时候保存在内存中,当DataNode启动时会把当前节点上的Block信息和节点信息上报给NameNode

注意了,刚才我们说了NameNode启动的时候会把文件中的元数据信息加载到内存中,然后每一个文件的元数据信息会占用150字节的内存空间,这个是恒定的,和文件大小没有关系,咱们前面在介绍HDFS的时候说过,HDFS不适合存储小文件,其实主要原因就在这里,不管是大文件还是小文件,一个文件的元数据信息在NameNode中都会占用150字节,NameNode节点的内存是有限的,所以它的存储能力也是有限的,如果我们存储了一堆都是几KB的小文件,最后发现NameNode的内存占满了,确实存储了很多文件,但是文件的总体大小却很小,这样就失去了HDFS存在的价值

最后,在datanode的数据目录下面的current目录中也有一个VERSION文件

这个VERSION和namenode的VERSION文件是有一些相似之处的,我们来具体对比一下两个文件的内容。

namenode的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

datanode的VERSION文件

[root@bigdata02 current]# cat VERSION 
#Wed Apr 08 20:30:04 CST 2020
storageID=DS-0e86cd27-4961-4526-bacb-3b692a90b1b0
clusterID=CID-cc0792dd-a861-4a3f-9151-b0695e4c7e70
cTime=0
datanodeUuid=0b09f3d7-442d-4e28-b3cc-2edb0991bae3
storageType=DATA_NODE
layoutVersion=-57

我们前面说了namenode不要随便格式化,因为格式化了以后VERSION里面的clusterID会变,但是datanode的VERSION中的clusterID并没有变,所以就对应不上了。

咱们之前说过如果确实要重新格式化的话需要把/data/hadoop_repo数据目录下的内容都清空,全部都重新生成是可以的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵广陆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值