使用rsync快速同步与备份服务器数据

19年以来似乎折腾了很多数据备份/同步工具,例如rclone、mega等等。

不得不说rclone是一个神器,它支持了非常多的协议和网盘,大鱼目前的数据安全性方案里也用到了很多,但是rclone也有它的缺陷,比如它是基于已有的协议作为转换的。在刚开始的NAS每日备份方案中,用到了rclone基于WebDav协议进行nextcloud网盘的数据备份,即便是文件内容没有任何变化,rclone仍然花费了近一个小时来检查同步我那不过几百个G的数据,而且在此过程中,发送了非常多的请求,造成了主机长时间高负载。
后来在重新研究备份方案时,发现了rsync。与rclone兼容已有协议/服务不同,它是一个CS架构的软件,需要在客户机和服务器上同时部署,虽然增加了一些服务器的负载,不过带来的优势却是很明显的,可以通过数据压缩等各种优化来加快同步。rsync是直接同步文件系统的,有更高的效率。而且,rsync是基于时间戳和文件大小来检查文件是否一致的,这样在文件系统只发生少量变动的情况下在极短的时间内就可以完成同步任务。(基于时间戳和文件大小的方法在原理上可能会出现实际文件发生改动但是时间戳和大小不变的情况,不过正常情况下不会出现这种情况,可以放心使用)
rsync是基于delta-transfer的差分同步方案,对于一些经常改变但是只有一小部分发生更新的大文件非常有效,比如说日志,在降低了网络通信开销的同时也加快了同步速度。此外,它是一个跨机的文件同步的工具,这样就可以异地备份,提高可靠性。

安装部署

rsync部署起来也很方便,直接 sudo apt install -y rsync
就可以了,然后在服务器上使用命令 rsync --daemon
运行服务端。

以下依旧是基于docker的部署方式,首先放 Dockerfile

可以直接跳到后面

FROM alpine:3.10

RUN apk add --no-cache rsync

ADD bootstrap.sh /etc/bootstrap.sh

ENTRYPOINT ["/etc/bootstrap.sh"]

# bootstrap.sh
if ! [[ -z $@ ]]; then
    eval $@
else
    rsync --daemon --config=/etc/rsyncd.conf
    while pgrep rsync > /dev/null; do sleep 1; done
fi

配置和使用

首先要写一下配置文件。前面的部分是全局的配置,后面可以针对每一个子项进行配置,比如我们要同步 /data
目录。

# /etc/rsyncd: configuration file for rsync daemon mode
# See rsyncd.conf man page for more options.
uid = root
gid = root

# 如果要在客户端上保留文件系统权限和用户,这里需要配置成yes
use chroot = yes
# 如果服务端只用来提供同步,这里可以设置成yes,避免数据被误操作
read only = no

# 配置允许的客户端网段,需要注意的是docker需要配置`--net host`才能正确使用。
# hosts allow = 192.168.1.0/255.255.255.0 172.18.50.111
# hosts deny = *

# 配置单客户端最大的连接,这个如果只是私人使用,基本用不到
#max connections = 4

transfer logging = yes
log format = %t %a %m %f %b
log file = /var/log/rsync.log

# 拍不lost found等没有用的文件夹
exclude = lost+found/
# 无响应超时时间
timeout = 600

# 在发生io错误的时候继续处理
ignore nonreadable = yes

# 避免无意义的压缩带来的资源浪费
dont compress   = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2

[data]
path = /data/
# 是否公开显示
list = yes
comment = This is site data
# 这里可以配置多个,用空格空开
auth users = newnius
secrets file = /etc/rsyncd.secrets
exclude = lost+found/

保存为 /data/rsync/config/rsyncd.conf
文件。

再创建一个 /data/rsync/config/rsyncd.secrets
文件,文件内容是用户和秘钥,建议设置的复杂一点,文件格式如下:

user1:password1
user2:password2
newnius:123456

你可以 在这里找到完整的配置项和含义

启动服务端

docker run \
    --name rsync \
    -d \
    --restart always \
    --publish 873:873 \
    --mount type=bind,src=/data/,dst=/data/ \
    --mount type=bind,src=/data/rsync/config/,dst=/config/ \
    newnius/rsync

服务端需要暴露873端口用于请求处理和数据传输。

客户端同步

docker run \
    -it \
    --rm \
    --name rsync \
    --env AUTH_USER=newnius \
    --env AUTH_PASSWORD=password \
    --mount type=bind,src=/data/,dst=/data/ \
    newnius/rsync rsync -avzP --delete --password-file=/etc/rsyncd.secret newnius@192.168.1.101::data/ /data/

注意修改脚本里的账号、密码以及ip地址,文件目录等等。

脚本默认已经配置了免输入密码,如果自己在宿主机上配置的话,需要主要秘钥文件的权限一定要是 600
,否则会被忽略,你也可以在日志文件里看到提示。

chmod 600 /etc/rsyncd.user1.secret

chmod 600 /etc/rsyncd.secrets

安全性

rsync提供了急于账号秘钥的验证方式,同时也可以配置允许的客户端ip,在数据链路安全上,rsync可以采用基于ssh协议的传输方式(本文没有涉及),基本可以保证安全性。

不过ssh协议容易被检测,直接将rsync服务暴露在公网也有一定的隐患,大鱼的方案是利用已有的内网代理v2ray,然后让rsync走代理,这样即便是rsync的验证存在问题,也可以保证安全。要让rsync走代理,只需要在客户端命令前面加上 RSYNC_PROXY=localhost:8118
即可,http协议,不用写。