方案的选择
最近有一大批文件需要迁移,从 AWS S3 US region 到某国某 IDC 。文件数量千万级,大小几个 TB 。由于都是小文件,考虑到时间成本,最早想到的是 AWS 的 Snowball ,但是发现 AWS Snowball 不支持跨国甚至跨 region 快递,只好放弃。
AWS 的 Snowball 的原理是用本地高速局域网将文件转存到一台带存储的电脑上,然后邮寄电脑,再将数据通过本地高速局域网导入到目标机器。
AWS S3 有传输加速功能,但是由于历史原因这个功能无法打开。因为 bucket name 包含 _ 字符。因为 S3 最早的时候并没有考虑到要加 CDN 和数据传输加速功能,命名规则很宽松。但是现在新建 bucket 只能按域名的规则命名,为的就是兼容其他组件。
AWS S3 有自动跨域同步功能,比如从 S3 US region 到 S3 EU region 。但是这个功能只支持新建文件。
然后尝试在 EC2 上进行 S3 手动跨域同步,但是速度跟直接在目标 IDC 机房机器上执行差不多,所以放弃这个方案。
这里只能用最笨的办法解决,从命令使用方式上找到最快的方法。
s3cmd 是最稳定的 S3 客户端
s3cmd 是最常用的 S3 客户端,是一个 Python 写的小程序,数据同步最常用命令:
s3cmd sync s3://bucket/folder /localpath/bucket/folder -v --skip-existing
这条命令适用于小量文件的镜像同步。或者最终的数据镜像校验。它的执行过程是先扫描本地文件夹的文件列表,存储在内存中;然后从远程文件夹获取文件夹下的文件列表和文件的 meta 信息;然后对比差异开始逐个文件的下载。这里的问题是千万级别的本地文件 meta 信息的扫描、S3 上文件列表和 meta 信息的传送都会耗时很久。假如中途进程中断,整个过程会重新开始。并且非常耗费 CPU 资源。
s3cmd get -r --skip-existing s3://bucket/folder /localpath/bucket/folder
这条命令直接从远程 S3 获取文件进行下载,但是不提供数据校验。速度很快,瓶颈在网络 IO 上。
尽管有很多多线程的 S3 客户端工具,但是在尝试之后 s3cmd 仍然是最好的选择,原因是更加稳定,功能完善,考虑到了很多边界问题。但是小文件传输 s3cmd 单进程成为瓶颈,并不能充分利用带宽和机器资源。单个进程的同步速度只有几十 KB/s 。
可以手动启用多个 s3cmd 进程,并行同步多个子文件夹,在 screen 或者 tmux 上执行。
假如数据的文件夹结构是按日期划分,这个脚本也许有用:
#!/bin/bash
trap ctrl_c INT
function ctrl_c() {
exit $?
}
currentdate=$1
loopenddate=$(/bin/date --date "$2 1 day" +%Y%m%d)
until [ "$currentdate" == "$loopenddate" ]
do
echo $currentdate
s3cmd get -r --skip-existing s3://bucket/folder/$currentdate /localpath/bucket/folder
currentdate=$(/bin/date --date "$currentdate 1 day" +%Y%m%d)
done
最终的方案是结合之前的两条命令和文件夹结构用脚本完成数据同步。
并发情况下 DNS 成为瓶颈之一
配置一个稳定的 DNS 服务,比如 Google DNS 8.8.8.8 。即使这样仍然有时会出现 name cannot be resolved 类的 DNS 解析错误。通过流量监控,可以看到 DNS 解析的流量会达到几十 KB/s 。
并发情况下错误很常见
S3 的外部接口是 HTTP 协议。并发量大以后错误会非常常见,经常会出现 500 错误,但是 s3cmd 内置了重试策略,文件下载失败会等待几秒后重试。
另外,S3 限制了单连接传输文件的个数,达到阈值后会自动断开连接,s3cmd 已经做了处理。
附加几个用得到的命令
网卡使用率和流量监控:
iftop -B
多个网卡的话:
iftop -B -i eth0
磁盘使用率监控:
iostat -xm 1
运维帮「运维大咖CLUB」招募会员:如果你是甲方运维总监/运维经理,欢迎加入我们,请联系微信yunweibang555
商务合作,请加微信yunweibang555