前言
在HDFS中,我们都知道DataNode是通过定期发送心跳信息到NameNode,以此证明自己还“活着”。当然心跳信息发送的另一项作用是发送自身的块报告信息给NameNode,以此保证集群数据的更新。然后NameNode会反馈给各DataNode一个回复命令。从这里看出,心跳在这里的所执行的操作还是比较“重”的。所以这里会引发出一个问题,一方面DataNode需要及时将自身的块信息报告给NameNode,另一方面,DataNode又要等待NameNode的心跳返回命令,换句话说,如果NameNode当前处理忙碌状态,处理心跳的速度异常地缓慢,那么就有可能造成DataNode下次心跳发送的延时,最糟糕的结果就是被认定为了dead node。所以在这里,我们应该要将心跳的“存活”检查功能从当前逻辑中剥离开来,从而达到一个轻量级的DataNode的生命检查。在本文的讲述中,我们将此称之为生命线(Lifeline)。
DataNode生命线介绍
DataNode生命线,英文全称为DataNode Lifeline。随着HDFS代码功能的叠加,每次的心跳处理过程变得也越来越“重”。其实心跳过程中的块上报过程和等待回复命令这2个过程是可以分开的。而DataNode Lifeline消息就是基于前者实现的。用下面一句话来概括DataNode Lifeline的概念。
DataNoded Lifeline本质上是一次轻量级的块信息的汇报,它不需要等待NameNode的回复结果,同时它能达到DataNode状态检查的目的。
DataNode生命线的适用场景
那么DataNode生命线到底能帮我们解决哪些异常情况下的问题呢?这里举2个例子,这样大家就会明白它的重要性了。
场景一:NameNode持续忙碌状态
在原有的逻辑中,DataNode的心跳报告方法是阻塞式的,它必须等待NameNode完毕,并给出回复命令,然后DataNode接着执行这些命令操作。所以这里会有一个严重的问题,当NameNode正在处理一个很大的块报告信息时,为了保持数据的一致性,处理过程是需要加锁的,其它的心跳信息就会被迫处于阻塞状态,等待当前处理过程的结束。这就会造成DataNode下次心跳的延时,如果DataNode超过了心跳检测的最长容忍时间(默认630s),就会被认为是dead node了,最终会导致一次完全没有必要的大量的replication操作。
场景二:DataNode持续忙碌状态
不仅仅是NameNode会处于忙碌状态,DataNode自身也会存在忙碌状态。比如说,DataNode用于发送心跳信息的BPServiceActor线程服务突然卡在了其中某一步操作上了,导致其没有及时的执行blockReport操作,时间长了也会被认为是dead node了。
其实从这里我们可以看出,将心跳的存活检查功能和等待命令处理过程放在一起是一件不太靠谱的事情。一个好的办法就是构造一个轻量级的消息发送接口,放在一个不同于BPServiceActor的心跳发送线程内,这样能很好地做到DataNode存活状态的更新了。而DataNode Lifeline就是这么做的。
DataNode生命线设计
DataNode生命线消息功能目前暂未发布,实现于社区issue:HDFS-9239(DataNode Lifeline Protocol: an alternative protocol for reporting DataNode liveness)。笔者在阅读完它的设计文档之后,总结了以下几个关键设计点:
- 构造了一个轻量级的块报告信息协议,汇报的块信息的格式与当前心跳形式完全一致,区别在于它不需要带返回结果,而且不需要NameNode进行加锁操作。
- DataNode生命线消息发送需要放在一个独立的线程中,进行定期的执行,避免心跳发送主线程的影响,同时做到一个备用的功能。
主要是以上2点,更多细节,大家可以阅读文章末尾的DataNode Lifeline设计文档链接。