官网原文:https://issues.apache.org/jira/browse/HDFS-1073
官网原文PDF:https://issues.apache.org/jira/secure/attachment/12478323/hdfs1073.pdf
转载自:tps://www.xuebuyuan.com/1159402.html
原文版本很老了,但是模型设计没变。
这个设计极大的简化了Fsimage和Editlog的处理和命名,NN名字空间目录的storage layout被重构成更为健壮,现在每个Edit都有个txid,并且每个文件都有txid与之关联,如果是CheckPoint的文件则有一个txid,而Editlogs则有一个txid的范围与之关联,详细设计文档如下:
1、Transaction IDs
HDFS在Fseditlog中使用txid的概念已经很久了,Txid被顺序的赋予到各个写入数据到Editlog的线程,然后在利用txid在logSync()中进行group commit
1.1 Persistent Transaction IDs
Hdfs-1521作为Hdfs-1073的子任务,其目标是将txid进行持久化。也就是说一个刚刚初始化的NN的txid是1,以后在这个namesystem的生命周期内,同一个txid永远不会被重用,这包括NN重启和进行CheckPoint的情况。
1.2 Non-namespace transactions
FsEditlog中已经包含了一些特殊的Transaction,这些Transaction不会改变namespace而是在NN的logs已经被rolled或者其他情况下用来通知BN。这个设计中将会在增加两个这样的Transaction
1、OP_BEGIN_LOG_SEGMENT 这个Transaction写在每个新的Editlog文件的最开始,目前不包含任何数据的,以后可能会将一些namespace中特殊的CheckPoint和metadata信息写入
2、OP_END_LOG_SEGMENT 这个Transaction在每个Editlog文件即将关闭的时候写在末尾。这可以检查该文件是否被正确的关闭,另外也可以用在BN与NN进行log roll同步的时候。以后,这个Transaction可能会被扩展加入log文件的checksum。
这两个Transaction也被用于确保所有的Editlog中至少包含一个Transaction,这就避免了很多判断Editlog为空文件的代码
2、Storage contents
NN的storage目录仍然按照要么是Edits/Images,要么是Edits&Images来组织。不同之处在于每个edit文件或者image文件都有个后缀来标明该文件中包含的txid,具体的文件名模式如下:
fsimage_N 这是一个CheckPoint,并且所有小于等于N的Transaction都已经包含在内
edits inprogress N 这是一个Editlog文件,它的第一个Transaction的id是N,最后一个Transaction的id未知。这个文件要么是ActiveNN正在写入,要么是前一个NN没有正确的shutdown
edits N-M 这是一个Editlog文件,它包含了从N到M的素有的Transactions
例如,一个刚刚格式化的NN具有如下的内容:
1、fsimage_0 空的image文件
2、edits_inprogress_1 正在写入的Editlog文件
当Editlog文件进行roll的时之后,edits_inprogress将会被重命名为edits_N-M。所以如果在一个写入了10个edits的NN中进行roll的话,将会看到:
1、fsiamge_0 同上
2、edits_1-10 所有在roll之前的Transactions
3、edits_inprogress_11 正在写入的edit文件
当进行CheckPoint的时候一个image被save或者upload时,将会进行以下验证:任何fsiamge_N必须包含所有小于N的logs。所以如果在上一个例子中,如果调用了saveNamespace,将会看到:
1、fsimage_0 同上
2、edits_1-10 roll之前的Transactions
3、edits_11-12 包含有特殊的BEGIN _LOG_SEGMENT以及END_LOG_SEGMENT但是并没有进行namespace更改
4、fsimage_12 所有的edits都会写入到namespace
5、edits_inprogress_13 被写入的editlog文件
3、Log Rolling
3、1 Triggers to roll logs
以下事件将会发起一个log的roll
1、NN startup
2、saveNamespace
3、SecondaryNN或者BN进行CheckPoint
4、一个失效的storage目录重新使用
5、主动的trig一个log roll,这在进行backup中比较管用。
3、2 Log rolling process
1、关闭当前的edits_inprogress_N
2、在所有的edits目录中,进行重命名edits_inprogress_N为edits_N-M。
3、任何之前就有问题的edits目录将会留下edits_inprogress_N(因为无法判断是否所有的edits都已经在roll之前写入到该文件中)
4、在所有的edits目录中打开edits_inprogress_M+1文件,即使在是失效的目录中也会尝试
4、Startup behavior
如果NN没有正确的关闭,那么在重启之时,将要进行recovery。特别地,如何带有inprogress的文件是由于以下原因造成:
1、NN在运行的时候,这个目录就变成了非法,那么NN将停止对这个目录的写入
2、NN在打开并且写入log到该文件的状态下crash掉
第一种情况,由于其他的目录可能是完好的,那么没多大的问题。而第二种情况则需要在startup时进行重放
NN通过LOG RECOVERY过程来判断每个EditLog归属于哪个category,并且判定从哪个log集中加载namespace
4、1 Log recovery(ActiveNN)
PrimaryNN通过以下步骤进行log recover
1、在所有的edit目录下找寻edits_inprogress_N
2、对每个找到的N:
a、在所有的edit目录中找寻finallized的并且以N作为开始的edits文件
b、如果找到至少一个edits_N-M,那么edits_inprogress_N可能已经corrupt了,此时应该重命名为edits_inprogress_N_corrupt(如果狠点的话就删除)
c、如果没找到一个edits_N-M文件,那么NN应该是在写logN文件的时候crash了,在所有的edits_N_inprogress启动以下初始化过程
1、对每个log,计算合法长度,即去掉结束的OP_INVALID之后的文件长度
2、使用最长的log文件来进行replaying
4、2 Log recovery(backup node)
在BN中,任何"inprogress"文件必须删除,过后再从PNN中获取。这些文件发生在BN正在进行replicating的时候crash了,那么遗留的这些文件会因为PNN在不断的写入而比PNN中对应的文件短。
4、3 Image recovery
任何fsimage_ckpt_N文件都可能是没有完成的,因为"_ckpt"表名该文件正在被写。因此需要删除这些image文件(或者加上".corrupt"后缀)
4、4 Namespace reconstruction
在进行了上述recovery操作之后,接下来需要选择那些log文件应该被load进去以构建Namespace
1、找到fsimage_N,其中N是所有的edits目录中的最大值
2、找到所有的log文件,其txid起始值大于N
3、将所有的edits目录下的log文件按照其实txid分组
4、Invariant:所有具有相同起始txid的log文件具有相同的结束txid
5、Invariant:如果有一个组的log文件具有从N到M的txid,那么这个文件要么是最后一个组要么下一个组的起始txid为M+1
那么,可以按照以下顺序启动NN
1、载入fsimage_N
2、从以txid为N+1到M的log组中加载任意的一个log文件
3、从以txid为M+1的log组中加载任何一个log文件
4、其他
如果最后一个组(起始txid为M+1的那个组)以txid为Q结尾,那么NN将写入log到edits_inprogress_Q+1
4、5 Upgrade
升级过程本质是不变,除了我们必须读取老的layout(fsimage,edits,edits.new)来进行升级。本文中描述的改变仅仅发生在current目录中,所以previous目录在Upgrade/rollback/finalization过程中的管理方式并没有改变。
5、saveNamespace
PNN进行保存Namespace的过程如下:
1、NN必须在safemode下,这使得没有任何editlog写入到namesystem中
2、NN写入OP_END_SEGMENT到当前的"inprogress"文件中并且对该文件进行close,rename,finalize,假定N是OP_END_SEGMENT的txid
3、NN在每个edits目录中保存namespace到fsimage_ckpt_N中
4、NN重命名fsimage_ckpt_N为fsimage_N在所有的edits目录中
5、NN在所有的edits目录中打开edits_inprogress_N+1,并且写入OP_BEGIN_SEGMENT。
5、1 Failure analysis
如果NN在结束了一个log segment之后并且保存namespace之前crash了,那么老的log文件已经finallized了,新的log文件尚未创建,重新启动后log recovery正如4.1所描述
如果NN在saveNamespace时crash掉,那么image recovery将会移除未完成的ckpt image,recovery过程同上
如果NN已经重命名一个或多个image之后crash了,那么在recovery的时候会正确的从image文件进行,并且忽略小的txid的edits文件
6、Checkpoint process
本文中的checkpointing node是值任何能够发起checkpointing过程的node,可能是secondarynamenode,CheckpointNode或者其他,具体看实现。但是Checkpoint的过程不变如下:
1、CheckpointSignature加入最新的fsimage的 txid和目前正在写入(inprogress)的edits文件的start txid
2、Checkpointing node发起一个beginCheckponit的rpc到NN
3、NN开始roll这些log文件,并且将上述的Checkpoint signature返回。
4、Checkpointing node发起一个getRemoteEditLogs的rpc去获取一个finallized log segments,这些log文件的是在image的txid和current log 的txid之间的所有的Transactions
5、GetImageServelet应该可以由参数指定来下载哪个image或者edits文件
6、Checkpoint node 下载fsimage_N以及所有从N到CheckpointSignature中指定txid之间的所有edits文件。注意:下载之后这些文件被命名为类似于:edits_inprogress_N-M和fsimage_ckpt_N,只有经过验证之后,再命名为edits_N和fsimage_N
7、CheckPointer 在本地保存fsimage_M,然后upload到NN。和前面一样,NN也是先命名文件为fsimage_ckpt_N,等上传完成之后才命名回去,这样确保CheckPoint中断之后,不会导致storage目录的corrupt。
8、NN对CheckpointSignature验证时,只确保来自同一个文件系统,检查相应的Security Token,以前关于文件的时间检查不在需要了,因为这都包含在txid内。
9、NN将fsimage_M+1保存到本地的image文件加中,不对log做任何操作
6、1 Handling multiple secondary name nodes
注意上述过程中,NN没有保存任何正在进行的CheckPoint的状态,也就是说如果多个CheckPointer发起CheckPoint的请求,NN也会照做。在这个情况下,NN会多次进行roll,将不同的txid交给相应的CheckPointer,然后CheckPointer上传不同txid的fsimage
7、BackupNode operation
这个设计中,BackupNode的操作也显著的简化了
7、1 BackupNode state
BN包含以下状态
JournalState - 枚举类型,要么IN_SYNC要么JOURNAL。
IN_SYNC:表名该BN的namespace目前和PNN的是同步的,并且BN新接收到的edits应该立刻应用到namespace中。
JOURNAL:表名该BN的namespace当前落后与PNN的状态,并且新的edits只要写入到磁盘即可
NamesystemReflectsLogsThroughTxId - 当前BN已经apply过了的edits的txid
StopApplyingAtNextRoll - boolean型,容许CheckPoint停止对edit的apply
7、2 BackupNode Startup
启动过程中,BN首先依照4.2节描述的方式进行storage recovery。然后按照4.4的方式进行namespace重建,即使NN也是如此。
1、当启动完成,NamesystemReflectsLogsThroughTxId变量将会更新成BN刚刚recover过的最新的image或者editlog文件的txid
2、然后BN向PNN进行注册,注册时,PNN将会进行一次roll log,然后开始向streaming log流到BN上
3、BN开始状态处于Journal模式,因为它不一定和PNN同步。为了在启动后同步,BN可以调用catchupSynchronization()
7、3 Receiving edits
一旦注册之后,PNN开始通过RPC向BN流式发送edit
7、3、1 Special edit records
BN对OP_BEGIN_LOG_SEGMENT和OP_END_LOG_SEGMENT这两个log没有任何不同,它需要依靠这两个log来对本地的edits进行roll,以便和PNN同步。
如果StopApplyingAtNextRoll 被设置,并且BN收到了OP_END_LOG_SEGMENT,那么BN将从IN_SYNC模式转换为JOURNAL模式,也就是说,从这个Transaction之后,BN不再将edit日志apply到namespace中
7、3、2 Applying and jouraling edits
依据当前的JournalState,BN为每个edit采取不同的措施
如果是在IN_SYNC状态,那么edit会尽快apply到namesystem中,同时也写入到磁盘文件中。
如果是在JOURNAL状态,那么edit仅仅写入到磁盘中。
7、4 Checkpointing
为了进行Checkpoint,BN采取以下措施:
1、设置StopApplyingAtNextRoll标识
2、通知NN进行beginCheckponit,roll log,写入OP_END_LOG_SEGMENT。因为这个Transaction,BN也相应进入JOURNAL状态。
3、现在BN应该已经关闭log并且进入到JOURNAL状态,如第六节描述,beginCheckponit将返回一个checkpointSignature
4、如果BN之前是在IN_SYNC,那么BN和NN已经是同步了。如果BN不是在IN_SYNC,那么需要下载从NamesystemReflectsLogsThroughTxId到checkpointSignature中指定的txid之间的所有editlog并且apply到namespace
5、上传checkpoint到PNN中
6、调用catchupSynchronization
7、5 Converging logs(TODO need to update this design for txid)
完成checkpoint之后,BN现在处于JOURNAL状态,需要进行"catch back up"到PNN,算法如下:
def catchupSynchronization():
assert we are in JOURNAL state
converged = false
while namesystemReflectsLogsThrough <= currentReceivingLog:
if namesystemReflectsLogsThrough < currentReceivingLog:
# we're still catching up on finalized logs
fetchAndReplayLogIndex(namesystemReflectsLogsThrough + 1)
else:
converged = tryConverge(namesystemReflectsLogsThrough + 1)
assert mode == IN_SYNCdef tryConverge(N):
open current edits_N_inprogress that is being written to
if the open fails due to FNFE:
assert that edits_N exists [ie it got rolled before we opened it]
return False
replay logs until EOF
lock journal
if currentReceivingLog > N:
# we rolled while replaying, go back to catchup sequence
unlock journal
assert that edits_N exists (ie that our open file got finalized under us)
continue to replay logs from same open stream until EOF
namesystemReflectsLogsThrough = N
return False [we did not succeed in converging]
assert currentReceivingLog == N
replay last logs in edits_N_inprogress until another EOF
set state = IN_SYNC
namesystemReflectsLogsThrough = N
unlock journal
return True7、6 Handling multiple BNs
上述设计中个,BN并没有假设NN可能会在某些情况下停止rolling,所有的checkpoint在server都是无状态的。如果多个BN都进行checkpoint,他们可能在不同的txid上进行,上传不同txid的fsimage到NN
8 Image/edits file retention policies
上述设计中,并未描述image和edit的删除策略,为了保证空间的可控,NN在做restart的时候应该删除一些不必要的editlog文件和image文件。删除策略如下:
1、历史Image的个数 - 确保至少有N个历史的image文件在目录中,确保txid>=最老的Nth的image文件的txid都在这N个文件中。
2、时间 - 确保所有在设定时间内的edit都在文件中保留,即:txid>=最老image的txid
3、打包 - 为了审计,purage机制也很容易的实现将log打包到hdfs,tape,san等存储设备
9 Future Direction
尽管在本次设计中,没有实现以下功能,但是本次设计也为这些功能在以后实现预留了空间。以下详述这些观点:
9、1 NN-triggered checkpointing
除了让BN定期的进行checkpoint之外,也很容易实现让BN在OP_END_LOG_SEGMENT上进行checkpoint。优点在于这样让NN能够在一个合适的时机进行checkpoint,缺点在于如果多个BN同时发起checkpoint时,load比较高
9、2 Offline Checkpointing
除了可以有一个特殊的daemon来进行checkpoint之外,还可以搞一个Offline的工具来对给定的storage目录进行checkpoint,如下:
1、在所有的fsimage_x文件中,读入fsimage_N,N为最大值的那个文件。
2、读入任何所有大于N的editlog文件。
3、保存fsimage_M到该目录中
注意,这种情况,不会对inprogress的edit(如果该指定目录中有该文件的话)进行checkpoint,如果需要一个up-to-date的checkpoint,需要trigger PNN先进行一次roll,这可以通过一个dfsadmin -rollEdits命令来达成。
在写入fsimage_ckpt_M的时候,需要使用一个advisory lock来保持对该文件的独占。另外也可以通过将文件写入一个唯一的fsimage_ckpt_M_<GUID>来确保独占。
理想情况下,这个工具应该和checkpointNode大体相同。
9、3 Shared storage for metadata
本设计的一个优点是,任何finallized过的edit或者image在整个集群中都具有一个唯一标识(包括NN,BN,SNN)等。
在Shared storage目录中,TransferFsImage的调用不需要进行任何操作,BN改为直接tail当前shared-storage目录中的inprogress的editlog文件来获取最新的log,当BN遇到OP_END_LOG_SEGMENT时,它开启下一个inprogress进行tail。
这个设计和AvatarNode设计类似,除了AvartarNode需要在checkpoint和avatar之间进行协调。