转载:https://clouderatemp.wpengine.com/blog/2015/03/understanding-hdfs-recovery-processes-part-2/
很好的文章,但是要翻墙转载给国内的伙伴,作者有问题请联系删除
在运行或转向可用于生产环境的Apache Hadoop时,掌握HDFS恢复过程非常重要。在由两部分组成的结论中,解释了管道恢复。
HDFS的一项重要设计要求是确保连续且正确的操作支持生产部署。因此,对于操作员而言,了解HDFS恢复过程的工作方式非常重要。在这篇文章的第1部分中,我们研究了租赁回收和大块回收。现在,在第2部分中,我们将探讨管道恢复。
这三个恢复过程对于HDFS容错至关重要。它们共同帮助确保即使在存在网络和节点故障的情况下,HDFS中的写入也持久且一致。
概括
在HDFS中,文件分为多个块,并且文件访问遵循多读取器,单写入器的语义。为了满足容错要求,一个块的多个副本存储在不同的DataNode上。副本数称为复制因子。创建新文件块或打开现有文件进行追加时,HDFS写入操作将创建一个DataNodes管道以接收和存储副本(复制因子通常确定该管道中DataNode的数量)。随后对该块的写入将通过管道(图1)。
图1. HDFS写管道
对于读取操作,客户端选择保存该块副本的DataNode之一,并请求从中进行数据传输。
要深入了解此背景信息,请阅读本文的第1部分。
管道恢复
写管道
HDFS客户端写入文件时,数据将按顺序块写入。为了写入或构造一个块,HDFS将该块分解为数据包(实际上不是网络数据包,而是消息;术语“ 数据包”指代体现这些消息的类),并将其传播到写入管道中的DataNodes,如图所示。 2。
图2. HDFS写入管道阶段
写管道包括三个阶段:
- 管道设置。客户端沿着管道发送Write_Block请求,最后一个DataNode发回确认。收到确认后,管道即可进行写入。
- 数据流。数据以数据包的形式通过管道发送。客户端缓冲数据,直到数据包填满为止,然后将数据包发送到管道。如果客户端调用hflush(),则即使数据包未满,它也将被发送到管道,并且直到客户端接收到对先前hflush数据包的确认后,才会发送下一个数据包。
- 关闭(完成副本并关闭管道)。客户端等待,直到所有数据包都已确认,然后发送关闭请求。管道中的所有DataNode将相应的副本更改为FINALIZED状态,并报告回NameNode。如果至少已配置的最小数据复制数量报告了其对应副本的FINALIZED状态,则NameNode会将块的状态更改为COMPLETE。
管道恢复
当在写入块时,管道中的一个或多个DataNode在三个阶段中的任何一个阶段遇到错误时,都会启动管道恢复。
从管道设置故障中恢复
- 如果为新块创建了管道,则客户端将放弃该块,并向NameNode请求一个新块和一个新的DataNode列表。为新块重新初始化管道。
- 如果创建了管道以附加到块,则客户端将使用剩余的DataNode重建管道,并增加块的生成标记。
从数据流故障中恢复
- 当管道中的DataNode检测到错误(例如,校验和错误或写入磁盘失败)时,该DataNode将通过关闭所有TCP / IP连接将自身从管道中移出。如果认为数据未损坏,它还会将缓冲的数据写入相关的块和校验和(METADATA)文件。
- 当客户端检测到故障时,它将停止向管道发送数据,并使用剩余的良好DataNode重建新的管道。结果,该块的所有副本都被碰撞到新的GS。
- 客户端将继续使用此新GS发送数据包。如果发送的数据已被某些DataNode接收,则它们只是忽略该数据包并将其传递到管道的下游。
从关闭失败中恢复
- 当客户端在关闭状态下检测到故障时,它将使用剩余的DataNode重建管道。如果尚未确定副本,则每个DataNode都会提高该块的GS并确定副本。
当一个DataNode损坏时,它将自己从管道中删除。在管道恢复过程中,客户端可能需要使用剩余的DataNode重建新的管道。(根据下一节中描述的DataNode替换策略,它可能会也可能不会用新的DataNode替换坏的DataNode。)复制监视器将负责复制该块以满足配置的复制因子。
失败时的DataNode替换策略
关于建立与其余DataNode的恢复管道时是否添加其他DataNode来替换不良DataNode,有四种可配置的策略:
- DISABLE:禁用DataNode替换并引发错误(在服务器上);这就像从来没有在客户端一样。
- 永不:当管道发生故障时(通常不是理想的操作),切勿替换DataNode。
- 默认:根据以下条件进行更换:
- 令r为配置的复制号。
- 令n为现有副本数据节点的数量。
- 仅在r> = 3且仅此时添加一个新的DataNode
- floor(r / 2)> = n; 要么
- r> n,并且该块被填充/附加。
- 总是:当现有DataNode发生故障时,请始终添加新的DataNode。如果无法替换DataNode,此操作将失败。
要禁用使用这些策略中的任何一个,可以将以下配置属性设置为false(默认值为true):
dfs.client.block.write.replace-datanode-on-failure.enable
启用后,默认策略为DEFAULT。以下配置属性更改了策略:
dfs.client.block.write.replace-datanode-on-failure.policy
使用DEFAULT或ALWAYS时,如果只有一个DataNode在管道中成功,则恢复将永远不会成功,并且客户端将无法执行写入。此问题通过以下配置属性解决:
dfs.client.block.write.replace-datanode-on-failure.best-effort
默认为false。使用默认设置,客户端将继续尝试直到满足指定的策略。当将此属性设置为true时,即使无法满足指定的策略(例如,管道中只有一个成功的DataNode成功,小于策略要求),仍将允许客户端继续来写。
一些已解决的问题
- HDFS-5016详细介绍了管道恢复中的死锁情形,该死锁情形导致DataNode被标记为已死(重复HDFS-3655 “ Datanode recoveryRbw可能会挂起”和HDFS-4851 “管道恢复中的死锁”)。发生的情况是:恢复正在进行时,它将导致一些相关的线程互相等待,从而导致死锁。由于
FSDataset
锁保持在此死锁中,因此心跳线程和数据收发器线程被阻塞,等待FSDataset
锁。解决方案是引入超时机制以打破僵局。 - HDFS-4882报告了一个情况,即NameNode的LeaseManager在checkLeases中永远循环。硬限制到期后,如果倒数第二个块为COMMITTED,而最后一个块为COMPLETE,则LeaseManager尝试恢复租约,
internalReleaseLease()
将在不释放租约的情况下返回,并且LeaseManager将继续尝试释放相同的租约,因此无限循环 由于FSNamesystem.writeLock
保留在循环中,因此实质上使NameNode无响应。解决方法是仅尝试定期而不是连续释放租赁。 - HDFS-5557详细介绍了以下情况:由于处理块报告时错误的GS记录,导致块中最后一个数据包的写管道恢复可能导致拒绝有效副本。最坏的情况是,所有好的副本都将被拒绝,而坏的副本将被接受。在这种情况下,相应的块将完成,但是只有在收到包含有效副本之一的下一个完整块报告之后,才能读取数据。解决方案是修复GS记录。
- HDFS-5558报告了以下情况:如果最后一个块已完成,而倒数第二个块未完成,则LeaseManager监视线程可能崩溃。如果文件的最后一个和倒数第二个块均未处于COMPLETE状态,并且试图关闭该文件,则最后一个块可能会更改为COMPLETE,而倒数第二个可能不会。如果这种情况持续很长时间并且文件被放弃,LeaseManager将尝试恢复租约并在块上进行块恢复。但是
internalReleaseLease()
这种文件将因无效的强制转换异常而失败。解决方案是在关闭文件之前,确保倒数第二个块处于COMPLETE状态。
已知的未解决问题
- 随着的引入
dfs.client.block.write.replace-datanode-on-failure.best-effort
,即使只有一个DataNode,客户端也将能够继续写入。发生这种情况时,一个块可能只有一个副本,并且如果在复制之前对该单个副本进行任何操作,则将发生数据丢失。为了缓解该问题,HDFS-6867提出了一个后台线程来在客户端向单个副本进行写操作时进行管道恢复。 - HDFS-4504 详细介绍了
DFSOutputStream#close
并非总是释放资源(例如租赁)的情况。在某些情况下,DFSOutputStream#close
可以抛出IOException
。一个示例是如果发生管道错误,然后管道恢复失败。不幸的是,在这种情况下,所使用的某些资源DFSOutputStream
被泄漏了。一个特别重要的资源是文件租用,因此,寿命长的HDFS客户端(例如Apache Flume)可能会向文件写入许多块,但随后无法关闭它。但是,客户端中的LeaseRenewer线程将继续为“ undead”文件续订租约。将来尝试关闭文件只会重新抛出先前的异常,客户端无法取得任何进展。 - HDFS-6937详细介绍了由于校验和错误导致的管道恢复问题。中间DataNode上的数据(假设复制因子3)以某种方式被破坏,但未被检测到。最后一个DataNode发现了校验和错误,并将自己从管道中取出。恢复过程一直在尝试用新的替换新的管道中的最后一个DataNode,并将数据从中间的DataNode复制到新的DataNode。每次由于校验和错误而导致复制失败(由于中间DataNode处的副本已损坏),并且新的DataNode被标记为不良并被丢弃,即使它不是很糟糕。最终,在耗尽所有数据节点后,恢复将失败。
- HDFS-7342报告了以下情况:当倒数第二个块为COMMITTED且最后一个块为COMPLETE时,租赁恢复无法成功。一个建议的解决方案是强制收回租约,这与在最后一个块被提交时的处理方式类似。可以看到,HDFS-7342,HDFS-4882和HDFS-5558的相关性在于倒数第二个块处于COMMITTED状态。问题的微妙性目前仍在调查中。
结论
租用恢复,块恢复和管道恢复对于HDFS容错都是必不可少的。他们共同确保即使在存在网络和节点故障的情况下,HDFS中的写入操作也是持久且一致的。
希望在阅读这些文章之后,您可以更好地了解何时,为什么调用这些过程以及它们的作用。如果您想了解更多信息,则可以通读一些链接,包括设计规范,此处引用的JIRA或相关代码。