最近需要搞一下Lease,分析一下recoverLease的過程,順帶把recoverBlock的過程分析一下。
一、 recoverLease
recoverLease是恢複租約,我理解為釋放檔案之前的租約,close檔案,報告namenode。
recoverLease有兩條路徑去調用
1. DistributedFileSystem.create -> DFSClient.create -> Namenode.create -> FSNamesystem.startFile -> FSNamesystem.startFileInternal -> recoverLeaseInternal(myFile, src, holder, clientMachine, false)
這條路徑是在用戶端檔案create時調用的,此時它不需要close檔案。
2. DistributedFileSystem.recoverLease -> DFSClient.recoverLease -> Namenode.recoverLease(src,clientname) -> FSNamesystem.recoverLease(src,holder,clientMachine) -> recoverLeaseInternal(inode, src, holder, clientMachine, true)
這條路徑是在用戶端顯式調用一個path的recoverLease,此時它需要close檔案。[HDFS-1554]
以上兩個路徑,最終會調用FSNamesystem.recoverLeaseInternal,下面我們著重看一下recoverLeaseInternal,它主要做以下事情:
1. 獲得pendingfile,獲得當前holder的lease
2. 如果lease不為空白,且不是force,則AlreadyBeingCreatedException
3. 獲得當前client的lease,如果lease為空白,則AlreadyBeingCreatedException
4. 如果force則強制internalReleaseLeaseOne;否則,如果超過softlimit,也強制internalReleaseLease,但也拋出AlreadyBeingCreatedException。
它會通過調用internalReleaseLeaseOne實現對recoverBlock的執行。
recoverLeaseInternal -> internalReleaseLease -> internalReleaseLeaseOne
internalReleaseLeaseOne的過程:
1.找這個file的最後一個block的targets
2.pendingFile.assignPrimaryDatanode() -> DatanodeDescriptor.addBlockToBeRecovered() -> recoverBlocks.offer
recoverBlocks會在datanode向namenode發送心跳包時,將recoverBlock的命令以NN_RECOVERY的holder身份返回給datanode,datanode執行命令。
3.reassignLease
二、recoverBlock過程
recoverBlock是在Datanode上執行的,有兩條路徑調用,一個由Namenode發起的,一個DFSClient發起的。
1. Namenode發起recoverBlock
a)Namenode上的過程:
Namenode.sendHeartbeat(datanode調用,向namenode發送心跳包,namenode返回i要執行的cmd -> FSNamesystem.handleHeartbeat ->
DatanodeDescritor.getLeaseRecoveryCommand -> recoverBlocks.poll()
按照上面recoverLease的分析,如果有recoverLease的請求,BlockQueue類型的recoverBlocks就有待處理的recoverBlock
b)datanode上的過程
Datanode.run -> offerService()(一直運行,和namenode互動) -> processCommand(cmds []) -> processCommand(cmd) ->
DNA_RECOVERBLOCK -> recoverBlocks(bcmd.getBlocks(), bcmd.getTargets()) -> recoverBlock(blocks[i], false, targets[i], true)
[closeFile = true]
即datanode上有個心跳線程,預設每個3秒鐘,向namenode彙報心跳包,並獲得要在datanode上執行的cmd。如果有namenode發來的recoverBlock請求,
datanode上最終會調用recoverBlock方法,此時closeFile=true。它是recoverLease發起的,此時要關閉檔案,並使得這個檔案的block在datanode上的資訊一致。
2. DFSClient發起的recoverBlock
DFSClient.processDatanodeError ->DataNode.recoverBlock(Block block, boolean keepLength, DatanodeInfo[] targets) -> DataNode.recoverBlock(Block block, boolean keepLength, DatanodeInfo[] targets, false) [closeFile = false]
DFSClient通過dataStreamer發送block的packet資料,如果這個過程出現異常,會由processDatanodeError進行recover處理,即獲得pipeline中錯誤的datanode,在剩餘的兩個datanode選取一個datanode發起recoverBlock,從這個datanode開始重建pipeline。
此時調用datanode的recoverBlock傳遞的closeFile=false,因為在DFSClient寫入Block出現異常時,需要的是recover,不是關閉檔案。
關於recoverBlock(Block block, boolean keepLength, DatanodeInfo[] targets, boolean closeFile)
1.檢查ongoingRecovery中是否有這個block正在recover,如果有,則拋出IOException,Block is already being recovered, ignoring this request to recover it。如果沒有,則add進入ongoingRecovery
2.根據targets建立syncList,即明確向哪些節點sync哪個block
---> syncBlock
1.首先為這次syncBlock從namenode處獲得generationStamp
2.以新的generationStamp建立新的newBlock
3.對syncList中的每個datanode,執行updateBlock操作,將舊的block更新為newBlock
4.如果執行成功,向namenode報告commitBlockSynchronization,包含新的block和generationStamp
5.返回locatedBlock
---> updateBlock
1.FSDataset.updateBlock
2.如果finalize為true,FSDataset.finalizeBlockIfNeeded;通知namenode已經received block
以上,記錄以備忘。