定义
DistCp 是 Apache Hadoop 发行包中附带的一个命令行工具,其名称来自 distributed copy 的缩写,用于在同一个集群内部或集群之间进行大批量数据复制[1]。它本身并不是一个独立的服务,而是以 MapReduce 作业的形式运行:命令行参数被解析后,工具先列出需要复制的全部路径,再启动一个只含 Map 阶段(有时附带提交阶段)的作业来完成物理拷贝[3]。
第二段在命令行中通常写作 hadoop distcp,源和目标都以带协议头的绝对 URI 表示,例如从 nn1 集群的某个目录写到 nn2 集群的另一个目录[1]。除命令行方式外,DistCp 也可以被程序化调用:通过构造 DistCpOptions 对象并初始化 DistCp 类来启动作业,或对其派生子类以调整行为[3]。
原理
DistCp 的执行分为两个阶段。第一阶段负责生成复制清单:复制列表生成器检查源路径的内容(包括通配符展开),把需要复制的全部路径写入一个 SequenceFile,供后续作业消费[4]。清单生成器有若干实现,例如递归列出目录内容的 SimpleCopyListing、负责展开通配符的 GlobbedCopyListing,以及从指定文件读取源路径列表的 FileBasedCopyListing[4]。
第二阶段由 MapReduce 组件完成实际拷贝。UniformSizeInputFormat 在多个 Map 之间按字节数尽量均衡地切分清单,使每个 Map 复制的数据量大致相等;DynamicInputFormat 则把清单切成数量多于 Map 数的若干块文件,Map 处理完一块后再领取下一块,速度快的数据节点因而可以承担更多数据,从而加快整体作业[5]。真正执行物理拷贝的是 CopyMapper,它在拷贝前会对照作业配置判断文件是否需要复制:目标端不存在同名文件、文件大小不同、校验和不同、指定了覆盖,或需要保留的块大小不一致时才会执行复制[5]。作业结束前的提交阶段由 CopyCommitter 负责,包括按选项保留目录权限、清理临时文件与工作目录等[5]。
从数据流上看,单个文件的复制可以简略表示为源路径经清单生成、按 Map 分片、再经数据通道写入目标路径:
$ \text{源路径列表} \rightarrow \text{复制清单} \rightarrow \text{InputSplit} \rightarrow \text{CopyMapper} \rightarrow \text{目标文件系统} $
需要留意的是,每个文件只由 1 个 Map 处理,文件是当前最小的任务粒度,因此把 Map 数量提高到超过文件数量并不会带来性能收益[6]。
发展历程
DistCp 随 Hadoop 早期版本一同发布,2008 年 12 月发布的 0.18.3 版本文档中已经包含 DistCp 的中文说明,当时它被描述为大规模集群内部和集群之间拷贝的工具,使用 Map/Reduce 实现文件分发、错误处理与恢复以及报告生成[7]。这一代实现通常被称为旧版 DistCp(Legacy DistCp)。
此后 Hadoop 对 DistCp 进行了重写,新版本被称为 DistCp Version 2 或 DistCpV2。重写针对旧版在使用、可扩展性和性能方面的不足,引入了新的组件划分,使工具能够以编程方式使用和扩展,同时默认保留旧版行为[8]。DistCpV2 的驱动类被标注为 Public 与 Evolving,表明它是面向公共使用但仍可能演进的接口[3]。
新旧两版在语义上有若干差别:旧版中跳过不拷贝的文件其属性(权限、属主与属组等)也保持不变,新版即使跳过文件复制也会更新这些属性;旧版不会在目标端创建源路径中的空根目录,新版会创建[6]。在 Map 数量的确定方式上,旧版会在作业启动前先筛选出确实需要复制的文件,再据此决定 Map 数量;新版只计算源路径的内容,把是否跳过的判断推迟到 MapReduce 作业中执行,从而缩短准备时间,但启动的 Map 数量等于 -m 指定的值,未指定时默认为 20[6]。
应用
最常见的用法是集群之间的数据复制,例如把 nn1 集群上的某个目录整体写入 nn2 集群的目标目录;也可以在同一条命令中给出多个源目录,或用 -f 选项从一个文件中读取待复制的源路径列表[1]。DistCp 要求使用绝对路径,并且每个运行 Map 任务的节点都必须能访问源端与目标端文件系统;对 HDFS 而言,两端需要运行相同版本的协议或使用向后兼容的协议[1]。
由于数据量往往很大,DistCp 提供了多个控制类选项。-m 用于指定同时执行拷贝的 Map 数量,但增加 Map 数并不必然提升吞吐量;-bandwidth 用于限制每个拷贝任务的传输带宽,单位为 MB/s;-atomic 可以把实际提交推迟到作业结束,避免中途失败留下部分写入的文件;-delete 通常与 -update 配合,用于删除目标端存在而源端已不存在的文件,实现两端同步;-filters 则接受一个本地文件,其中的正则表达式用于排除不需要复制的路径[9]。
DistCp 不仅能用于 HDFS 之间,也能对接对象存储。官方文档指出它可以与 Amazon S3、Azure ABFS 和 Google GCS 等对象存储配合使用,前提是相应对象存储实现的 JAR 包及其依赖位于类路径上[5]。在云平台上,它也被用于把 HDFS 数据原样复制到云对象存储:由平台自动构造 DistCp 命令、提交到 Hadoop 集群并监控复制状态,从而利用集群自身的算力而非单机运行时[10]。
在跨版本复制方面,官方建议在 Hadoop 不同大版本之间(例如 1.X 与 2.X)使用 WebHdfsFileSystem,因为 WebHDFS 同时支持读和写,DistCp 可以在源集群或目标集群任一端运行;同一大版本之间的复制则使用 hdfs 协议以获得更好性能[5]。
局限
DistCp 的最小工作单元是一个文件,单个文件只能由一个 Map 处理,因此复制包含大量小文件的数据集时,会启动数量庞大的 Map 任务,反而拖慢整体速度,实践中常需要先做小文件合并再迁移[9]。同时,DistCp 需要把源路径下所有文件和目录的清单保存在客户端内存中,当路径数量极大(例如达到百万级)时,可能在生成清单阶段出现内存溢出,官方建议通过调整 JVM 堆大小参数缓解[6]。
异步与一致性方面也存在边界。执行期间如果仍有其他客户端在写入某个源文件,复制很可能失败;尝试覆盖目标端正在被写入的文件在 HDFS 上同样会失败;源文件在复制前被移动或删除,则作业会以文件未找到的异常终止[1]。此外,官方提示 DistCp 同时依赖 MapReduce 和文件系统 API,这三者中任意一环或它们之间的问题都可能悄无声息地影响复制结果,因此建议在复制完成后另行生成并交叉核对源端与目标端的文件列表来验证结果[1]。
功能覆盖范围上,某些选项有明确限制。例如 -diff 依赖快照差异来同步数据,要求源和目标文件系统都是 DistributedFileSystem,在借道 Amazon S3 复制时不受支持[11]。位点同步的语义也需要谨慎理解:-update 并不是同步操作,它判断是否覆盖的唯一依据是源文件与目标文件的大小是否相同,而保留属性的 -p 选项在指定 -update 时不会同步状态更新,除非文件大小也发生变化[1]。
参见
-
HDFS —— DistCp 最主要的源端与目标端文件系统,两者通过协议通信完成复制。
-
MapReduce —— DistCp 借助它把拷贝任务分发给多个 Map 并行执行。
-
Apache Hadoop —— DistCp 所属的开源项目,工具随其发行包一同提供。
-
对象存储 —— DistCp 可对接的存储类型,用于把 HDFS 数据复制到云端。
-
数据迁移 —— DistCp 的典型使用场景,用于集群间或存储系统间的数据搬迁。
参考资料
- DistCp Guide [引用日期2026-10-14]
- Hadoop DistCp - Alibaba Cloud - Search for Help Content [引用日期2026-10-14]
- Class DistCp [引用日期2026-10-14]
- Apache Hadoop Distributed Copy [引用日期2026-10-14]
- Apache Hadoop Distributed Copy [引用日期2026-10-14]
- Apache Hadoop Distributed Copy [引用日期2026-10-14]
- DistCp [引用日期2026-10-14]
- Apache Hadoop Distributed Copy [引用日期2026-10-14]
- Running the DistCp Command — MapReduce Service [引用日期2026-10-14]
- connector-hdfs [引用日期2026-10-14]
- Using DistCp with Highly Available Remote Clusters [引用日期2026-10-14]