distcp流程分析

本文详细解析了DistCp在Hadoop集群间高效复制数据的原理与流程,包括shell使用、源码分析、元数据生成等关键环节。

背景

distcp可用于跨集群或集群内目录的复制,distcp参数不同复制的结果差别较大。本文结合官网及源码,对distcp流程进行分析,并结合测试给出验证。

使用

1. shell

目标目录父目录不存在时,可以自动建立多层目标目录。

1. 文件复制

文件复制时,相当于cp,因为hdfs无法并行写。将a.txt复制并重命令为a_bak.txt

$ hadoop distcp \
hdfs://cluster-host1:9000/v2-ec-source/2019/07/02/_SUCCESS \
hdfs://10.179.25.59:9000/v2-ec-source/2019/07/02/_SUCCESS_bak
2. 文件夹复制

distcp主要为复制文件夹服务。一个文件只能分配到一个map。因此,在文件夹中有多个文件时,可以发挥并行优势。

$ hadoop distcp \
hdfs://cluster-host1:9000/v2-ec-source/2019/07/02 \
hdfs://10.179.25.59:9000/v2-ec-source/2019/bak

将02下的所有文件,复制到bak目录下。

多文件夹复制

将多个文件夹复制到目标文件夹下,并且多个文件夹最后一个文件夹名保留。

$ hadoop distcp \
hdfs://cluster-host1:9000/v2-ec-source/2019/06 \
hdfs://cluster-host1:9000/v2-ec-source/2019/07 \
hdfs://10.179.25.59:9000/v2-ec-source/2019/mult

目标文件夹结果:

$ hadoop fs -ls /v2-ec-source/2019/mult
... 2019-10-23 20:44 /v2-ec-source/2019/mult/06
... 2019-10-23 20:44 /v2-ec-source/2019/mult/07

当从多个源拷贝时,如果两个源冲突,DistCp会停止拷贝并提示出错信息, 如果在目的位置发生冲突,会根据选项设置解决。 默认情况会跳过已经存在的目标文件(比如不用源文件做替换操作)。每次操作结束时都会报告跳过的文件数目,但是如果某些拷贝操作失败了,但在之后的尝试成功了。

值得注意的是,当另一个客户端同时在向源文件写入时,拷贝很有可能会失败。 尝试覆盖HDFS上正在被写入的文件的操作也会失败。 如果一个源文件在拷贝之前被移动或删除了,拷贝失败同时输出异常 FileNotFoundException。

2. distcp源码分析

1.shell入口:

hadoop-common-project/hadoop-common/src/main/bin下以hadoop文件为入口:

...
    elif [ "$COMMAND" = "distcp" ] ; then
      CLASS=org.apache.hadoop.tools.DistCp
      CLASSPATH=${CLASSPATH}:${TOOL_PATH}
...
	# Always respect HADOOP_OPTS and HADOOP_CLIENT_OPTS
    HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"

    #make sure security appender is turned off
    HADOOP_OPTS="$HADOOP_OPTS -Dhadoop.security.logger=${HADOOP_SECURITY_LOGGER:-INFO,NullAppender}"

    export CLASSPATH=$CLASSPATH
    exec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS $CLASS "$@"
    ;;

进入 org.apache.hadoop.tools.DistCp
我们看到Distcp是一个ToolToolRunner应用(如果不熟悉hadoop的ToolRunner模式,请参看本博客ToolRunner文章)。Tool应用要求实现run方法,如下:

public class DistCp extends Configured implements Tool {
   
   
  ...
  // Tool应用必须的run方法
  @Override
  public int run(String[] argv) {
   
   
    // 下文具体分析时给出源码
  }
  
  // main方法,也是shell的入口
  public static void main(String argv[]) {
   
   
    int exitCode;
    try {
   
   
      DistCp distCp = new DistCp();
      Cleanup CLEANUP = new Cleanup(distCp);

      ShutdownHookManager.get().addShutdownHook(CLEANUP,
        SHUTDOWN_HOOK_PRIORITY);
      exitCode = ToolRunner.run(getDefaultConf(), distCp, argv);
    }
    catch (Exception e) {
   
   
      LOG.error("Couldn't complete DistCp operation: ", e);
      exitCode = DistCpConstants.UNKNOWN_ERROR;
    }
    System.exit(exitCode);
  }
}
准备工作

我们从main函数入手,先看main的准备工作。

  1. 构造器
  2. cleanup:
  private static class Cleanup implements Runnable {
   
   
    private final DistCp distCp;

    Cleanup(DistCp distCp) {
   
   
      this.distCp = distCp;
    }

    @Override
    public void run() {
   
   
      if (distCp.isSubmitted()) return;

      distCp.cleanup();
    }
  }
...
  // 清理方法
  private synchronized void cleanup() {
   
   
    try {
   
   
      if (metaFolder == null) return;

      jobFS.delete(metaFolder, true);
      metaFolder = null;
    } catch (IOException e) {
   
   
      LOG.error("Unable to cleanup meta folder: " + metaFolder, e);
    }
  }

如果distcp实例未提交任务,则删除metaFolder,并另metaFolder = null
至于metaFolder作用,下文分析。

  1. ShutdownHookManager工具类(可参看其他文章)。
执行

disctp使用ToolRunner.run执行任务。

      exitCode = ToolRunner.run(getDefaultConf(), distCp, argv);

我们回到run方法中。

 @Override
  public int run(String[] argv) {
   
   
    if (argv.length < 1) {
   
   
      OptionsParser.usage();
      return DistCpConstants.INVALID_ARGUMENT;
    }
    
    try {
   
   
      inputOptions = (OptionsParser.parse(argv));
      setTargetPathExists();
      LOG.info("Input Options: " + inputOptions);
    } catch (Throwable e) {
   
   
      LOG.error("Invalid arguments: ", e);
      System.err.println("Invalid arguments: " + e.getMessage(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值