hdfs跨集群数据迁移

顺便附上官网地址。

http://hadoop.apache.org/docs/r1.0.4/cn/distcp.html

需求

老集群中的HDFS数据迁移至新集群。

迁移之前需要考虑的事情

1、迁移总数据量有多少?
2、新老集群之间的带宽有多少?能否全部用完?为了减少对线上其他业务的影响最多可使用多少带宽?
3、如何限制迁移过程中使用的带宽?
4、迁移过程中,哪些文件可能发生删除,新增数据的情况?哪些目录可能会发生新增文件的情况?
5、迁移后的数据一致性校验怎么做?
6、迁移后的HDFS文件权限如何跟老集群保持一致?

迁移方案

1、迁移数据量评估。
通过hdfs dfs -du -h /命令查看各目录总数据量。按业务划分,统计各业务数据总量。
2、制定迁移节奏。
由于数据量大,带宽有限,HDFS中的文件每天随业务不断变化,所以在文件变化之前全部迁移完成是不现实的。建议按业务、分目录、分批迁移
3、迁移工具选择。
使用Hadoop自带数据迁移工具Distcp,只需要简单的命令即可完成数据迁移。
命令示意:hadoop distcp hdfs://nn1:8020/data hdfs://nn2:8020/4、迁移时间评估。
由于老集群每天仍然在使用,为了减小对线上业务的影响,尽量选择老集群低负载运行的时间段来进行数据迁移。
5、对新老集群之间的网络进行硬件改造。
咨询运维同学,新老集群之间的最大传输带宽是多少,如果带宽跑满的话会不会影响线上其他业务。
能否对新老集群之间的网络进行硬件改造,例如通过新老集群之间搭网线的方式来提升网络传输的带宽并消除对其他线上业务的影响。
6、数据迁移状况评估。
在完成上面所有准备之后,先尝试进行小数据量的迁移,可以先进行100G的数据迁移、500G的数据迁移、1T的数据迁移,以评估数据迁移速率并收集迁移过程中遇到的问题。

迁移工具Distcp

工具使用很简单,只需要执行简单的命令即可开始数据迁移,可选参数如下:
hadoop distcp 源HDFS文件路径 目标HDFS文件路径hadoop distcp hdfs://nn1:8020/data hdfs://nn2:8020/

root@ ~ # hadoop distcp
usage: distcp OPTIONS [source_path...] <target_path>
              OPTIONS
 -append                       Reuse existing data in target files and
                               append new data to them if possible
 -async                        Should distcp execution be blocking
 -atomic                       Commit all changes or none
 -bandwidth <arg>              Specify bandwidth per map in MB
 -blocksperchunk <arg>         If set to a positive value, fileswith more
                               blocks than this value will be split into
                               chunks of <blocksperchunk> blocks to be
                               transferred in parallel, and reassembled on
                               the destination. By default,
                               <blocksperchunk> is 0 and the files will be
                               transmitted in their entirety without
                               splitting. This switch is only applicable
                               when the source file system implements
                               getBlockLocations method and the target
                               file system implements concat method
 -delete                       Delete from target, files missing in source
 -diff <arg>                   Use snapshot diff report to identify the
                               difference between source and target
 -f <arg>                      List of files that need to be copied
 -filelimit <arg>              (Deprecated!) Limit number of files copied
                               to <= n
 -filters <arg>                The path to a file containing a list of
                               strings for paths to be excluded from the
                               copy.
 -i                            Ignore failures during copy
 -log <arg>                    Folder on DFS where distcp execution logs
                               are saved
 -m <arg>                      Max number of concurrent maps to use for
                               copy
 -mapredSslConf <arg>          Configuration for ssl config file, to use
                               with hftps://. Must be in the classpath.
 -numListstatusThreads <arg>   Number of threads to use for building file
                               listing (max 40).
 -overwrite                    Choose to overwrite target files
                               unconditionally, even if they exist.
 -p <arg>                      preserve status (rbugpcaxt)(replication,
                               block-size, user, group, permission,
                               checksum-type, ACL, XATTR, timestamps). If
                               -p is specified with no <arg>, then
                               preserves replication, block size, user,
                               group, permission, checksum type and
                               timestamps. raw.* xattrs are preserved when
                               both the source and destination paths are
                               in the /.reserved/raw hierarchy (HDFS
                               only). raw.* xattrpreservation is
                               independent of the -p flag. Refer to the
                               DistCp documentation for more details.
 -rdiff <arg>                  Use target snapshot diff report to identify
                               changes made on target
 -sizelimit <arg>              (Deprecated!) Limit number of files copied
                               to <= n bytes
 -skipcrccheck                 Whether to skip CRC checks between source
                               and target paths.
 -strategy <arg>               Copy strategy to use. Default is dividing
                               work based on file sizes
 -tmp <arg>                    Intermediate work path to be used for
                               atomic commit
 -update                       Update target, copying only missingfiles or
                               directories

1、Distcp的原理是什么?
Distcp的本质是一个MapReduce任务,只有Map阶段,没有Reduce阶段,具备分布式执行的特性。在Map任务中从老集群读取数据,然后写入新集群,以此来完成数据迁移。

// org.apache.hadoop.tools.DistCp#main
// org.apache.hadoop.tools.DistCp#run
// org.apache.hadoop.tools.DistCp#execute

/**
 * Implements the core-execution. Creates the file-list for copy,
 * and launches the Hadoop-job, to do the copy.
 * @return Job handle
 * @throws Exception
 */
public Job execute() throws Exception {
  Job job = createAndSubmitJob();

  if (inputOptions.shouldBlock()) {
    waitForJobCompletion(job);
  }
  return job;
}
/**
 * Create Job object for submitting it, with all the configuration
 *
 * @return Reference to job object.
 * @throws IOException - Exception if any
 */
private Job createJob() throws IOException {
  String jobName = "distcp";
  String userChosenName = getConf().get(JobContext.JOB_NAME);
  if (userChosenName != null)
    jobName += ": " + userChosenName;
  Job job = Job.getInstance(getConf());
  job.setJobName(jobName);
  job.setInputFormatClass(DistCpUtils.getStrategy(getConf(), inputOptions));
  job.setJarByClass(CopyMapper.class);
  configureOutputFormat(job);

  job.setMapperClass(CopyMapper.class);
  // 无reduce阶段
  job.setNumReduceTasks(0);
  job.setMapOutputKeyClass(Text.class);
  job.setMapOutputValueClass(Text.class);
  job.setOutputFormatClass(CopyOutputFormat.class);
  job.getConfiguration().set(JobContext.MAP_SPECULATIVE, "false");
  job.getConfiguration().set(JobContext.NUM_MAPS,
                String.valueOf(inputOptions.getMaxMaps()));

  if (inputOptions.getSslConfigurationFile() != null) {
    setupSSLConfig(job);
  }

  inputOptions.appendToConf(job.getConfiguration());
  return job;
}

2、迁移期间新老两个集群的资源消耗是怎样的?
Distcp是一个MapReduce任务,如果在新集群上执行就向新集群的Yarn申请资源,老集群只有数据读取和网络传输的消耗。
3、如何提高数据迁移速度?
Distcp提供了 -m <arg>参数来设置map任务的最大数量(默认20),以提高并发性。注意这里要结合最大网络传输速率来设置。
4、带宽如何限制?
Distcp提供了-bandwidth <arg> 参数来控制单个Map任务的最大带宽,单位是MB。

限速原理如下:

// org.apache.hadoop.tools.util.ThrottledInputStream#read()

public int read() throws IOException {
  // 每次从源HDFS读取数据的时候,会进行限速
  throttle();
  int data = rawStream.read();
  if (data != -1) {
    bytesRead++;
  }
  return data;
}

private void throttle() throws IOException {
   // getBytesPerSec()获取上次读取和此次读取这段时间内的速率(byte/s)与限速值作比较
   while (getBytesPerSec() > maxBytesPerSec) {
      try {
        // 如果超速了则sleep一段时间
        Thread.sleep(SLEEP_DURATION_MS);
        totalSleepTime += SLEEP_DURATION_MS;
      } catch (InterruptedException e) {
        throw new IOException("Thread aborted", e);
      }
   }
}

5、迁移之后的数据一致性怎么校验?
Distcp负责进行CRC校验,可以通过-skipcrccheck参数来跳过校验来提供性能。
6、迁移之后的文件权限是怎样的?
Distcp提供了-p <arg>参数来在新集群里保留状态(rbugpcaxt)(复制,块大小,用户,组,权限,校验和类型,ACL,XATTR,时间戳)。如果没有指定-p <arg>参数,权限是执行MapReduce任务的用户权限,迁移完成以后需要手动执行chown命令变更。
7、迁移的过程中老集群目录新增了文件,删除了文件怎么办?
把握好迁移节奏,尽量避免这些情况的出现。Distcp在任务启动的时候就会将需要copy的文件列表从源HDFS读取出来。如果迁移期间新增了文件,新增的文件会被漏掉。删除文件会导致改文件copy失败,可以通过 -i参数忽略失败。
8、迁移中遇到文件已存在的情况怎么办?
Distcp提供了-overwrite 参数来覆盖已存在的文件。
9、迁移了一半,任务失败了怎么办?
删除掉新集群中的脏数据,重新执行迁移命令。不加-overwrite参数,来跳过已存在的文件。
10、遇到需要对一个文件增量同步怎么办?
Distcp提供-append参数将源HDFS文件的数据新增进去而不是覆盖它。

总结

上面说了那么多,在实际的迁移工作中肯定还会遇到没有考虑到的问题。做好前期的准备工作,利用DistCp的工具配合自己的解决方案才能顺利的完成数据迁移任务。