HDFS客户端无法及时addBlock和关闭文件问题分析

如题所述

第1个回答  2022-07-12
现网运行过程中,某些高负载集群的 NN 频繁打印下面的 “block is COMMITTED but not COMPLETE" 日志,且客户端经常会关闭文件失败,导致业务异常退出,如下所示:

这实际是一个 block 无法及时到达 COMPLETE 状态的问题,在 HDFS 中,一个 block 只有达到最小副本数之后,才能变为 COMPLETE 状态。HDFS 默认的最小副本数是1,也就是说,NameNode 收到至少1个 DataNode 的上报之后,这个 block 才能达到 COMPLETE 状态,表示这个 block 已经正式写入完毕,其内容此时已成功固化到磁盘。

如果一个文件的 block 不能及时达到 COMPLETE 状态,则会导致

这两个集群是负载较高的两个集群,共同点是 NameNode 都会频繁的打印上面那种 “block is COMMITTED but not COMPLETE” 日志,但这两个集群又有所不同:

以那个导致客户端出错的 block 为例(block ID 为:blk_16141305305),可以看到,客户端有5次重试,加上第一次的正常操作,一共尝试了6次 addBlock(或 completeFile),但全部未成功,这将直接导致客户端写文件失败(或关闭文件失败):

这个 block 涉及到两个 DN,以9.179.163.164 这个 DN 为例,可以看到,DN IO 线程在 16:46:16 写完 block 触发增量上报之后,一直过了45s 到了16:47:01,DN 心跳线程才开始真正向 NN 发送增量上报 RPC 消息,这很不正常,正常情况应该是立即发送才对(另外结合上面的 NN 日志可以看到,DN 发送增量上报 IBR 之后,就被 NN 同时在16:47:01处理完毕,可见此时 NN 没有问题):

进一步分析 DN 的 IBR 上报记录,可以看到:心跳线程在 16:46:07 到 16:47:01 之间,这54s之内,根本没有进行任何 IBR 上报,这也导致 16:47:01一下子积攒了很多 block,那么问题很清楚了,在这长达54s 的时间内,DN 心跳线程到底在干什么?

DN 心跳线程循环执行 BPServiceActor.offerService() 函数,在这个函数里,它循环做下面的事情:

现在的问题集中在:DN 在处理这次 IBR 之前,一共54s 内,到底在干嘛?

首先想到的就是 jstack,但是现在是事后分析,已经没法再 jstack 了。好在这个问题集群其实一直在持续性的出现这种文件不能及时关闭的问题,所以,现在再 jstack,也来的及,具体步骤:

这次倒是比较顺利的拿到了结果:

既然找到了原因,那么解决起来就比较容易了,通过上面的分析,核心的原因还是 FsDatasetImpl.datasetLock 这把全局互斥锁实在是太难抢了,导致心跳线程在 getStorageReports() 时长时间等这把锁(最终是 getDfsUsed() )。但实际上,心跳线程此时其实不需要这把锁,因为它拿到锁之后,要访问的数据结构是一个 ConcurrentHashMap,要知道 ConcurrentHashMap 本身即是一个支持并发读写的结构,访问它根本不需要额外再加什么锁。

到底为止,改法其实出来了,DN 心跳线程在 getDfsUsed() 时,不用加 FsDatasetImpl.datasetLock 这把全局互斥锁。

历尽千辛万苦,终于找到了原因,但是当我要去改的时候,发现 hdfs 3.x 已经改了这个地方(改动的目的是解决另外一个问题,但却顺带着也解决了我们这次的问题),所以 backport 就可以了,具体 jira 为:HDFS-7060 Avoid taking locks when sending heartbeats from the DataNode

从这个问题的分析过程,也可以看出,像 NameNode 和 DataNode 这种高并发、大吞吐的多线程任务,在功能方面,可以不断的增加新特性,但在性能方面,最终的瓶颈往往会落到某个全局锁上(或者虽然不是全局但范围特别广的锁),这时候争锁才是导致多线程无法完全发挥潜力、整体吞吐量下降的阿克琉斯之踵。更加难受的是,争锁的困境往往很难通过小修小补解决,而是需要架构层面的重构,这又进一步加大了优化的成本。典型的比如 HDFS NN 和 DN 中的两把全局锁,对整体性能的影已经是一个旷日持久的问题,但直到现在,也依然没有得到解决:

DN 心跳线程争锁是一个老生常谈的问题,除了上面已经合入的 HDFS-7060 之外,社区还有其他几个 Patch 也需要合入:
相似回答