文章目录
前言
前面时间笔者曾写过一篇关于利用HDFS fastcopy功能来加速DistCp数据拷贝效率的文章(Distcp结合HDFS Fastcopy的性能改造提升),以及提到了现有DistCp在数据切分时候的一些问题(聊聊Hadoop DistCp的数据切分处理方式),会导致长尾任务的出现等等。其实在后续的测试过程中,我们还发现并解决了许多大大小小的坑,使得我们整体数据拷贝的耗时达到一个相对短的小时。本文笔者来简单总结下这期间我们踩过的坑,以及我们最后是如何将1000w级别文件数量,10PB规模size的数据,在预估2小时内的时间就能全部迁移完成。
HDFS元数据快速膨胀带来的性能瓶颈问题
首先交代一下本文所述的数据迁移实战经历的一个背景是因为我司内部HDFS集群因为业务上的调整导致数据量出现了快速激增的情况。通过每日的RPC总量统计结果,整个集群的RPC处理量比之前翻了2,3倍之多。简单来说,就是我们集群承受了前所未有的RPC压力,这也让我们的HDFS经常处于一个busy的状态,关键SLA任务时不时会因为HDFS慢的问题导致延时的问题。
上面的问题已经不是通过打个简单patch就能立马解决的问题,基于这个背景,于是我们决定采用新加HDFS Federation的方式,将部分业务数据整体迁移到另一个新的namespace下,即我们新加入的一对NN中。
超大规模数据迁移所面临的挑战和困难
上面数据迁移大目标定好后,真正的难点在于数据的迁移,新NN环境搭建本身是一件比较容易搞定的事情。
我们对业务数据主要通过以下3个指标对其数据进行初步的分析
- 物理数据量所占空间
- 文件目录总数
- 每个业务目录下所产生的RPC总数
分析出结果后,我们综合考虑,选择迁移其中一个关键业务目录,对其进行迁移,这个目录的业务数据规模在1000w,10PB级别这样的层级。
随后我们做了一个简单的数据测试,生成10TB数据,进行数据拷贝大约花了15分钟,换算而言1PB约为1500分钟。如果我们把1500分钟约为1天(1440分钟)来算的话,10PB就要花10天的时间进行拷贝迁移。这显然是无法接受的一个时间。
上面给我们的要求是最多只允许2~3小时的窗口时间内(此时间允许服务downtime),分毫不差的完成所有数据的迁移。毫无疑问,这听上去对我们来说是一个巨大的挑战。
DistCp的全面优化提升
尽管面临的挑战非常的巨大,但是后面还是得一步步开始,大困难化小困难,小事化无这样的解决思路走。此部分,笔者来简单聊聊我们是如何一步步对DistCp做优化的。因为我们是用现有DistCp工具做拷贝的,所以动的最多的改动是在这个工具代码里。
第一大改造,集成HDFS Fastcopy改动(详见Distcp结合HDFS Fastcopy的性能改造提升)。鉴于我们的集群处于HDFS Federation模式的,下面的DN存储是共享的。所以在物理数据层面进行拷贝的话,其实是没有必要的,因为都在这一堆DN节点里面。于是我们将HDFS Fastcopy的文件拷贝集成到DistCp的文件拷贝过程中,通过新增一个useFastcopy的option来控制是否走fastcopy的方式。Fastcopy这块的优化改动后,相比原生DistCp拷贝,速度提升了5倍之多。在fastcopy的模式下,DistCp就演变为map task只在做createFile,addBlock这样的操作了。
第二点改动,数据分配倾斜优化(详见聊聊Hadoop DistCp的数据切分处理方式)。在实际测试过程中,我们经常发现在文件size分布不均衡导致的长尾任务的出现。比如要拷贝的目录里有众多的小文件,然后突然有个子目录里都是GB级别这样的大文件,于是这类的大文件被分到的那些task往往就会变得很慢。如果在按照文件目录数进行划分的strategy(设置DynamicInputFormat)时尤为明显。但是如果我们用按拷贝文件size进行均分时,在fastcopy下时其实没有意义,因为我们不copy实际的物理数据。于是我们想了一个办法,在还是基于文件size分配策略逻辑下,对不足1个块大小的小文件统统按照1个块的size算,来减少大文件和小文件之间的差异性影响。在此改造后,长尾现象得到了一定的改善。
第三点,目录ACL preserve操作的前置。在拷贝大目录操作的时候,我们经常会发现DistCp在所有task执行后会卡在最后commit上好长时间,后来发现是在做目录ACL的preserve保留操作。和文件ACL perserve是在map task里做的不同,目录是统一放在最后最的,于是我们直接将这步操作同样移到了每个task内执行。
第四点,失败任务的处理优化。在拷贝大量数据时,难免某些task会出现因为网络或者机器层面原因导致的个别任务拷贝失败的情况。这个时候如果在不指定ignore failure的情况下,DistCp会执行失败的。DistCp目前是有现有参数控制这个逻辑的。另外,我们新增了一个reduce task来收集,前面map task拷贝失败的文件记录,然后最后由reduce task写出到一个文件里。后续我们可以对失败文件,进行二次拷贝恢复。
第五点,部分相关参数的调整。在拷贝过程中,个别慢节点,异常节点的情况也时有发生,当集群规模比较大的情况下,这个很难避免。我们通过调整了一些参数来让task进行更快的重试来避免这个情况。比如ipc.client.connect.max.retries.on.timeouts=3,最多允许client连接3次超时,默认是45次(相当之多了,每次超时会等待20s)。
在经过前面5点的优化之后,我们的DistCp拷贝相较原生模式,在稳定性和效率上已有很大的提升了。但是重新来看之前定的2~3小时迁完全部数据的目标,难度还不小。于是我们挑选了前面几个大头任务,逐个目录对里面的数据进行了分析。照理来说,业务的增量数据,占比不会太高,大部分还是老的历史数据。如果我们将业务数据提取拷走,只在最后change的窗口拷贝当天新增数据,就可以达到我们的目标了。
后面经过我们的分析,1000w左右的文件数,我们能实现拷贝走大约一半的数据,最后留另外的5,600w的数据在操作当天迁移走。按照我们在集群中的测试情况来预演,4, 500w的数据大约在1个半小时可以迁移完成,这已经足以达到我们的目标了。
于是最后我们准备了各自filter list列表,通过DistCp的-filter参数到时进行指定即可。
至此,我们的DistCp数据迁移方案算是完整的实战演练了一把,期间经历了1,2个月的反复测试调整。最后希望本文的经验总结能给大家带来帮助和借鉴意义,上面提到的优化改动其实倒不难,关键是要想到点子上。