hadoop中有一个叫做distcp(分布式复制)的有用程序,能从hadoop的文件系统并行复制大量数据。

distcp一般用于在两个HDFS集群中传输数据。如果集群在hadoop的同一版本上运行,就适合使用hdfs方案:

   % hadoop distcp hdfs://namenode1/foo hdfs://namenode2/bar 
这将从第一个集群中复制/foo目录(和它的内容)到第二个集群中的/bar目录下,所以第二个集群会有/bar/foo目录结构。如果/bar不存在,则会新建一个。可以指定多个源路径,并且所有的都会被复制到目标路径。源路径必须是绝对路径。

默认情况下,distcp会跳过目标路径已经有的文件,但可以通过提供的-overwrite选项进行覆盖,也可以用-update选项来选择只更新那些修改过的文件。

 

第一个集群的子树/foo下的一个文件与第二个集群的改变进行同步。

% hadoop distcp -update hdfs://namenode1/foo hdfs://namenode2/bar/foo 
distcp是作为一个MapReduce作业执行的,复制工作由集群中并行运行的map来完成。这里没有reducer。每个文件都由一个单一的map进行复制,并且distcp通过将文件分成大致相等的文件来为每个map数量大致相同的数据。

map的数量确定:

通过让每一个map复制数量合理的数据以最小化任务建立所涉及的开销,是一个很好的想法,所以每个map的副本至少为256MB。例如,1GB的文件被分成4个map任务。如果数据很大,为限制带宽和集群的使用而限制映射的数据就变得很有必要。map默认的最大数量是每个集群节点(tasktracker)有20个。例如,复制1000GB的文件到一个100个节点的集群,会分配2000个map(每个节点20个map),所以平均每个会复制512MB。通过对distcp指定-m参数,会减少映射的分配数量。例如,-m 1000会分配1000个map,平均每个复制1GB。

如果想在两个运行着不同版本HDFS的集群上利用distcp,使用hdfs协议是会失败的,因为RPC系统是不兼容的。想要弥补这种情况,可以使用基于HTTP的HFTP文件系统从源中进行读取。这个作业必须运行在目标集群上,使得HDFS RPC版本是兼容的。使用HFTP重复前面的例子:% hadoop distcp hftp://namenode1:50070/foo hdfs://namenode2/bar 

注意,需要在URI源中指定名称节点的Web端口。这是由dfs.http.address的属性决定的,默认值为50070。

保持HDFS集群的平衡

最好首先就用默认的每个节点20个map这个默认设置来运行distcp。

然而,这也并不总能阻止一个集群变得不平衡。也许想限制map的数量以便一些节点可以被其他作业使用。若是这样,可以使用balancer工具继续改善集群中块的分布。

distcp主要用于在hadoop集群之间拷贝数据。

1,如果haboop版本相同,可以使用如下格式

hadoop distcp hdfs://<hdfs_address:hdfs_port>/src hdfs://<hdfs address:port>/des

2, 如果在不同版本的hadoop集群之间拷贝数据,可以使用如下格式

hadoop distcp -i hftp://<hdfs_address:http_port>>/src hdfs://<hdfs address:port>/des

注意,这个时候,需要在目标集群上运行distcp, -i是忽略错误。

注意hftp和ftp没有什么关系,它是通过http访问hdfs文件系统的协议包装,以支持不同版本之间拷贝数据。它的端口,不是dfs端口,而是http端口。

在我的应用中,一个是hadoop1.0.0集群,一个是cloudera cdh3u0集群,此时需要将hadoop1.0.0里面的数据拷贝到cloudera cdh3u0的hdfs中。因此采用hftp的distcp。

更进一步,如果只是造无逻辑关系的数据,distcp没有只写的teragen或slive快。在我的测试中,teragen和slive的混合写入,磁盘写入速度可以达到300MB/s,网络io可以达到100+MB/s。而distcp,磁盘写入为100MB/s,网络io也达到100+MB/s。