HDFS HA
HDFS采用的是fsimage + edits的存储方式,fsimage是某个时间的内存文件系统镜像,edits是修改操作,每个修改操作称为一个事务,有一个整形的事务id指定。checkpoint的时候就存储一次fsimage,同时可以删除之前的edits。另外edits切割为很多segement,不同的segment都包含一段修改操作记录,正在写入的segment的文件名有inprogress和起始结束的txid修饰,写入完成就只有起始结束的txid修饰。recover的时候先把最新的fsimage加载到内存,然后回放对应的edits文件,这样就恢复到最新状态。整个流程类似于数据库的redo log。
HDFS为了提高可用性,提供了SecondaryNameNode,NFS,QuorumJournalManager等几种方法。
- SecondaryNameNode
SecondaryNameNode定期从NameNode拉取fsimage和edits文件,NameNode停止写入edit,写入新的edit.new。SecondaryNameNode然后加载fsimage,合并edits之后生成新的fsimage2,把fsimage2复制到NameNode中,NameNode替换原来的edits和fsimage。然后把edit.new改名回edit。
可以手动从SecondaryNameNode恢复之前checkpoint的数据。作用就是帮NameNode进行check point。没有failover。
- Using the NFS
热备。Active NameNode和StandBy NameNode之间有共享的存储NFS。Active会把修改写入NFS的edit,StandBy会看到这个修改,然后应用到自身的namespace,通过这样保持与Active的同步。
DataNode需要向两个NameNode发送Block信息。为了避免split brain,需要设置fencing方法,当failover的时候,禁止之前的Active继续向NFS写入edit。
- Using the Quorum Journal Manager
基于Paxos的Quorum-based方法。整个流程和Using the NFS类似,使用JournalNode作为共享存储。
包含以下模块:
1. NameNode中运行的QuorumJournalManager。负责通过RPC和JournalNode通信,发送edits,执行fencing和同步等操作。分为Active NN和StandBy NN两种状态的NN。
2. JournalNode守护进程运行在N(N>=3)台机器上。每个进程都允许QuourumJournalManager写入修改到本地中。
其中fsimage保存NameNode的本地,JN只负责存储edits内容。
另外算法必须保证
1.任何同步的修改不能lost;
2.任何没有同步的修改可能lost也可能生效;
3.如果edit被读取,那么就一定不能lost;
4.对于指定的txid,必须只有一个有效的事务。
Active NN正常运行时,流程如下:
往JournalNode写入Edits(QJournalProtocol.journal)
NameNode进行logSync时,QJM把队列的batch edits的byte数组复制到新的数组后发送到所有的JoualNode中。JN收到edits后,需要进行一些校验:
(a)校验epoch number是否大于等于lastPromisedEpoch (b)校验epoch number是否等于lastWriterEpoch (c)校验请求的segmentTxID是否等于当前log segment的txID (d)校验batch edits的firstTxnId是否等于上一次写入Edits的transactionsID + 1(nextTxId)
其中a是fencing机制,避免之前active的NN进行修改,如果大于lastPromisedEpoch,则更新并保存到本地;b是保证lastWriterEpoch的正确,用于recover;c是由于每个log segment都有txid,保证每个segment的内容一致;d是保证segment的edits是按照txid有序,也是保证内容一致;
校验之后,把edits写入当前log segment,然后返回success。如果JN的校验失败,会抛出OutOfSync或者IO异常,NN会标记这个JN停止后续对其发送RPC修改,直到startLogSegment才重新写入该JN。
NameNode在执行logSync的线程中,等待quorum节点数返回。如果quorum节点数返回异常或者超时,logSync()跑出异常。这样QJM就会导致NameNode退出。