Skip to content

Commit

Permalink
add cos_migrate_tool_v5
Browse files Browse the repository at this point in the history
  • Loading branch information
chengwu(吴承) committed Apr 3, 2018
0 parents commit c7fd100
Show file tree
Hide file tree
Showing 44 changed files with 4,115 additions and 0 deletions.
29 changes: 29 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 迁移工具

## 功能说明

迁移工具集成了有关COS数据迁移的功能, 目前支持以下四大类迁移
- 本地数据迁移到COS, 功能同之前的本地同步工具
- 友商数据迁移到COS, 目前支持aws s3, 阿里云oss, 七牛存储
- 根据url下载列表进行下载迁移
- COS的bucket数据相互复制, 支持跨账号跨地域的数据复制

## 运行依赖
- JDK1.7或以上, 有关JDK的安装请参考[JAVA安装与配置](https://cloud.tencent.com/document/product/436/10865)
- linux或windows环境, 推荐linux

# 使用范例
1 配置全部通过配置文件读入
sh start_migrate.sh
2 指定部分配置项以命令行为主.
sh start_migrate.sh -DmigrateLocal.localPath=/test_data/aaa/ -Dcommon.cosPath=/aaa
sh start_migrate.sh -DmigrateAws.prefix=/test_data/bbb/ -Dcommon.cosPath=/bbb

## 迁移机制

迁移工具是有状态的,已经迁移成功的会记录在db目录下,以KV的形式存储在leveldb文件中.
每次迁移前对要迁移的路径, 先查找下DB中是否存在, 如果存在,且属性和db中存在的一致, 则跳过迁移, 否则进行迁移。这里的属性根据迁移类型的不同而不同,对于本地迁移,会判断mtime。对于友商与bucket复制,会判断源文件的etag和长度是否与db一致。
因此,我们参照的db中是否有过迁移成功的记录,而不是查找COS,如果绕过了迁移工具,通过别的方式(比如coscmd或者控制台)删除修改了文件,那么运行迁移工具由于不会察觉到这种变化,是不会重新迁移的。

## 其他
请参照COS迁移工具官网文档
117 changes: 117 additions & 0 deletions conf/config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# 配置迁移类型
# 目前支持四大类, 这里的存储类型和之后的分节名称一致
# 1 从本地迁移, migrateLocal(本地迁移工具, 同之前的本地同步工具)
# 2 从友商迁移, migrateAws(从aws迁移), migrateAli(从阿里迁移), migrateQiniu(从七牛迁移),
# 3 从url列表迁移, migrateUrl(这些url都是可以直接下载的,将要迁移的url放到一个文件或者多个文件里)
# 4 COS的bucket复制. migrateBucketCopy(将COS一个bucket下的数据复制到另外一个bucket, 支持跨账号跨地域,前提是账户需要对源bucket源bucket有可读权限,对目的bucket有putObjectCopy权限)
[migrateType]
type=migrateLocal

# 迁移工具的公共配置分节,包含了要迁移到得目的COS的账户信息
[common]
# 用户的秘钥 secret_id (可在 https://console.qcloud.com/capi 查看)
secretId=AKIDXXXXXXXXXXXXXXXXX
# 用户的秘钥 secret_key (可在 https://console.qcloud.com/capi 查看)
secretKey=gcYYYYYYYYYYYYYYYYYYYYYY
# 目的Bucket的名称, 命名规则为{name}-{appid},即bucket名必须包含appid, 例如movie-1251000000
bucketName=mybucket-1251600000
# 目的bucket的region信息. COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
region=ap-guangzhou
# 存储类型, 标准(Standard), 低频(Standard_IA)
storageClass=Standard
# 要迁移到的cos路径, /表示迁移到bucket的根路径下, /aaa/bbb/表示要迁移到bucket的/aaa/bbb/下面, 如果/aaa/bbb/不存在,则会自动建立
cosPath=/
# 是否使用HTTPS传输(传输速度较慢,适用于对传输安全要求高的场景), on开启, off关闭
https=off
#临时目录,用于运行过程中,临时文件的存储, 主要用于友商数据迁移到COS, 因为迁移会现将数据下载到临时目录,再进行上传后删除.对于linux绝对路径, 如/a/b/c, 对于windows绝对路径,注意分隔符为两个反斜杠,如E:\\a\\b\\c
tmpFolder=E:\\code\\java\\workspace\\cos_migrate_tool\\tmp
# 小文件阈值的字节,大于等于这个阈值使用分块上传,否则使用简单上传, 默认5MB
smallFileThreshold=5242880
# 小文件(文件小于smallFileThreshold)的并发度,使用简单上传
smallFileExecutorNum=64
# 大文件(文件大于等于smallFileThreshold)的并发度,使用分块上传
bigFileExecutorNum=8
# 表示迁移工具将全文的MD5计算后,存入文件的自定义头部x-cos-meta-md5中, 用于后续的校验,因为COS的分块上传的大文件的etag不是全文的md5
entireFileMd5Attached=on
# 表示是否启用damon模式,damon表示程序会循环不停的去执行同步,每一轮同步的间隔由damonModeInterVal参数设置
# 如果启用damon模式, 则设置为on, 否则为off
daemonMode=off
# 表示每一轮同步结束后,多久进行下一轮同步,单位为秒
daemonModeInterVal=60


# 从本地迁移到COS配置分节
[migrateLocal]
# 本地路径, 表示将该路径下的数据都迁移到COS, 对于linux绝对路径, 如/a/b/c, 对于windows绝对路径,注意分隔符为两个反斜杠,如E:\\a\\b\\c
localPath=E:\\code\\java\\workspace\\cos_migrate_tool\\test_data
# 要排除的目录或者文件的绝对路径, 表示将localPath下面某些目录或者文件不进行迁移,多个绝对路径之前用分号分割,不填表示localpath下面的全部迁移
exeludes=


## 从阿里迁移到COS的配置分节
[migrateAli]
bucket=mubucket-test
accessKeyId=xxxxxxxxxx
accessKeySecret=yyyyyyyyyyy
#友商的地址
endPoint=oss-cn-shenzhen.aliyuncs.com
# 要迁移的路径的前缀, 如果是迁移bucket下所有的数据, 则prefix为空
prefix=
# 如果要使用代理进行访问,则填写代理IP地址
proxyHost=
# 代理的端口
proxyPort=


# 从七牛迁移到COS
[migrateQiniu]
# 从七牛迁移到COS的配置分节
# 七牛的bucket名称
bucket=assda
# 七牛的账户信息
accessKeyId=xxxxxxxxxx
accessKeySecret=yyyyyyyyyyyyyyyy
# 七牛的下载地址, 对应downloadDomain
endPoint=wwww.bkt.clouddn.com
# 要迁移的路径的前缀, 如果是迁移bucket下所有的数据, 则prefix为空
prefix=
# 如果要使用代理进行访问,则填写代理地址
proxyHost=
# 代理端口
proxyPort=

# 从通过URL列表进行迁移,URL列表里面填写的源文件的下载路径,该路径可以直接下载下来,迁移工具会将其再上传到COS上去
[migrateUrl]
# 使用url列表迁移,如果urllistPath填的是目录,那么就会把这个目录下所有文件都当作urllist文件去扫描迁移
# 对于linux绝对路径, 如/a/b/c, 对于windows绝对路径,注意分隔符为两个反斜杠,如E:\\a\\b\\c
urllistPath=/data/mydata/url

## 从AWS迁移到COS的配置分节
[migrateAws]
# aws的bucket
bucket=aws-emr-test
accessKeyId=xxxxxxxx
accessKeySecret=yyyyyyyyyy
# aws的endpoint地址
endPoint=s3.us-east-1.amazonaws.com
# 要迁移的路径的前缀, 如果是迁移所有的,则prefix为空
prefix=
# 迁移的代理地址
proxyHost=
# 代理端口
proxyPort=

# bucket copy
[migrateBucketCopy]
# 源 bucket的region信息. COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
srcRegion=ap-shanghai
# 源 Bucket的名称, 命名规则为{name}-{appid},即bucket名必须包含appid, 例如movie-1251000000
srcBucketName=mysrcbucket-1251668555
# 源bucket隶属的用户的秘钥 secret_id (可在 https://console.qcloud.com/capi 查看)
# 因为bucket copy支持跨账号,所以如果是另外一个账户的数据,则srcSecretId和common中的secretId不同
# 如果是同一客户的数据, 则srcSecretId和common中的secretId相同
srcSecretId=xxxxxxxxxxx
# 源bucket隶属的用户的秘钥 secret_key(可在 https://console.qcloud.com/capi 查看)
srcSecretKey=yyyyyyyyyyyyyyyy
# 要迁移的cos路径的
srcCosPath=/
Binary file not shown.
12 changes: 12 additions & 0 deletions opbin/rebuild.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
:: 双击运行脚本, 生成的可执行程序在上一层目录的dep下
:: 此脚本用于重新编译生成迁移工具的JAR包
:: 依赖mvn, 请确保网络畅通, 可以连接mvn仓库
@echo off
set cur_dir=%CD%
cd %cur_dir%
cd ..
call mvn clean compile assembly:single
move /Y target\*.jar dep\
rd /s /q target
echo "rebuild over!"
pause>nul
10 changes: 10 additions & 0 deletions opbin/rebuild.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
# 此脚本用于重新编译生成同步的JAR包
# 依赖mvn, 请确保网络畅通, 可以连接mvn仓库
cur_dir=$(cd `dirname $0`;pwd)
cd ${cur_dir}
cd ..
mvn clean compile assembly:single
mv target/*.jar dep/
rm -rf target
cd -
119 changes: 119 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qcloud</groupId>
<artifactId>cos_migrate_tool</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>


<dependencies>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.2.11</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.3.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>happy-dns-java</artifactId>
<version>0.1.4</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.4.2</version>
</dependency>

<dependency>
<groupId>org.ini4j</groupId>
<artifactId>ini4j</artifactId>
<version>0.5.4</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>

<dependency>
<groupId>org.iq80.leveldb</groupId>
<artifactId>leveldb</artifactId>
<version>0.9</version>
</dependency>


<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.4</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.8.3</version>
<exclusions>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.11.271</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>

</exclusions>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.qcloud.cos_migrate_tool.app.App</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
</project>
74 changes: 74 additions & 0 deletions src/main/java/com/qcloud/cos_migrate_tool/app/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.qcloud.cos_migrate_tool.app;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.qcloud.cos_migrate_tool.config.CommonConfig;
import com.qcloud.cos_migrate_tool.config.ConfigParser;
import com.qcloud.cos_migrate_tool.config.CopyBucketConfig;
import com.qcloud.cos_migrate_tool.config.CopyFromAliConfig;
import com.qcloud.cos_migrate_tool.config.CopyFromAwsConfig;
import com.qcloud.cos_migrate_tool.config.CopyFromLocalConfig;
import com.qcloud.cos_migrate_tool.config.CopyFromQiniuConfig;
import com.qcloud.cos_migrate_tool.config.CopyFromUrllistConfig;
import com.qcloud.cos_migrate_tool.config.MigrateType;
import com.qcloud.cos_migrate_tool.meta.TaskStatics;
import com.qcloud.cos_migrate_tool.task.MigrateAliTaskExecutor;
import com.qcloud.cos_migrate_tool.task.MigrateAwsTaskExecutor;
import com.qcloud.cos_migrate_tool.task.MigrateCopyBucketTaskExecutor;
import com.qcloud.cos_migrate_tool.task.MigrateLocalTaskExecutor;
import com.qcloud.cos_migrate_tool.task.MigrateQiniuTaskExecutor;
import com.qcloud.cos_migrate_tool.task.MigrateUrllistTaskExecutor;
import com.qcloud.cos_migrate_tool.task.TaskExecutor;

public class App {

private static final Logger log = LoggerFactory.getLogger(App.class);

private static TaskExecutor buildTaskExecutor(CommonConfig config) {
if (ConfigParser.instance.getMigrateType().equals(MigrateType.MIGRATE_FROM_LOCAL)) {
return new MigrateLocalTaskExecutor((CopyFromLocalConfig) config);
} else if (ConfigParser.instance.getMigrateType().equals(MigrateType.MIGRATE_FROM_ALI)) {
return new MigrateAliTaskExecutor((CopyFromAliConfig) config);
} else if (ConfigParser.instance.getMigrateType().equals(MigrateType.MIGRATE_FROM_AWS)) {
return new MigrateAwsTaskExecutor((CopyFromAwsConfig) config);
} else if (ConfigParser.instance.getMigrateType()
.equals(MigrateType.MIGRATE_FROM_COS_BUCKET_COPY)) {
return new MigrateCopyBucketTaskExecutor((CopyBucketConfig) config);
} else if (ConfigParser.instance.getMigrateType()
.equals(MigrateType.MIGRATE_FROM_URLLIST)) {
return new MigrateUrllistTaskExecutor((CopyFromUrllistConfig) config);
} else if (ConfigParser.instance.getMigrateType().equals(MigrateType.MIGRATE_FROM_QINIU)) {
return new MigrateQiniuTaskExecutor((CopyFromQiniuConfig) config);
} else {
System.out.println("unknown migrate type");
}

return null;
}

public static void main(String[] args) {
if (!ConfigParser.instance.parse()) {
return;
}

CommonConfig config = ConfigParser.instance.getConfig();
while (true) {
TaskStatics.instance.reset();

TaskExecutor taskExecutor = buildTaskExecutor(config);
taskExecutor.run();
taskExecutor.waitTaskOver();

if (!config.isDamonMode())
break;

try {
Thread.sleep(config.getDamonInterVal() * 1000);
} catch (InterruptedException e) {
log.error("the program is interrupted!", e);
break;
}
}
}
}
Loading

0 comments on commit c7fd100

Please sign in to comment.