Namenode名字节点
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Namenode名字节点相关的知识,希望对你有一定的参考价值。
参考技术A对于Namenode的分析,分以下几个部分:
这些操作都是在安全模式中进行的:
当Namenode收集到的阈值比例满足最低副本系数的数据块时才可以离开安全模式。
HDFS的高可用(High Availability, HA)方案就是为了解决Namenode的单点故障而产生的。
在HA HDFS集群中会同时运行两个Namenode
备份Namenode的命名空间与活动Namenode是实时同步的,所以当活动Namenode发生故障而停止服务时,备份Namenode可以立即功换为活动状态,而不影响HDFS集群的服务。
1. HA架构
在一个HA集群中,会配置两个独立的Namenode。在任意时刻,只有一个节点会作为活动的节点,另一个节点则处于备份状态。活动的Namenode负责执行所有修改命名空间以及删除备份数据块的操作,而备份的Namenode则执行同步操作以保持与活动节点命名空间的一致性。
如图3-64所示,为了使备份节点与活动节点的状态能够同步一致,两个节点都需要与一组独立运行节点( JournalNodes, JNS )通信。当Active Namenode执行了修改命名空间的操作时,它会定期将执行的操作记录在editlog中,并写入JNS的多数节点中,而Standby Namenode会一直监听JNS上editlog的变化,如果发现editlog有改动, Standby Namenode就会读取editlog并与当前的命名空间合并。
当发生了错误切换时, Standby节点会先保证已经从JNS上读取了所有的editlog并与命名空间合并,然后才会从Standby状态切换为Active状态。通过这种机制,保证了Active Namenode与Standby Namenode之间命名空间状态的一致性,也就是第一关系链的一致性。
为了使错误切换能够很快地执行完毕,就需要保证Standby节点也保存了实时的数据块存储信息,也就是第二关系链。这样发生错误切换时, Standby节点就不需要等待所有的数据节点进行全量块汇报,而可以直接切换为Active状态。为了实现这个机制, Datanode会同时向这两个Namenode发送心跳以及块汇报信息。这样Active Nanenode和Standby Namenode的元数据就完全同步了,一旦发生故障,就可以马上切换,也就是热备。这里需要注意的是,Standby Namenode只会更新数据块的存储信息,并不会向Namenode发送复制或者删除数据块的指令,这些指令只能由Active Namenode发送。
为了防止脑裂的问题,HDFS提供了三个级别的 隔离机制(fencing):
2 HA状态切换方式
3 Active Namenode和Standby Namenode之间如何共享editlog日志?
Active Namenode会将日志文件写到共享存储上,Standby Namenode会实时从共享存储读取editlog文件,然后合并到命名空间 。
4 QJM方案中有两个组件:
5 租约管理
我们知道HDFS文件是write-once-read-many,并且 不支持客户端的并行写 操作,那么这里就需要一种机制保证对HDFS文件的互斥操作。 HDFS提供了租约(Lease)机制来实现文件的互斥操作。
租约: 是Namenode给予租约持有者(LeaseHolder,一般是客户端)在规定时间内拥有文件权限(写文件)的合同。
在HDFS中,客户端写文件时需要先从 租约管理器(LeaseManager)申请一个租约 ,成功申请租约之后客户端就成为了租约持有者,也就拥有了对该HDFS文件的独占权限,其他客户端在该租约有效时无法打开这个HDFS文件进行操作。
Namenode的租约管理器保存了 HDFS文件与租约 、 租约与租约持有者的对应关系, 租约管理器还会定期检查它维护的所有租约是否过期。租约管理器会强制收回过期的租约,所以租约持有者需要定期更新租约(renew),维护对该文件的独占锁定。当客户端完成了对文件的写操作,关闭文件时,必须在租约管理器中释放租约。
Boy-20180726
HDFS名字节点启动
在NameNode类中有个main函数,也就是启动NameNode节点的入口函数。NameNode类的main函数中通过方法createNameNode()创建了一个NameNode对象,然后就调用NameNode.join()函数等待NameNode停止
在createNameNode()函数中首先获取一个Configuration对象,用于加载启动NameNode节点所需的配置参数。然后获取运行参数。然后根据运行参数的值作分别处理:
如果是FORMAT操作,那么进行格式化处理:
1.获取名字节点命名空间镜像fsimage保存的目录和编辑日志edits保存目录
2.创建FSNamesystem对象
a.首先创建FSImage对象:初始化成员变量FSEditLog对象,初始化父类Storage的属性
i.存储类型storageType为名字节点类型
ii.对每个存储目录:创建StorageDirectory:初始化root目录和名字节点目录的类型(是image还是edit目录)
添加到成员变量storageDirs列表中
b.初始化FSNamesystem对象中的一些参数
c.创建FSDirectory对象:
赋值FSImage对象给成员变量fsImage
初始化根目录INodeDirectoryWithQuota对象(rootDir成员变量):
初始化父类INodeDirectory:name为“”字符串,permission 755,childer为空
初始化节点配额:nsQuota无限大
初始化空间配额:-1
节点个数nscount设为1
d.FSDirectory对象作为FSNamesystem的属性
3.进行格式化操作(FSImage类中的format方法):
a.进一步初始化FSImage对象中的成员变量:
layoutVersion,namespaceID,cTime, checkpointTime
b.对每个存储目录,进行格式化处理:
1.(clearDirectory方法)当前目录下有current子目录的话,清除current子目录,并重新创建
在current目录下
2创建一个文件锁in_user.lock
3. 在current目录下,根据存储目录的类型进行分别处理(saveCurrent方法,此时只需要保存根目录信息):
a.(根据名字节点目录类型判断)如果是元数据镜像文件:创建fsimage文件,并写入layoutversion,namespaceId,
根节点对应的节点个数(初始为1),生成时间genstamp(初始为1000L)
接着保存根节点信息:名字长度(0),路径(“”),副本系数(0),最后一次修改时间(0),数据块大小(0),数据块个数(0),节点配额,空间配额,用户名,组名权限信息
b.如果是编辑日志文件:创建edits文件,写入layoutversion
c.(StorageDirectory的write方法):
1.在当前目录(根目录)下检查并创建子目录image,并在image目录下检查并创建fsimage文件,写入相关信息,如layoutversion,描述信息
2.在current目录下创建VERSION文件,并写入信息layoutVersion,
storageType,namespaceID,cTime
如果是FINALIZE操作,则进行一些FINALIZE处理:
1.获取名字节点命名空间镜像fsimage保存的目录和编辑日志edits保存目录
2.创建FSNamesystem对象
a.首先创建FSImage对象:初始化成员变量FSEditLog对象,初始化父类Storage的属性
i.存储类型storageType为名字节点类型
ii.对每个存储目录:创建StorageDirectory:初始化root目录和名字节点目录的类型(是image还是edit目录)
添加到成员变量storageDirs列表中
b.初始化FSNamesystem对象中的一些参数
c.创建FSDirectory对象:
赋值FSImage对象给成员变量fsImage
初始化根目录INodeDirectoryWithQuota对象(rootDir成员变量):
初始化父类INodeDirectory:name为“”字符串,permission 755,childer为空
初始化节点配额:nsQuota无限大
初始化空间配额:-1
节点个数nscount设为1
d.FSDirectory对象作为FSNamesystem的属性
3.FINALIZE处理:
a.对每个存储目录,进行处理
1.在根目录下查看previous目录是否存在,不存在抛出异常
2.然后把previous目录重命名为finalized.tmp目录,完成以后,删除finalized.tmp目录
如果是RECOVER操作,则进行恢复相关的操作:
1.获取名字节点命名空间镜像fsimage保存的目录和编辑日志edits保存目录
2.创建FSNamesystem对象
a.首先创建FSImage对象:初始化成员变量FSEditLog对象,初始化父类storage的属性
i.存储类型storageType为名字节点类型
ii.对每个存储目录:创建StorageDirectory:初始化root目录和名字节点目录的类型(是image还是edit目录)
添加到成员变量storageDirs列表中
c.初始化FSNamesystem对象中的一些参数
b.创建FSDirectory对象:
赋值FSImage对象给成员变量fsImage
初始化根目录INodeDirectoryWithQuota对象:
初始化节点配额:nsQuota无限大
初始化空间配额:-1
节点个数nscount设为1
初始化父类INodeDirectory:name为“”字符串,permission 755,childer为空
d.FSDirectory对象作为FSNamesystem的属性
3.RECOVER处理:
先重复上面格式化处理的第一步,第二步操作,然后(调用loadFSImage(MetaRecoveryContext recovery)方法)
a.对每个存储目录的current目录下读取fstime文件,获取最近一次检查点时间。然后在这些目录中获取最大检查点相应的目录,并对该目录检查否需要从上次中断中恢复(recoverInterruptedCheckpoint方法):
1.如果current目录下fsimage.ckpt文件存在,
edits.new文件也存在,此时我们必须得删除
fsimage.ckpt文件,因为我们不知道namenode崩溃时,fsimage是否已经上传完毕
2.如果current目录下fsimage.ckpt文件存在,
edits.new文件不存在,说明文件上传已经完毕此时我们只需要删除fsimage文件文件,把
fsimage.ckpt文件重命名为fsimage文件
3.在current目录下读取VERSION文件:读取layoutVersion,storageType,
namespaceID,cTime
4.加载该目录中fsimage文件:
a.读取layoutVersion,namespaceID,总节点个数,生成时间genstamp
b.循环读取每个节点:
1.读取路径长度,路径名,副本系数,修改时间,数据块大小,数据块
个数,对于每个数据块,读取数据块信息:
blockId,numBytes,generationStamp
2.如果节点是目录节点,读取节点配额,空间配额
3.读取用户名,组名,权限信息
4.对于根目录:如果节点配额或者空间配额不为1,更新根目录rootDir
配额,并更新其修改时间,权限信息等
5.添加该节点到父节点中(addToParent):
a.如果该节点是目录节点,并且节点配额或空间配额不为-1,则
创建一个INodeDirectoryWithQuota对象,否则创建一个
INodeDirectory对象
---创建INodeDirectory对象时候:
初始化了属性: modificationTime,accessTime,权限相关信息
但未初始化属性:children,name,parent属性信息
b.如果该节点是文件节点,则创建INodeFile对象
---创建INodeFile对象时候:
初始化了属性:modificationTime,accessTime,权限相关信息,
replication,preferredBlockSize
但未初始化属性:name,parent,blocks属性信息
(调用rootDir的addToParent方法)
c.设置该节点对应的文件或者目录名字(name属性)
d.获取父节点并把当前节点添加到父节点的children集合中
(子节点添加到父节点的children中,子节点的parent指向父节点)
e.检查父目录节点修改时间和当前节点修改时间,取较大的值作
为父目录节点修改时间
f.对于文件节点,如果是文件有数据,即有数据块。则对于该文件中的 每个数据块:
a.创建BlockInfo对象,并把该对象放到BlocksMap中的
GSet<Block, BlockInfo> blocks集合中(或者从blocks集合中获取BlockInfo对象),设置属性inode为当前文件节点
---创建BlockInfo对象时,初始化父类Block的属性,
建立了triplets数组(内容并未初始化),初始化inode属性
b.把BlockInfo对象添加到文件节点的成员变量blocks数组中
6.开始加载当前正在写的文件信息:
a.读取写文件的个数
b.对应每个正在写的文件
1.读取路径长度,路径,副本系数,修改时间,数据块大小,数据块个数,对于每个数据块,读取数据块信息:
blockId,numBytes,generationStamp
2.读取用户名,组名,权限信息
3.读取客户端名字,读取客户端机器名
4.读取该文件对应的数据节点个数,加载数据节点描述信息:
a.创建DatanodeDescriptor对象clientNode
b.读取数据到该对象的父类DatanodeID中的属性中:
name,storageID,infoPort
c.读取数据到父类DatanodeInfo的属性中:
ipcPort,capacity,dfsUsed,remaining等
5.创建INodeFileUnderConstruction对象:
初始化父类INodeFile(同上)
设置变量name(存的是路径),clientName,clientMachine,clientNode为null
6.获取文件路径,在rootDir下找出旧的文件节点
7.替换旧文件节点
a.从父节点中删除旧文件节点:从childer集合中删除当前节点,
parent指向空
b.把当前节点添加到父节点的children集合中,当前节点的parent指向父节点
c.对于该文件中的每个数据块:
1.创建BlockInfo对象,并把该对象放到
GSet<Block, BlockInfo> blocks集合中(或者从blocks集合中获取BlockInfo对象),设置属性inode为当前文件节点
---创建BlockInfo对象时,初始化父类Block的属性,
建立了triplets数组(内容并未初始化),初始化inode属性
2.把BlockInfo对象添加到文件节点的成员变量blocks数组中
7.(addLease方法)
创建租约lease对象:holder客户端名,lastUpdate为当前时间
添加到leases集合中:键客户端名,值租约本身
添加到TreeSet<Lease> sortedLeases中
添加到sortedLeasesByPath集合中:键路径名,值租约本身
把路径添加到租约对应paths集合中
5.加载编辑日志:
a.打开edits文件,读取日志版本号
b.获取操作码
1.如果是创建文件操作或者关闭文件操作:
a.读取文件的路径,副本数,修改时间,访问时间,数据块大小,数据块列表,权限(用户名,用户组名和访问权限)
如果是创建文件操作,还要读取客户端名称,客户端所在的主机
b.对于文件关闭操作,从父节点中删除当前节点
c.计算该文件旧节点的节点配额和空间配额:
节点配额: nsCount =1
空间配合:对每个数据块的大小求和,如果最后一个数据块是正在进行写操作, 使用建议的数据块大小
d.旧节点的所有父目录重新计算节点配额和空间配额(减去当前节点所占的配额)
e.设置父目录的修改时间为已经读取的修改时间
f.删除旧节点文件拥有的数据块:
parent设为空
每个数据块对应的inode对象设为空
blocks设为空
g.根据文件路径,从sortedLeasesByPath集合中删除,
租约中删除相关路径,如果租约为空,则从leases和sortedLeases集合中删除租约
h.添加当前文件对应的新节点,创建新的文件节点
i.计算该文件旧节点的节点配额和空间配额:
节点配额: nsCount =1
空间配合:对每个数据块的大小求和,如果最后一个数据块是正在进行写操作, 使用建议的数据块大小
j.设置新节点的name为文件路径
k.新节点的所有父目录重新计算节点配额和空间配额(加上当前节点所占的配额)
h.当前节点添加到父节点对应的childer结合中,当前节点的parent指向父节点
i.则对于该文件中的每个数据块:
a.GSet<Block, BlockInfo> blocks集合中,获取对应的BlockInfo对象
b.把BlockInfo对象添加到节点的成员变量blocks数组中
j.如果是创建文件操作,新建一个INodeFileUnderConstruction对象
用INodeFileUnderConstruction替代原来的节点
创建租约lease对象:holder客户端名,lastUpdate租约更新时间
添加到leases集合中:键客户端名,值租约本身
添加到TreeSet<Lease> sortedLeases中
添加到sortedLeasesByPath集合中:键路径名,值租约本身
把路径添加到租约对应paths集合中
6.保存内容到FSiamge中(saveNamespace方法):
1.关闭原来编辑日志输出流
2.设置FSImage对象的属性checkpointTime为当前时间
3.对于每个存储目录:
1.把current目录rename成lastcheckpoint.tmp目录
2.创建current目录
3.调用saveCurrent方法保存目录:
1. 在current目录下,根据存储目录的类型进行分别处理:
a.如果是元数据镜像文件:
1.创建fsimage文件,并写入layoutversion,namespaceId,
节点个数,生成时间genstamp
2.接着保存根节点信息:名字长度(0),路径(“”),副本系数(0),最后一次修改时间(0),数据块大小(0),数据块个数(0),节点配额,空间配额,用户名,组名权限信息
3.保存剩余节点信息:
a.保存当前节点的所有孩子节点:
对每个孩子节点,保存名字长度,路径:
1.如果孩子节点是文件节点, 保存副本系数,修改时间,
访问时间,指定的数据块大小,数据块个数,以及每个数据块信息,最后保存用户名,组名权限信息
对于目录节点:保存副本系数(0),修改
时间,访问时间(0),数据块大小(0),数据块个数(-1),
节点配额,空间配额,用户名,组名权限信息
如果孩子节点是目录节点,递归保存其子节点
4.保存正在构建的文件信息:
a.保存总共文件的个数(leaseManager.countPath())
b.从sortedLeases中读取每个文件路径,除了保存一些文件相关信息,还保存客户端名字和客户主机名,保存0
创建名字节点:
1.创建FSNamesystem对象:
a.配置一些参数信息
b.创建FSDirectory对象并赋给属性dir:
1.首先创建FSImage对象:初始化成员变量FSEditLog对象,初始化父类Storage的属性,赋值FSImage对象给FSDirectory中的成员变量fsImage
i.存储类型storageType为名字节点类型
2.初始化根目录INodeDirectoryWithQuota对象:
初始化节点配额:nsQuota无限大
初始化空间配额:-1
节点个数nscount设为1
初始化父类INodeDirectory:name为“”字符串,permission 755,childer为空
c.获取启动项
d.如果启动项是格式化处理:
1.对每个存储目录:创建StorageDirectory:初始化root目录和名字节点目录的类型(是image还是edit目录)添加到成员变量storageDirs列表中
2.格式化处理(略)
3.启动项设置为REGULAR
e.对于每个存储目录,分析该目录的存储状态,并做相关的恢复处理
g.根据启动项进行判断
1.如果是升级操作:
a.先加载最新检查点的image文件,加载对应的日志(loadFSImage(recovery)方法)
b.设置FSImage对象的cTime为当前时间,layoutVersion,checkpointTime为当前时间
对于每个存储目录:
c.把current目录rename成previous.tmp目录
d.调用saveCurrent方法保存内容到新目录
e.把previous.tmp目录改名为previous目录
2.如果是import操作,做import操作
3.如果是回滚操作:
a.创建FSImage对象:初始化成员变量FSEditLog对象,初始化父类Storage的属性,赋值FSImage对象给FSDirectory中的成员变量fsImage
i.存储类型storageType为名字节点类型
b.设置layoutVersion的值,对每个存储目录:
读取Previous目录中的VERSION文件:
赋给变量layoutVersion,storageType,namespaceID,cTime并进行验证
c.把current目录rename成removed.tmp
d.把previous目录rename成current目录
e.删除removed.tmp目录
f.对于回滚操作结束后或者REGULAR操作:
先加载最新的image文件,加载对应的日志
g.调用saveNamespace方法保存FSimage文件
2.创建安全模式管理对象SafeModeInfo:
blockSafe:0
threshold:0.95
1. 获取总共的数据块个数:blocksMap对象中的blocks.size()
2.从租约管理器中的sortedLeases集合中循环获取租约,获取租约中的每个路径对应的文件节点,获取文件节点对应的最后一个数据块如果大小为0,则总的数据块减1
3. 得出最终的安全的数据块个数,赋值给blockTotal属性
4.检查安全模式状态:
a.查看blockSafe/blockTotal是否小于0.95(满足最小副本水平),如果是,则进入安全模式
reached设为0(进入安全模式),lastStatusReport=当前时间,返回
b.如果blockTotal为0或者blockSafe/blockTotal大于等于0.95,如果reached<0(表示安全模式是关闭的)
或则extension <= 0 或者 threshold <= 0 --- 不要等待
离开安全模式(reached = -1),并返回
c.如果reached>0说明安全模式是打开的,返回
d.reached = 当前时间表示开始安全模式
创建安全模式后monitor线程启动:
安全模式的启动:
1.判断是否满足最小副本水平,则继续安全模式
2.否则离开安全模式,reached = -1
3.创建并启动心跳检查进程:
a.每隔5分钟检查一下心跳:
1.安全模式下,不检查心跳
2.从heartbeats集合中循环获取DatanodeDescriptor对象,获取第一个dead node:
a.检查该数据节点是否是dead节点:
就是上次检查时间lastUpdate+ heartbeatExpireInterval 小于当前时间,说明是dead节点
3.同步heartbeats集合和datanodeMap集合:
b.获取dead node的storageId,然后从datanodeMap集合中获取DatanodeDescriptor对象,
---datanodeMap集合中存放所有storageId 和对应的DatanodeDescriptor对象
再次检查该对象是否是长时间没有上报心跳,如果是的话,
删除该节点:
1.重新计算FSNamesystem对象的空间信息:
capacityTotal减去该节点的capicty,
capacityUsed,capacityRemaining,totalLoad
2.从heartbeats集合中删除该节点
3.该节点的isAlive设置为false
4.对该DatanodeDescriptor对象的每个数据块:
a.在blocksMap中:
对BlockInfo对象的处理:
1.根据数据块从blocks集合中获取BlockInfo对象
2.从该BlockInfo对象的triplets数组中获取对应的DatanodeDescriptor对象所在的索引位置
3.通过索引在该BlockInfo对象的triplets数组获取该数据节点前一个和后一个BlockInfo对象
4.在在该BlockInfo对象的triplets数组中,设置当前BlockInfo对象的前一个和后一个都为空
5.对于前一个BlockInfo对象,在该对象的triplets数组中找到对应的DatanodeDescriptor对象所在的索引位置,并把next指向后一个BlockInfo对象
6.对于后一个BlockInfo对象,在该对象的triplets数组中找到对应的DatanodeDescriptor对象所在的索引位置,并把previous指向前一个BlockInfo对象
7.该BlockInfo对象的元素个数减一,把最后一个数据节点的位置移到DatanodeDescriptor对象所在的索引位置
8.如果该BlockInfo对象的数组中没人任何元素,则可以从blocks中删除对应的数据块
数据块备份操作:
1.blocks中根据数据块获取BlockInfo对象,再获取对应的文件节点对象
2.如果安全模式下:
a.(使用countNodes方法)迭代该数据块对应BlockInfo对象的triplets数组,获取对应的
DatanodeDescriptor对象
1.获取损坏数据块对应的数据节点集合
2.迭代每个数据节点:
a.如果节点在nodesCorrupt 集合中,则损坏的副本数+1:corrupt++
b.如果当前数据节点正在撤销或者已经撤销状态时,
则位于撤销节点的副本数:count++
c.否则,获取当前节点多余的副本, 如果数据块是多于副本则多余副本数加1:excess++
否则正常副本加1:live++
---excessReplicateMap存放的是键数据节点的storageId,值是多于的数据块集合
d.新建NumberReplicas对象
b.获取正常的副本数,如果正常副本数达到safeReplication-1,则
blockSafe--,检查安全模式状态
-----以下是非安全模式
c.再次使用使用countNodes方法计算副本状态
d.获取预期的副本数
e.更新数据块的优先权:
1.获取旧的备份数和预期副本数
2.计算当前数据块的优先级:
a.如果当前备份已经大于预期副本,则返回3(不要备份)
b.如果当前备份为0,并且撤销的数目大于0,则返回0(最
高优先权),否则返回2
c.如果当前备份为1,返回0
d.如果当前备份*3小于预期副本,返回1
e.否则返回2
3.计算删除数据节点前数据块的优先级
4.如果旧的优先级不为3,且前后优先级有变化:
则在priorityQueues中删除对应的数据块
5.当前优先级不为3,把该数据块加到priorityQueues中
6.在excessReplicateMap,根据数据节点获取所有多于的数据块excessBlocks,从excessBlocks中删除该数据块
---excessReplicateMap键storageId,值对应的数据块集合
excessBlocksCount--
7.从corruptReplicasMap中获取该数据块对应的所有DatanodeDescriptor对象,删除对应的数据节点对象
---corruptReplicasMap键数据块,值数据块对应的DatanodeDescriptor对象集合
5. 对该DatanodeDescriptor对象:
a. 清空该节点对象的统计信息:capacity,dfsUsed,remaining等都清为0
b.(recentInvalidateSets无效的数据块副本,即等待的数据块副本)
----recentInvalidateSets存放键storageId,值数据块集合
recentInvalidateSets中删除该删除节点对应的所有无效数据块,并重新计算等待删除的数据块副本数
c.在clusterMap中删除对应的数据节点拓扑信息:
6.检查安全模式
4.创建并启动租约管理器monitor进程:
1.从sortedLeases获取最久的租约对象,判断是否英超
2.如果是的话,获取该租约的所有文件路径,递归读取每个文件路径:
a.根据文件路径获取文件节点对象
b.如果文件不拥有任何数据块:
1.从leases根据客户端名获取对应的租约:
removeLease方法:
a.sortedLeasesByPath中删除路径名与租约的对应关系
b.租约对应的paths中删除对应的文件路径
c.如果租约对应paths以为空,则可以冲leases中删除该租约
并且sortedLeases中删除
2.建立一个新的节点文件对象
3.用新的替代旧的节点对象
4.记录日志信息(略)
c.如果该文件对应的最后一个数据块为空:
1.获取倒数第二个数据块
2.通过数据块从blocks获取中获取BlockInfo对象,并获取该对象对应的数据节点个数据
3.获取该数据块对应的所有数据节点
4.重新设置targets为这些数据节点
5.循环读取这些数据节点,如果数据节点isAlive为true,该节点设置主数据节点:
a.建立BlockTargetPair对象并插入到blockq队列汇中
b.设置该文件节点的客户端名为NN_Recovery
c.在租约管理器中,调用removeLease方法删除租约
d.重新添加租约:
1.以NN_Recovery为客户端名创建租约(如果租约不存在的话,存在的话根据客户端名获取租约)
2.添加到leases集合和sortedLeases中
3.路径名和租约关系添加到sortedLeasesByPath中
4.路径名放到租约对应的paths中
d.如果租约恢复不成功:
a.直接调用removeLease删除租约
5.数据块恢复/删除线程:
1.如果安全模式下,不进行数据块备份和删除操作
2.计算复制最多数据块数blocksToProcess
2.复制操作:
a.如果neededReplications(等待赋值的副本)为空,不处理
b.否则去blocksToProcess和neededReplications.size()的较小值作为要处理的block个数
c.迭代获取neededReplications中的数据块及优先级,这些数据块放到blocksToReplicate集合中
d.对每个数据块,根据数据块获取对应的文件节点对象,如果文件节点为空或者正在构建中,则从neededReplications集合中删除对应的数据块
e.获取该节点对应的需要的数据块备份数
f.获取数据源节点(chooseSourceDatanode方法):
1.从blocksMap对象中可以获取所有的数据节点
2.从corruptReplicas获取坏了的数据节点
3.对每个数据节点,如果节点已损坏,或者该节点需要赋值的数据块个数
或者该节点已经撤销或者该当前节点上的数据块是多于的,则该数据节点不能作为源节点
4.如果该数据节点正在撤销中,则取该节点作为源节点,否则去随便去一个位源数据节点
g.如果该数据块的有效个数加上待复制的个数大于等于预期的数据块备份,
则把该数据块从neededReplications删除
h. 选择目标节点
i.根据数据块获取对应的文件节点对象,如果文件节点为空或者正在构建中,则从neededReplications集合中删除对应的数据块
j.如果该数据块的有效个数加上待复制的个数大于等于预期的数据块备份,
则把该数据块从neededReplications删除
k.添加数据块到要备份的列表中:replicateBlocks
l.从pendingReplications集合中,根据数据块获取对应的PendingBlockInfo对象
如果返回的是空:
创建一个PendingBlockInfo对象(numReplicasInProgress设为其备份数),放入集合中numReplicasInProgress+=备份数目
否则numReplicasInProgress+=备份数目,timeStamp设为当前时间
m.如果有效的备份数加上当前要备份数大于等需要备份的数据,从neededReplications删除该数据块
3.数据块删除操作:
a. 计算recentInvalidateSets.size() 和 nodesToProcess的较小值,作为要处理数据块副本的数据节点个数
b. 对这些数据节点:
1.安全模式不处理
2.从datanodeMap中获取nodeId对应的数据节点
3.从recentInvalidateSets中根据nodeId获取所有的无效数据块副本
4.把这些无效的数据块添加到该数据节点对应的属性invalidateBlocks集合中
4.如果pendingReplications中的timedOutItems不为空,说明有些复制请求超时,
a.获取这些数据块,从新计算该数据块的有效备份数,重新放到neededReplications中,发出备份请求
6.创建撤销管理,创建和启动数据节点撤销检查线程:
1.设置检查间隔recheckInterval:30秒
每次检查的数据节点个数numNodesPerCheck:5
2.启动进程:
a.
7.创建安全模式管理对象SafeModeInfo,并跟新成员变量blockTotal,调用结束后,名字节点
一般处于安全模式
8.创建并启用心跳检查进程:
默认每隔5分钟做一次心跳检查:如果某个数据节点故障,从心跳队列中删除该节点
9.创建并启用租约检查线程,数据块复制/删除线程
10.读入数据节点的include文件和exclude文件,创建并启动数据节点撤销检查线程
11.创建网路布局所需要的dnsToSwitchMapping对象,如果可能,分析include文件中包含的主机位置
以上是关于Namenode名字节点的主要内容,如果未能解决你的问题,请参考以下文章