i### 1. rsync的缺陷
sync是以字节为单位进行传输的迁移工具。它的缺陷,一方面:传输large
或者deep
为特征的数据时,它通常会先list
所有的文件再进行传输,list
时间可能耗费很长时间然后再进行真正的传输。另一方面:rsync即使在高速的网络上也仅占用少用的带宽传输。尽管,可以启动多个rsync进程来完善。但启动多个rsync也可能造成系统过载。
2. 利用parallel来提升迁移速率
# parallel -j {number} number用来限制rsync的最多启动数量
find -L -type f | parallel -j 8 -v rsync -razHXSR --ignore-errors --stats --info=progress2 --delete {} /目的端地址
缺点:从命令中分析,缺陷比较明显。在目录结构比较复杂的情况下,find命令耗时可能会特别长。
3. 利用fpart切分目录结构
fpart
是一种开源的第三方工具,用来对文件树进行排序并将其打包到袋子中。它将目录和文件树的列表划分为一定的数量,然后生成具有相同大小和文件数量的分区。
生成后,分区将作为文件列表打印到标准输出(默认)或者文件中,然后交由第三方工具处理。
-
fpart
包括实时模式,此模式允许其爬非常大的文件系统并且实时生成分区。可以使用挂钩对这些分区执行操作,立即使用rsync
或者cpio
启动传输,而不必等待文件系 统遍历作业完成。通过此方式,fpart
被视为数据迁移工具的强大基础。 -
fpart
还可以生成目录列表,而不是文件列表。
3.1 fpart工具的安装
yum install -y fpart
github地址
fpart 的官方地址 https://github.com/martymac/fpart
3.2 Example
- 利用
fpart
将待分区目录,打包为**3个总大小近似且文件数量近似的3个包。**3个包文件类似为"var-parts.[0-2]",并且产生输出文件output:
# 1. 待区分的目录结构
$ ll
total 164
drwxr-xr-x 13 root root 4096 Jul 30 23:23 braft
drwxr-xr-x 14 root root 4096 Jul 25 10:22 BRPC
drwxr-xr-x 4 root root 4096 Jul 15 20:38 celery
drwxr-xr-x 6 root root 4096 Aug 6 17:59 flask
drwxr-xr-x 8 root root 4096 Jul 20 08:14 gflags-master
drwxr-xr-x 8 root root 4096 Aug 5 14:25 gunicorn
-rw-r--r-- 1 root root 123955 Jul 20 08:14 master.zip
-rw------- 1 root root 0 Jul 30 17:48 nohup.out
drwxr-xr-x 10 root root 4096 Aug 10 15:58 python
drwxr-xr-x 3 root root 4096 Jul 13 18:17 SaltStack
drwxr-xr-x 7 root root 4096 Nov 27 19:17 workspace
# 2. 执行分包
$ fpart -n 3 -o var-parts /root/
Part #0: size = 346723836, 3898 file(s)
Part #1: size = 346723836, 3897 file(s)
Part #2: size = 346723836, 3897 file(s)
# 3. 查看区分后的文件
$ head -n 3 var-parts.0
/root/flask/myproject/stor/demo.pyc
/root/flask/myproject/stor/config.pyc
/root/flask/myproject/stor/globalvar.pyc
$ head -n 3 var-parts.1
/root/flask/myproject/stor/webapi.pyc
/root/flask/myproject/stor/.cache.py.swp
/root/flask/myproject/stor/globalvar.py
$ head -n 3 var-parts.2
/root/flask/myproject/stor/consumer.py
/root/flask/myproject/stor/consumer.pyc
/root/flask/myproject/stor/producer.pyc
- 将
root
下文件按照100M
大小进行分包。
$ fpart -s 102400000 -o 100M /root/
Part #0: size = 208902770, 1 file(s)
Part #1: size = 102400000, 1642 file(s)
Part #2: size = 102400000, 524 file(s)
Part #3: size = 102399999, 586 file(s)
Part #4: size = 102400000, 2256 file(s)
Part #5: size = 102399990, 2625 file(s)
Part #6: size = 102399999, 1752 file(s)
Part #7: size = 102399969, 1769 file(s)
Part #8: size = 68844076, 536 file(s)
Part #9: size = 45626872, 1 file(s)
$ ls
100M.0 100M.1 100M.2 100M.3 100M.4 100M.5 100M.6 100M.7 100M.8 100M.9
- 将
root
下文件按照1000个数量进行分包
$ find /root/ ! -type d | fpart -f 1000 -i - /root/ -o var-parts
Part #0: size = 56583042, 1000 file(s)
Part #1: size = 121092082, 1000 file(s)
Part #2: size = 355852324, 1000 file(s)
Part #3: size = 13442578, 1000 file(s)
Part #4: size = 82014917, 1000 file(s)
Part #5: size = 48615679, 1000 file(s)
Part #6: size = 59926636, 1000 file(s)
Part #7: size = 48890520, 1000 file(s)
Part #8: size = 57121118, 1000 file(s)
Part #9: size = 47201896, 1000 file(s)
Part #10: size = 58390103, 1000 file(s)
Part #11: size = 118222132, 1000 file(s)
Part #12: size = 64489337, 1000 file(s)
Part #13: size = 185003560, 1000 file(s)
Part #14: size = 261405448, 1000 file(s)
Part #15: size = 13627913, 1000 file(s)
Part #16: size = 80378519, 1000 file(s)
Part #17: size = 47155863, 1000 file(s)
Part #18: size = 60528540, 1000 file(s)
Part #19: size = 48019656, 1000 file(s)
Part #20: size = 86989632, 1000 file(s)
Part #21: size = 18283251, 1000 file(s)
Part #22: size = 98593740, 1000 file(s)
Part #23: size = 48521474, 384 file(s)
$ ls
var-parts.0 var-parts.10 var-parts.12 var-parts.14 var-parts.16 var-parts.18 var-parts.2 var-parts.21 var-parts.23 var-parts.4 var-parts.6 var-parts.8
var-parts.1 var-parts.11 var-parts.13 var-parts.15 var-parts.17 var-parts.19 var-parts.20 var-parts.22 var-parts.3 var-parts.5 var-parts.7 var-parts.9
- 对
du
检测出来的文件,进行重新排序。
$ du * | fpart -n 2 -a -o du
Part #0: size = 1192, 12 file(s)
Part #1: size = 1168, 12 file(s)
3.3 Live Mode 实时模式
默认情况下,在遍历完成FS
后fpart
才能生成和显示分区结果。如果使用实时模式(选项-L),则fpart
将在完成分区后立即显示每个分区。由此可以将此选项与HOOKS
结合使用,它们将在分区完成之前或者之后触发。
HOOKS
提供了几个环境变量(fpart)
:1. 获取有关fpart
和分区当前状态信息的便捷方法。例如: ${FPART_PARTFILENAME}
将包含刚生成的分区的输出文件的名称;在post-part
中使用该变量允许在分区生成后立即开始处理文件。
实时读取5个文件
example
# 向待打包目录中拷贝文件
$ cp /var/lib/ . -p
# 实时读取5个文件
$ fpart -L -f 5 -o ./mode-parts -W 'echo == ${FPART_PARTFILENAME} == ; cat ${FPART_PARTFILENAME}' ./tmp
== /root/var-parts/./mode-parts.0 ==
./tmp/lib/authconfig/last/authconfig
./tmp/lib/authconfig/last/login.defs
./tmp/lib/authconfig/last/libuser.conf
./tmp/lib/authconfig/last/openldap.conf
./tmp/lib/containerd/io.containerd.metadata.v1.bolt/meta.db
== /root/var-parts/./mode-parts.1 ==
./tmp/lib/yum/uuid
...
./tmp/lib/cloud/data/result.json
== /root/var-parts/./mode-parts.1860 ==
./tmp/lib/cloud/scripts/per-boot/TencentCloudRun.sh
这个示例以实时模式(选项-L)对./tmp文件进行遍历。对于每个文件(选项-f,每个分区5个文件),它将在当前目录下./mode-parts
中每5个文件生成一个分区。(选项-o
;是分区索引,并且将由fpart
自动添加)并执行以下后期部分挂钩(选项-W):
echo == ${FPART_PARTFILENAME} == ; cat ${FPART_PARTFILENAME}
这个钩子将显示当前分区的输出文件名以及其内容。
3.4 迁移工具
利用fpart
工具,GNU Parallel
和Rsync
拆分目录,并且在进行FS
遍历时立即完成较小文件列表的数据同步。例如,将数据从/mnt/Rsync-source
同步到/mnt/Rsync-dest
目录下。
fpart -L -f 10000 -x '.snapshot' -x '.zfs' -zz -o /tmp/part.out -W \
'/usr/local/bin/sem -j 3 "rsync -av --files-from=${FPART_PARTFILENAME}" /mnt/Rsync-source/ /mnt/Rsync-dest/'
此命令是以实时模式启动(选项-L)fpart
,从而在遍历FS期间生成分区。FPART
将产生若干个分区,每个分区最多包含10000个文件,并且将跳过".snapshot"和".zfs"的文件和文件夹,并且列出空目录和不能访问的目录(选项-zz,使用rsync用来确保整个文件树能够在目标目录中重新创建。),并且每个分区都将写入到/tmp/part.out
当中,并且在后置挂钩(选项-W)中使用,分区完成后,fpart
立即运行。
$ sem -j 3 "/rsync -av --files-from=${FPART_PARTFILENAME} /mnt/Rsync-source/ /mnt/Rsync-dest/"
这个钩子函数本身是一个嵌套命令,将运行GNU Parallel
的sem
调度程序(任何其他调度程序都可以执行),最多执行3个rsync
作业。
调度程序最终触发以下命令:
rsync -av --files-from=${FPART_PARTFILENAME} /mnt/Rsync-source/ /mnt/Rsync-dest/
在此示例中,原文中的例子是在同一台本地计算机上运行的,但也以将其用作比较复杂的解决方案的基础:原平台作者,$work
上,通过使用NFS
和运行的Open Grid Scheduler
,成功迁移了400TB
的数据。
Note
可以使用上面的示例启动多个连续的fpart
运行,来执行增量同步。也就是说,除非使用rsync
的--delete
选项,否则从源目录中删除的文件不会从目标中删除。但是,此选项不能与文件列表一起使用(未出现在列表中的文件将被忽略)。要将--delete
选项与fpart
结合使用,必须为rsync
的--files-from
选项提供目录列表。
3.5 Fpsync
fpart
工具提供了名为fpsync
的可执行文件。此工具是一个shell脚本,包装了fpart
和rsync
,用来并行启动多个同步作业。上面的例子中,是由GNU Parallel
安排的传输,fpsync
提供了自己的嵌入式调度程序,可以通过SSH
在多个节点上启动它们。
3.6 Here is a simple representation of how it works
fpsync [args] /data/src/ /data/dst/
|
+-- fpart (live mode) crawls /data/src/, generates parts.[1] + sync jobs ->
| \ \ \
| \ \ +___ part. #n + job #n
| \ \
| \ +______ part. #1 + job #1
| \
| +_________ part. #0 + job #0
|
+-- fpsync scheduler, executes jobs either locally or remotely ----------->
\ \ \
\ \ +___ sync job #n... --------------------------------------> +
\ \ |
\ +______ sync job #1 ----------------------------------> |
\ |
+_________ sync job #0 -----------------------------> +
/
/
Filesystem tree rebuilt and synchronized! <------------------+
[1] Either containing file lists (default mode) or directory lists (option -E)
3.7 File mode
默认模式下,fpsync
使用rsync
并与文件列表一起执行增量同步。
$fpsync -n 4 -f 1000 -s $((100 * 1024 * 1024)) /mnt/Rsync-source/ /mnt/Rsync-dest/
将在本地使用4个进程将/mnt/Rsync-source/
同步到/mnt/Rsync-dest/
目录下,每个同步任务最多传输1000
个文件和100MB
。
3.8 Directory mode(这里算是fpart工具的一个弊端 )
最后一次同步的问题。
3.11 限制 Limitations
Fpart
不会修改数据,也不会分割文件- 如果目录包含几个小文件和一个大文件,
Fpart
无法生成相同大小的分区。 Fpart
不会删除路径中的重复数据。
如果提供fpart
的几种路径,它将检查所有这些路径,如果这些路径重叠或者多次指定相同的路径,则相同的文件将在生成的分区中出现多次。Fpsync
仅同步目录内容。 这一点的实现,要学习一下- 与
rsync
相反,fpsync
在源目录上强制使用最后的/
。这意味着目录内容是同步的,而不是源目录本身的同步。(即,同步后,将不会在目标目录中获得源目录名称的子目录)