【概述】
我们都知道整个hdfs由nn zkfc,dn,jn组成,这些可能运行在不同节点上的组件能组成一个集群,其中包含了共同的集群信息,并且各自将集群信息持久化存储到了本地,这个文件就是VERSION文件。本文就来聊聊VERSION文件的相关内容。
【各组件中的VERSION文件】
1. nn中的version文件
version文件的存储位置及具体内容如下:
代码语言:javascript复制# /home/hncscwc/data/hadoop/dfs/nn 为配置项 "dfs.namenode.name.dir" 指定的值
cat /home/hncscwc/data/hadoop/dfs/nn/current/VERSION
#Fri Mar 11 08:52:21 CST 2022
namespaceID=161164106
clusterID=CID-78f2e32d-93e0-4aeb-84ef-c84fa92520e0
cTime=1646959941280
storageType=NAME_NODE
blockpoolID=BP-1219799146-172.168.3.21-16446959941279
layoutVersion=-63
文件仅在首次格式化时写入,其中namespaceID,clusterID,blockpoolID,cTime均在这个时候生成。
2. jn中的version文件
文件存储位置与内容:
代码语言:javascript复制# /home/hncscwc/data/hadoop/dfs/journal 为配置项 "dfs.journalnode.edits.dir" 指定的值
# hdfsHACluster 为配置项 "dfs.nameservices" 指定的值
cat /home/hncscwc/data/hadoop/dfs/journal/hdfsHACluster/current/VERSION
#Fri Mar 11 08:52:21 CST 2022
namespaceID=161164106
clusterID=CID-78f2e32d-93e0-4aeb-84ef-c84fa92520e0
cTime=1646959941280
storageType=JOURNAL_NODE
layoutVersion=-63
同样,文件仅在NN格式化命令执行时创建并写入。其中namespaceID,clusterID,cTime在NN格式化命令中传递,即具体值来自于NN,并且保持一致。
格式化之后,nn会通过rpc请求进行editlog的相关操作,每次rpc请求中都会携带namespaceID,clusterID。如果与jn本地保存的不一致,jn会返回错误。
3. dn中的version文件
dn中会有两个位置分别存放不同的version文件。
一个是数据存储目录下的version,一个是数据存储目录BP(BlockPool)目录下的version文件。
数据存储目录下的version文件,具体存储位置与内容为:
代码语言:javascript复制# /home/hncscwc/data/hadoop/dfs/dn 为配置项 "dfs.datanode.data.dir" 指定的值
# 如果指定多个目录,则在每个目录下均会创建VERSION文件
cat /home/hncscwc/data/hadoop/dfs/dn/current/VERSION
#Fri Mar 11 08:54:51 CST 2022
storageID=DS-2d782d28-48fe-4808-9648-a20992700e34
clusterID=CID-78f2e32d-93e0-4aeb-84ef-c84fa92520e0
cTime=0
datanodeUuid=78434f35-7229-49d2-b225-db2e11b6eb6b
storageType=DATA_NODE
layoutVersion=-57
其中clusterID从NN获取得到;storageID为存储目录的唯一ID,即每个存储目录都有一个唯一ID。datanodeUudi为dn的唯一uuid,在每个这样的version文件中,其值都是一样的。
数据存储目录中BP目录下的version文件,具体存储位置与内容为:
代码语言:javascript复制# BP-1219799146-172.168.3.21-1646959941279 为nn的BlockPoolID
cat /home/hncscwc/data/hadoop/dfs/dn/current/BP-1219799146-172.168.3.21-1646959941279/current/VERSION
#Fri Mar 11 08:54:51 CST 2022
namespaceID=161164106
cTime=1646959941280
blockpoolID=BP-1219799146-172.168.3.21-1646959941279
layoutVersion=-57
其中namespaceID,cTime,blockpoolID均从nn获取得到。
从上面可以知道,nn格式化后生成了namespaceID,cTime,clusterID,blockpoolID然后同步给了jn,dn。
那dn中的uuid,storageID又是怎么来的,如果新添加一个目录,是否会具有同样的信息,如果不同卷目录中的uuid不一致,又会怎样?我们继续来看看dn启动流程。
【dn启动流程】
dn启动与之相关的流程包括:
1. 向nn建立连接,并请求命名空间信息
2. nn响应dn的请求,并回复dn,在响应内容中包括namespaceID,clusterID,blockpoolID,cTime以及自身状态(Active或Standby)
3. dn收到响应后,进行存储的初始化,具体步骤包括:
1)读取各个存储路径中的VERSION文件
如果存储目录中没有这个文件(可能是首次启动,也可能是新添加的存储卷目录),则进行格式化动作。即写VERSION文件(仅写入数据存储目录下的VERSION);如果有则读取该文件中的具体内容,并与请求响应中的字段比较,如果namespaceID,clusterID不一致则返回错误。
2)初始化dn的uuid
在上一步骤中,以读取到的第一个非空的DatanodeUuid作为dn的uuid,如果均为空(首次启动),则生成一个uuid,然后再将uuid重新写入各个存储卷目录下的VERSION中。
也就是说,当DN首次启动时,初始化动作会写两次VERSION文件,第一次没有DatanodeUuid,第二次会包含DatanodeUuid字段。
另外,非首次启动(即再次重启)时,由于会依次读取每个存储卷目录下的VERSION文件,并将第一个非空的DatanodeUuid作为dn的uuid,如果后续存储卷目录VERSION文件中的uuid与之前的不一致,则会抛异常退出。
3)加载blockpool的信息
读取各个BlockPool卷目录下的VERSION文件,如果没有该文件则进行格式化;有则比对namespaceID,BlockPoolID,cTime是否一致(不一致会抛异常退出),如有必要则更新该文件(通常是升级时)。
4. 向nn进行注册
向nn进行注册,注册时会携带datanode的uuid、rpc通信的ip地址,端口、数据传输的ip地址,端口等信息。nn收到请求后以DatanodeUuid作为唯一key,记录dn的信息并进行管理。
读到这里,我们知道了datanode的uuid是如何产生并在多个存储卷目录同步了,以及再次重启时如何沿用之前产生的uuid。
【新增存储卷目录】
考虑这么一种场景,停止dn后,在配置文件中新增了存储卷目录,dn再次启动后,这个新增的存储卷目录中VERSION文件会是怎样的?
这里需要分两种情况来分析:
- 新增的卷目录放在配置条目的中间或最后(非配置条目的第一个) 结合上面的流程,可以看出,在进行存储的初始化动作时,因为该目录为空,所以会进行格式化动作,又由于之前读取了其他目录中的VERSION文件,并获取到了DatanodeUuid,因此格式化写入的VERSION中会包含DatanodeUuid。
- 新增的卷目录放在配置条目的第一个 同样会进行格式化动作,但因为该存储卷目录为读取的第一个目录,并且没有VERSION文件,因此此时DatanodeUuid为空。所以格式化写入的VERSION文件中也就没有uuid。在此之后加载其他存储卷目录的VERSION文件,得到了DatanodeUuid,并且非空,因此不会生成新的uuid并再次写入VERSION文件中。 最终新增的这个存储卷目录的VERSION文件中也就没有了DatanodeUuid字段。
例如:首次启动时,仅配置"/home/hncscwc/data/dfs/dn",停止dn后,新增一个存储卷目录"/home/hncscwc/data1/dfs/dn",并放在配置项的最前面,即"/home/hncscwc/data1/dfs/dn,/home/hncscwc/data/dfs/dn"。此后启动dn,会发现 "/home/hncscwc/data1/dfs/dn"下的VERSION文件中没有DatanodeUuid字段。
代码语言:javascript复制[root@hncscwc dfs]# cat /home/hncscwc/data1/dfs/dn/current/VERSION
#Fri Mar 11 08:54:51 CST 2022
storageID=DS-2d782d28-48fe-4804-9648-a20992700e34
clusterID=CID-78f2e32d-93e0-4aeb-84ef-c84fa92520e0
cTime=0
storageType=DATA_NODE
layoutVersion=-57
[root@hncscwc dfs]# cat /home/hncscwc/data/dfs/dn/current/VERSION
#Fri Mar 11 08:54:51 CST 2022
storageID=DS-2d782d28-48fe-4804-9648-a20992700e34
clusterID=CID-78f2e32d-93e0-4aeb-84ef-c84fa92520e0
cTime=0
datanodeUuid=78434fe5-7229-49d2-b225-db2e11b6eb6b
storageType=DATA_NODE
layoutVersion=-57
在这种情况下,虽然VERSION文件中没有datanodeUuid,但不会影响正常使用。
【总结】
小结一下,本文主要介绍了hdfs各个组件中VERSION文件中存储的集群信息,以及dn的唯一id是如何产生并保持不变的,可以扩展的一些点是:如果不小心对active的nn进行了格式化并进行了重启,如何进行集群的恢复;如果存储卷目录中的id不一致了应当如何恢复等。