简介
FastCopy 是 Hadoop 的一个 patch,目的是加速 Federation 数据的迁移速度。采用了 hardLink 的方式实现,相比 distcp,几乎不需要做 数据拷贝和搬移。
关键代码梳理
-
在 ClientDatanodeProtocol 协议里新增加一个 copyBlock 方法
-
DataNode 类对该方法做了具体实现,支持了两种拷贝方式:
- LocalBlockCopy (hardLink)
(1)设置 targetBlk 大小 = srcBlk numBytes
(2)做 hardLink
<1> 检查 srcBlk 磁盘是否可容下 targetBlk
<2> 获取 srcBlk 同一个磁盘下的 bp 目录对
<3> ${bpDir}/ tmp 目录下 hardLink meta 和 blk 文件
<4> 把 tmp 下的 blk 和 meta 文件,移动到 finalized 目录下
<5> 生成 FinalizedReplica,记录到 Map<bpId, <blkId, ReplicaInfo>> volumeMap 里 - DataCopy(支持不同 DN 之间做数据 copy)
- LocalBlockCopy (hardLink)
-
FastCopy 类是入口类,执行流程:
(1)解析 args,找到源目录下的所有文件保存在 List srcs 中,并返回 dst, 如果检测到空目录,会自动在 dst 中创建
(2)对(1)中得到的 List srcs,依次创建 FastFileCopyRequest 请求
(3)把 FastFileCopyRequest 提交到线程池中执行 copy
(4)copy 是核心方法
<1> 获取 src 文件所有的 blks (注意:会 skip UC 文件)
<2>在 dst namenode 上,参照 src 文件的 meta 信息,创建一个 一样的空文件<3> 目标 dstNN 上 addBlock
<4> 创建 BlockCopyRPC 提交到线程池执行。线程内部调用 ClientDatanodeProtocol 的 copyBlock 实现 fastcopy。虽然 <3>中 addBlock 传入了 favoredNodes,但是 dstBlk 的副本节点不一定是这批机器,因此,这里先做了一个对齐操作(相同 DN 上进行 LocalBlockCopy,不同的 DN 上走 DataCopy),每个副本对应一个同步线程
<5> 等待该 blk 拷贝完成,再处理下一个 blk 。所有 blk 执行完,执行 dstNN 的 complete 方法收尾。
踩坑记录:
在线上使用的时候,也发现了一些 bug。
1. 如果输入源是空目录,导致的 IndexOutOfBoundsException
Fix: 检测到 src 是目录,直接 skip。
2.源路径下的空文件夹,不会被同步
Fix:在目标 Fs 上 创建出空目录
注:这块改动虽小,但是要考虑到实际的业务使用情况。例如:有些业务会用空目录作为任务进度的 tag 标记,此时就需要 mkdir 出来。
3.DN 磁盘 remaining 不足,大量并发 FastCopy 失败
在 NN 和 DN 端有两处限制:
(1)NN 端: chooseTarget 选择 DN 的时候,会对选出的 DN 进行检查 isGoodTarget 检查:storage 类型一致,状态 NORMAL,节点是否下线/stale,容量,负载等
(2)DN 端:hardLink 时,也会检查对应的磁盘空间是否足够
首先,hardLink 空间消耗不大,其次,因为集群整体水位线偏高,有不少 remaining 很小的 DN,因此在大量并发 FastCopy 的时候,会出现这个问题。因此,针对 FastCopy功能,取消了这两处限制。
注:这个改动,要根据集群实际情况,项目进度等等因素综合考量(默认不推荐)
其他
FastCopy 和 DistCp 这种同步任务 同步超大目录,会很慢而且可能因为大量 list,造成慢 RPC。
为了方便管理,可以开发一个简单的任务调度平台
1. 同步需求入到数据库 DB
2. 调度 Server 拉取任务,启动 Worker 进行调度
3. Worker 更新任务进度和状态,回写数据库
4. 基于 DB 中的状态和进度信息,进行监控/报警