手动切换方案,即在管理员发现Active NN不工作以后,或者由于升级等原因,手动将Standby NN切换为Standby NN。
手动切换的流程为:
1. 管理员在Active NN上,通过Hadoop命令行工具,通过HAAdmin工具(实现了Tools接口),将Active NN切换为Standby NN
hadoop HAAdmin -transitionToStandby
hadoop HAAdmin -transitionToActive
不同于NFS方案,以上两步操作如果没有顺序执行,也不会出现同时又两个Active NN的情况。这也是QJM方案的核心优势之一。
下面,我们看一下,如果原Active NN没有切换为Standby的情况下,将 Standby切换为Active会发生什么情况:
首先,每个NN都持有一个QuorumJournalManager,QuorumJournalManager可以理解为JournalNode的客户端,通过它可以连接到任意JournalNode(在hdfs-site.xml文件里配置的dfs.namenode.shared.edits.dir,配置了所有JournalNode的地址:qjournal://ocdata16:8488;ocdata17:8488;ocdata18:8488/mycluster)。QuromJournalManager通过AsyncLoggerSet保存到所有JournalNode的连接,对loggers的每次操作,都会通过call.waitFor等待各个JournalNode的返回结果。对于大部分操作,waitFor传入的最小返回节点数为(总节点数/2+1),对于format等特殊操作,传入的最小返回节点数为总节点数。
将Standby切换为Active时,调用:NameNode.startActiveServices()->FSNamesystem.startActiveServices()->FSEditLog.recoverUnclosedStreams()->JournalSet.recoverUnfinalizedSegments()->QourumJournalManager.recoverUnfinalizedSegment()->QourumJournalManager.createNewUniqueEpoch()
这时候,首先向所有的JournalNode询问他们最后的Epoch,在收到半数返回后,选择最大的epoch,这个epoch就是原Active NN持有的epoch。把这个epoch加1,然后告诉所有的JournalNode 这个新的epoch。从此以后,原Active只要操作EditLog,JournalNode就会发现它的epoch已经小于自己的epoch了,于是拒绝操作。
digraph G { edge [fontname="FangSong"] node [fontname="FangSong"] compound=true subgraph cluster_1{ fillcolor="#00FF80" style=filled JournalNode3 JournalNode2 JournalNode1 } subgraph cluster_2 { fillcolor="#FF8000" style=filled DataNode5 DataNode4 DataNode3 DataNode2 DataNode1 } subgraph cluster_NameNode_Active { fillcolor="#00FFFF" style=filled label="NameNode(Active)" QuorumJournalManager_L HAAdmin_L } subgraph cluster_NameNode_Standby { fillcolor="#00FFFF" style=filled label="NameNode(Standby)" QuorumJournalManager_R HAAdmin_R } JournalNode2 -> DataNode3[style=invis] QuorumJournalManager_L -> JournalNode2[lhead=cluster_1,label="日志写入"] QuorumJournalManager_R -> JournalNode2[dir=back,lhead=cluster_1,label="日志读取"] QuorumJournalManager_L -> DataNode2[dir=back,lhead=cluster_2,ltail=cluster_NameNode_Active,label="BlockReport"] QuorumJournalManager_R -> DataNode4[dir=back,lhead=cluster_2,ltail=cluster_NameNode_Standby,label="BlockReport"] HAAdmin_L->QuorumJournalManager_L[style=invis] HAAdmin_R -> QuorumJournalManager_R[style=invis] User -> {HAAdmin_L HAAdmin_R}[label="手动切换"]; User[label="用户",fillcolor="#5A99CC",style=filled] HAAdmin_L[label="HAAdmin"] HAAdmin_R[label="HAAdmin"] QuorumJournalManager_L[label="QuorumJournalManager"] QuorumJournalManager_R[label="QuorumJournalManager"] }