在两台服务器之前进行大文件传输时,要保证支持断点续传,避免传输过程中因网络异常中断导致前功尽弃、传输能够支持压缩,降低传输的数据大小,加快传输速度。常见的文件传输工具,如 scp 基于 ssh 的方式传输,虽然进行数据加密,保证了数据安全,但不支持断点续传。本篇介绍一种保留 scp 所有有点,并能够进行断点续传和数据压缩的大文件传输(复制)工具。以 Ubuntu 18.04 为例演示所有代码。

大文件切分与小文件合并

在传输大文件时,通常的思维是先将大文件切分成多个小文件,把小文件传输后,再合并这些小文件,得到大文件。

大文件切分

在本地将大文件切分,最好切分前先对文件进行压缩,缩小文件大小,便于传输

1
2
# M 表示兆字节,G表示吉字节,本例切分为100兆字节,也可以切分为吉字节
split -b 100M -d test.zip test_part

然后通过 scp 等命令传输这些小文件

1
scp test_part* jinzhongxu@1.1.1.1:./.

小文件合并

然后在远程服务器上合并这些小文件

1
cat test_part* > nes_test.zip

rsync

rsync 是一个快速、多功能、远程(和本地)的文件复制工具。在本地也可以直接替换 cpmv 等命令。字母 “r” 是 remote 的意思,即 rsync 表示远程同步。其最大特点是会在传输中检查发送方和接收方已有的文件,仅传输有变动的部分,默认的检查规则是文件大小或修改时间等。

安装

需要注意的是 rsync 需要在本地和远程服务器都安装,才可以使用。

1
2
3
4
5
# Ubuntu or Debian
sudo apt update
sudo apt install rsync
# CentOS
sudo yum install rsync

使用

1
2
3
4
5
6
7
8
9
10
11
Local:  rsync [OPTION...] SRC... [DEST]

Access via remote shell:
Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST]
Push: rsync [OPTION...] SRC... [USER@]HOST:DEST

Access via rsync daemon:
Pull: rsync [OPTION...] [USER@]HOST::SRC... [DEST]
rsync [OPTION...] rsync://[USER@]HOST[:PORT]/SRC... [DEST]
Push: rsync [OPTION...] SRC... [USER@]HOST::DEST
rsync [OPTION...] SRC... rsync://[USER@]HOST[:PORT]/DEST

常用的命令如下:

1
2
3
4
# 通过 ssh 的方式进行断点续传和压缩,并打印进度,把本地 test.tar 文件传输到远程服务器上
rsync -P -e 'ssh -p 2222' -z --append-verify ./test.tar jinzhongxu@1.1.1.1:./.

rsync -avzP --append-verify -e 'ssh -p 2222' ./test.tar jinzhongxu@1.1.1.1:./.

其他重要参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
-a、--archive 参数表示存档模式,保存所有的元数据,比如修改时间(modification time)、权限、所有者等,并且软链接也会同步过去

--append 参数指定文件接着上次中断的地方,继续传输

--append-verify 参数跟 --append 参数类似,但会对传输完成后的文件进行一次校验。如果校验失败,将重新发送整个文件

-b、--backup 参数指定在删除或更新目标目录已经存在的文件时,将该文件更名后进行备份,默认行为是删除。更名规则是添加由 --suffix 参数指定的文件后缀名,默认是 ~

--backup-dir 参数指定文件备份时存放的目录,比如 --backup-dir=/path/to/backups

--bwlimit 参数指定带宽限制,默认单位是 KB/s,比如 --bwlimit=100

-c、--checksum 参数改变 rsync 的校验方式。默认情况下,rsync 只检查文件的大小和最后修改日期是否发生变化,如果发生变化,就重新传输;使用这个参数以后,则通过判断文件内容的校验和,决定是否重新传输。

--delete 参数删除只存在于目标目录、不存在于源目标的文件,即保证目标目录是源目标的镜像

-e 参数指定使用 SSH 协议传输数据

--exclude 参数指定排除不进行同步的文件或文件夹,比如 --exclude="*.iso",--exclude={"MEGA", '.*'} 等

--exclude-from 参数指定一个本地文件,里面是需要排除的文件模式,每个模式一行

--existing、--ignore-non-existing 参数表示不同步目标目录中不存在的文件和目录

-h、 --human-readable 参数表示以人类可读的格式输出

(-h)、--help 参数返回帮助信息

-i 参数表示输出源目录与目标目录之间文件差异的详细情况

--ignore-existing 参数表示只要该文件在目标目录中已经存在,就跳过去,不再同步这些文件

--include 参数指定同步时要包括的文件,一般与 --exclude 结合使用

--link-dest 参数指定增量备份的基准目录

-m 参数指定不同步空目录

--max-size 参数设置传输的最大文件的大小限制,比如不超过 200KB(--max-size='200k')

--min-size 参数设置传输的最小文件的大小限制,比如不小于 10KB(--min-size=10k)

-n 参数或 --dry-run 参数模拟将要执行的操作,而并不真的执行。配合 -v 参数使用,可以看到哪些内容会被同步过去

-P 参数是 --progress 和 --partial 这两个参数的结合

--partial 参数允许恢复中断的传输。不使用该参数时,rsync 会删除传输到一半被打断的文件;使用该参数后,传输到一半的文件也会同步到目标目录,下次同步时再恢复中断的传输。一般需要与 --append 或 --append-verify配合使用。

--partial-dir 参数指定将传输到一半的文件保存到一个临时目录,比如 --partial-dir=.rsync-partial。一般需要与 --append或--append-verify 配合使用

--progress 参数表示显示进展

-r 参数表示递归,即包含子目录

--remove-source-files 参数表示传输成功后,删除发送方的文件

--size-only 参数表示只同步大小有变化的文件,不考虑文件修改时间的差异

--suffix 参数指定文件名备份时,对文件名添加的后缀,默认是 ~

-u、--update 参数表示同步时跳过目标目录中修改时间更新的文件,即不同步这些有更新的时间戳的文件

-v 参数表示输出细节。-vv 表示输出更详细的信息,-vvv 表示输出最详细的信息

--version 参数返回 rsync 的版本

-z 参数指定同步时压缩数据

更多说明请使用如下命令查看:

1
rsync -h

文件或文件夹同步

其实 rsync 最重要的功能就是磁盘同步。能够帮助我们同步重要文件或文件夹。下面给一些常用例子:

1
2
3
4
5
6
# 把远程服务器上的 archive 文件夹同步到本地服务器的 /archive 文件夹
# -avzp 含义参见上面释义
# --delete 表示同步时,删除目标文件夹/archive下有而在源文件夹www.mc.com:/home/jinzhongxu/archive/下没有的文件或文件夹
# --delete-excluded 能够删除空文件夹
# --exclude 不同步源文件夹下的 films 文件夹,注意此时源文件夹 /home/jinzhongxu/archive/ 后面的 /,如果没有该斜杠,则需要把 films 补全为 archive/films
rsync -avzP --delete --delete-excluded --exclude 'films' jinzhongxu@www.mc.com:/home/jinzhongxu/archive/ /archive
1
2
3
4
# 把本地的文件夹/home/jinzhongxu 同步到远程服务器 jinzhongxu@1.2.2.1:/mnt/d/power 中
# 同上一个例子,这里排除 /home/jinzhongxu/ 下的多个文件夹 'MEGA','.*','examples.desktop'
# 注意逗号,后面不要有空格
rsync -avzP --delete --delete-excluded /home/jinzhongxu/ --exclude={'MEGA','.*','examples.desktop'} jinzhongxu@1.2.2.1:/mnt/d/power

实时监控同步

使用 PyCharm 专业版进行 Python 项目开发时,能够远程项目同步,本地开发实时同步代码到远程服务器。搭配 inotify + rsyncfswatch + rsync 同样能够达到上面的效果。

安装

1
2
sudo apt update
sudo apt install inotify-tools fswatch

在 Mac OS 上只能安装 fswatch

1
2
brew update
brew install fswatch

inotifywait + rsync

如果是 Ubuntu 等 Linux 系统,建议使用 inotifywait,安装 inotify-tools 后就可以使用 inotifywait 工具。打开一个终端 A 输入下面的监控代码,打开另一个终端 B 进行文件夹操作,可以看到终端 A 中会实时显示终端 B 操作的事件情况:

1
2
3
4
5
6
7
# -m 表示时刻监控
# -r 表示递归监控
# -q 表示 quiet,监控打印信息更少
# --format '%w%f' 表示打印结果以用户自定义格式,%w%f 表示打印文件名
# -e 表示支持的事件
# /home/jinzhongxu 为监控的目录
/usr/bin/inotifywait -mrq --format '%w%f' -e create,delete,move,modify,attrib /home/jinzhongxu

搭配 rsync 实时监控同步,编写脚本 vim /home/jinzhongxu/inotify-rsync.sh:

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

path=$1
remote_path=$2

/usr/bin/inotifywait -mrq --format '%w%f' -e create,delete,move,modify,attrib $path | while read line
do
if [[ $line ]];then
rsync -avzP $path jinzhongxu@www.cmathsx.com:/workspace/$remote_path
fi
done

执行:

1
2
3
# 监控本地的 /home/jinzhongxu/ 目录
# 把该目录实时同步(只要在本地的 /home/jinzhongxu/ 目录下进行操作,包括 create,delete,move,modify,attrib等)到 www.cmathsx.com:/workspace/jzx/ 下
/bin/bash /home/jinzhongxu/inotify-rsync.sh /home/jinzhongxu/ jzx

这样在本地 /home/jinzhongxu/ 目录下编程程序,就可以通过 SSH 到远程服务器上直接运行程序。

一些重要配置参数说明:inotify 有一些默认的内核参数,其控制了 inotifywait 运行的行为。这些参数都写着目录 /proc/sys/fs/inotify 下的文件中:

  1. max_queued_events 默认值是 16384. 表示调用 inotify 初始化时分配给 inotify 实例可排队的 event 事件的数目最大值,超出这个值的事件被丢弃,但会触发 IN_Q_OVERFLOW 事件;
  2. max_user_instances 默认值是 128. 表示每一个 real user id 可创建的 inotify 实例的数量上限;
  3. max_user_watches 默认值是 8192. 表示每个 inotify 实例可监控的最大目录数量。如果监控的文件数目巨大,需要根据情况,适当增加此值的大小。

建议在运行 inotifywait 前先对这些配置参数进行调整(以 root 身份运行):

1
2
3
echo 10000000 > /proc/sys/fs/inotify/max_queued_events
echo 10000 > /proc/sys/fs/inotify/max_user_instances
echo 100000000 > /proc/sys/fs/inotify/max_user_watches

或者采用下面方法,上面方法在电脑重启时恢复默认值,下面方法将永久生效:

1
2
3
echo 'fs.inotify.max_queued_events=10000000' >> /etc/sysctl.conf
echo 'fs.inotify.max_user_instances=10000' >> /etc/sysctl.conf
echo 'fs.inotify.max_user_watches=100000000' >> /etc/sysctl.conf

更多关于 inotifywait 操作请使用命令查看:

1
2
man inotifywait
inotifywait -h

fswatch + rsync

该组合用法类似于 inotifywait + rsync. 使用 fswatch 监控目录

1
2
3
4
5
# 打印事件个数
/usr/bin/fswatch -o /home/jinzhongxu

# 监控延迟 1 秒
/usr/bin/fswatch -l 1 /home/jinzhongxu

fswatch 依赖监控窗口,如 inotify,查看窗口:

1
2
fswatch -M
fswatch --list-monitor

搭配 rsync 实时监控同步,编写脚本 vim /home/jinzhongxu/fswatch-rsync.sh:

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

path=$1
remote_path=$2

/usr/bin/fswatch -o $path | while read line
do
if [[ $line ]];then
rsync -avzP $path jinzhongxu@www.cmathsx.com:/workspace/$remote_path
fi
done

执行:

1
2
3
# 监控本地的 /home/jinzhongxu/ 目录
# 把该目录实时同步(只要在本地的 /home/jinzhongxu/ 目录下进行操作,如增删改等等)到 www.cmathsx.com:/workspace/jzx/ 下
/bin/bash /home/jinzhongxu/inotify-rsync.sh /home/jinzhongxu/ jzx

更多内容请使用如下命令获取:

1
2
man fswatch
fswatch -h

参考文献

  1. 对于linux系统,如何传输大文件?_raysync的博客-CSDN博客_linux大文件传输
  2. 服务器之间迁移大文件
  3. rsync 用法教程 - 阮一峰的网络日志
  4. 如何使用Rsync排除文件和目录
  5. 第二十三节 inotify事件监控工具
  6. Rsync远程同步+inotify监控
  7. 使用inotifytools监控文件
  8. linux inotify-tools 监控文件变化
  9. 在 linux 中遇到 OSError: inotify watch limit reached 错误
  10. Linux重启inotify配置max_user_watches无效被恢复默认值8192的正确修改方法