Files
Cloud-book/其他/08.rsync.md
2025-08-27 17:10:05 +08:00

504 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RSYNC
# 什么是RSYNC
rsync是类unix下的一款数据镜像备份工具——remote sync。
Rsync 的基本特点如下:
- 可以镜像保存整个目录树和文件系统;
- 可以很容易做到保持原来文件的权限、时间、软硬链接等;
- 无须特殊权限即可安装;
- 优化的流程,文件传输效率高;
- 可以使用 rcp、ssh 等方式来传输文件,当然也可以通过直接的 socket 连接;
- 支持匿名传输;
- rsync的主要特点就是**增量传输**,只对变更的部分进行传送。
# RSYNC原理
## `rsync`原理
`rsync``linux`下同步文件的一个高效算法,用于同步更新两处计算机的文件和目录,并适当利用查找文件中的不同块以减少数据传输。`rsync`的主要特点就是增量传输,只对变更的部分进行传送。
```shell
vim 1.txt
1 2 3 4
vim 2.txt
1 2 3 4
diff 1.txt 2.txt
```
### 增量同步算法
假如我们现在需要同步两个文件保持一致,并且只想传送不同的部分,那么我们就需要对两边的文件做`diff`,但是这两个文件在两台不同的机器上,无法做`diff`。如果我们做`diff`,就要把一个文件传到另一台机器上做`diff`,但这样一来,我们就传了整个文件,这与我们只想传输不同部分的初衷相背。于是我们就要想一个办法,让这两边的文件见不到面,但还能知道它们间有什么不同。这就是`rsync`的算法。
### `rsync`同步算法
我们将同步源文件名称为`fileSrc`,同步目的文件叫`fileDst`
#### 1. 分块`Checksum`算法
**找到文件不同的地方**
首先,我们会把`fileDst`的文件平均切分成若干个小块,比如每块`512`个字节(最后一块会小于这个数),然后对每块计算两个`checksum`:
1. 一个叫`rolling checksum`,是弱`checksum``32`位的`checksum`(相对粗略,但是快)
2. 另一个是强`checksum``128`位的,以前用`md4`,现在用`md5 hash`算法。
为什么要这样?因为若干年前的硬件上跑`md4`的算法太慢了,所以,我们需要一个快算法来鉴别文件块的不同,但是弱的`adler32`算法碰撞概率太高了,所以我们还要引入强的`checksum`算法以保证两文件块是相同的。也就是说,弱的`checksum`是用来**区别不同**,而强的是用来**确认相同**。
#### 2. 传输算法
**同步目标端会把`fileDst`的一个`checksum`列表传给同步源**,这个列表里包括了三个东西,`rolling checksum(32bits)md5 checksume(128bits)`,文件块编号。
同步源机器拿到了这个列表后,会对`fileSrc`做同样的`checksum`,然后和`fileDst``checksum`做对比,这样就知道哪些文件块改变了。
但是,聪明的你一定会有以下两个疑问:
如果我`fileSrc`这边**在文件中间加了一个字符,这样后面的文件块都会位移一个字符,这样就完全和`fileDst`这边的不一样了,但理论上来说,我应该只需要传一个字符就好了**。这个怎么解决?
如果这个`checksum`列表特别长,而我的两边的相同的文件块可能并不是一样的顺序,那就需要查找,线性的查找起来应该特别慢吧。这个怎么解决?
很好,让我们来看一下同步源端的算法。
#### 3. `checksum`查找算法
同步源端拿到`fileDst``checksum`数组后,会把这个数据存到一个`hash table`(特殊的数据结构体,可以快速检索)中,用`rolling checksum``hash`,以便获得`O(1)`时间复杂度的查找性能。这个`hash table``16bits`的,所以,`hash table`的尺寸是`2的16次方`,对`rolling checksum``hash`会被散列到`0 到 2^16 1`中的某个整数值。
#### 4. 比对算法
![图片描述](08.rsync/bVbpkxQ)
1.`fileSrc`的第一个文件块(我们假设的是`512`个长度),也就是从`fileSrc`的第`1`个字节到第`512`个字节,取出来后做`rolling checksum`计算。计算好的值到`hash`表中查。
2. 如果查到了,说明发现在`fileDst`中有潜在相同的文件块,于是就再比较`md5``checksum`,因为`rolling checksume`太弱了,可能发生碰撞。于是还要算`md5``128bits``checksum`,这样一来,我们就有` 2^-(32+128) = 2^-160`的概率发生碰撞,这太小了可以忽略。如果`rolling checksum``md5 checksum`都相同,这说明在`fileDst`中有相同的块,我们需要记下这一块在`fileDst`下的文件编号。
3. 如果`fileSrc``rolling checksum` 没有在`hash table`中找到,那就不用算`md5 checksum`了。表示这一块中有不同的信息。总之,只要`rolling checksum``md5 checksum` 其中有一个在`fileDst``checksum hash`表中找不到匹配项,那么就会触发算法对`fileSrc``rolling`动作。于是,算法会住后`step 1`个字节,取`fileSrc`中字节`2-513`的文件块要做`checksumgo to (1.) ` 现在你明白什么叫`rolling checksum`了吧。(主动往后一位)
4. 这样,我们就可以找出`fileSrc`相邻两次匹配中的那些文本字符,这些就是我们要往同步目标端传的文件内容了。
#### 5. 传输
![图片描述](08.rsync/bVbpkyQ)
最终在同步源这端,我们的`rsync`算法可能会得到这个样子的一个数据数组,图中,红色块表示在目标端已匹配上,不用传输(注:我专门在其中显示了两块`chunk #5`,代表数据中有复制的地方,不用传输),而白色的地方就是需要传输的内容(注意:这些白色的块是不定长的),这样,同步源这端把这个数组(白色的就是实际内容,红色的就放一个标号)压缩传到目的端,在目的端的`rsync`会根据这个表重新生成文件,这样,同步完成。
参考博客:
https://segmentfault.com/a/1190000018391604?utm_source=tag-newest
# 安装部署服务端
- 安装xineted服务
```bash
[root@server1 ~]# yum install rsync.x86_64 -y
[root@server1 ~]# yum install xinetd -y
```
- 修改xineted配置文件
```bash
[root@server1 ~]# vim /etc/xinetd.d/rsync
service rsync
{
disable = no
socket_type = stream
wait = no
user = root
server = /usr/bin/rsync
server_args = --daemon
port = 873
log_on_failure = USERID
}
```
- 修改rsync配置文件
```bash
[root@server1 ~]# vim /etc/rsyncd.conf
[test] // 模块名,主要是定义服务器哪个目录要被同步
path = /test // 指定文件目录所在位置,这是必须指定的
uid = root
gid = root
max connections = 2
timeout = 300
read only = false
auth users = root // 认证用户是 root必须是服务器上真实存在的用户
secrets file = /etc/rsync.passwd // 密码存在哪个文件
strict modes = yes
use chroot = yes // 在传输文件之前服务器守护程序在将chroot 到文件系统中的目录中
```
- 准备密码文件
```bash
[root@server1 ~]# vim /etc/rsync.passwd
root:123456
[root@server1 ~]# chmod 600 /etc/rsync.passwd
```
- 启动服务
```bash
[root@server1 ~]# systemctl start xinetd.service
[root@server1 ~]# ss -tanl | grep 873
LISTEN 0 64 :::873 :::*
```
- 准备文件
```bash
[root@server1 ~]# mkdir /test
[root@server1 ~]# touch /test/123
```
# 六种不同的工作模式
- 在server2上安装rsync
```bash
[root@server2 ~]# yum install rsync.x86_64 -y
```
rysnc工具的参数
```
rsync 相关参数
-v --verbose详细
-a --avchive归档模式表示递归方式传输文件并保持所有文件属性等于-rlptgoD
-z 传递过程中使用zip压缩传递速度更快
-p, --perms 保持文件权限
-P --partial 保留那些因故没有完全传输的文件,以便加快随后的再次传输
-r --recursiv递归目录
-e --rsh=COMMAND指定使用rsh、ssh方式进行数据同步
--progress 在传输时现实传输过程(显示备份过程)
-topg 保持文件原有属性o=owner,t=time,p=perms(权限)g=group
-b --backup创建备份也就是对于目的已经存在有同样的文件名时将老的文件重新命名为~filename
-u --update仅仅进行更新也就是跳过已经存在的文件
-l--links保留软连接
--delete 删除那些DST中SRC没有的文件(就是在目的目录中只保留传输过去的文件,其它的都删除),保持和源文件相同
-q, --quiet 精简输出模式
-c, --checksum 打开校验开关,强制对文件传输进行校验
-R, --relative 使用相对路径信息
-b, --backup 创建备份,也就是对于目的已经存在有同样的文件名时,将老的文件重新命名为~filename。可以使用--suffix选项来指定不同的备份文件前缀。
--backup-dir 将备份文件(如~filename)存放在在目录下。
-suffix=SUFFIX 定义备份文件前缀
-u, --update 仅仅进行更新也就是跳过所有已经存在于DST并且文件时间晚于要备份的文件。(不覆盖更新的文件)
-l, --links 保留软链结
-L, --copy-links 想对待常规文件一样处理软链结
--copy-unsafe-links 仅仅拷贝指向SRC路径目录树以外的链结
--safe-links 忽略指向SRC路径目录树以外的链结
-H, --hard-links 保留硬链结
-o, --owner 保持文件属主信息
-g, --group 保持文件属组信息
-D, --devices 保持设备文件信息
-t, --times 保持文件时间信息
-S, --sparse 对稀疏文件进行特殊处理以节省DST的空间
-n, --dry-run现实哪些文件将被传输
-W, --whole-file 拷贝文件,不进行增量检测
-x, --one-file-system 不要跨越文件系统边界
-B, --block-size=SIZE 检验算法使用的块尺寸默认是700字节
-e, --rsh=COMMAND 指定使用rsh、ssh方式进行数据同步
--rsync-path=PATH 指定远程服务器上的rsync命令所在路径信息
-C, --cvs-exclude 使用和CVS一样的方法自动忽略文件用来排除那些不希望传输的文件
--existing 仅仅更新那些已经存在于DST的文件而不备份那些新创建的文件
--delete-excluded 同样删除接收端那些被该选项指定排除的文件
--delete-after 传输结束以后再删除
--ignore-errors 及时出现IO错误也进行删除
--max-delete=NUM 最多删除NUM个文件
--partial 保留那些因故没有完全传输的文件,以是加快随后的再次传输
--force 强制删除目录,即使不为空
--numeric-ids 不将数字的用户和组ID匹配为用户名和组名
--timeout=TIME IP超时时间单位为秒
-I, --ignore-times 不跳过那些有同样的时间和长度的文件
--size-only 当决定是否要备份文件时,仅仅察看文件大小而不考虑文件时间
--modify-window=NUM 决定文件是否时间相同时使用的时间戳窗口默认为0
-T --temp-dir=DIR 在DIR中创建临时文件
--compare-dest=DIR 同样比较DIR中的文件来决定是否需要备份
--exclude=PATTERN 指定排除不需要传输的文件模式
--include=PATTERN 指定不排除而需要传输的文件模式
--exclude-from=FILE 排除FILE中指定模式的文件。
如果排除单个文件或者目录,可以直接指定 --exclude-from=File_Name
如果是多个文件或目录,可以新建一个文件 exclude里面写上要排除的文件名或目录名可以使用正则然后使用--exclude-from='/../exclude'指定
--include-from=FILE 不排除FILE指定模式匹配的文件。用法同上
--version 打印版本信息
--address 绑定到特定的地址
--config=FILE 指定其他的配置文件不使用默认的rsyncd.conf文件
--port=PORT 指定其他的rsync服务端口
--blocking-io 对远程shell使用阻塞IO
-stats 给出某些文件的传输状态
--log-format=formAT 指定日志文件格式
--password-file=FILE 从FILE中得到密码
--bwlimit=KBPS 限制I/O带宽KBytes per second
-h, --help 显示帮助信息
```
- 模式一,查看服务端有哪些可用数据源
```bash
[root@server2 ~]# rsync --list-only root@192.168.88.10::
test
```
- 模式二本地文件拷贝到本地当src和dest都不包含有冒号时就启动从本地进行拷贝
```bash
[root@server2 ~]# mkdir /backup
[root@server2 ~]# touch local.txt
[root@server2 ~]# rsync local.txt /backup/
[root@server2 ~]# ls /backup/
local.txt
```
- 模式三本地文件拷贝到远程当dest包含冒号时就启动拷贝到远程
```bash
[root@server2 ~]# rsync local.txt root@192.168.88.10:/test
The authenticity of host '192.168.175.10 (192.168.175.10)' can't be established.
ECDSA key fingerprint is SHA256:x573vWoEULGOYwloNT7s9EqxZa6lA1k5zZMFk7bU0xg.
ECDSA key fingerprint is MD5:60:21:e0:bf:3c:c0:d8:09:74:b8:23:26:55:4e:d1:0e.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.175.10' (ECDSA) to the list of known hosts.
root@192.168.175.10's password:
[root@server1 ~]# ll /test/local.txt
-rw-r--r-- 1 root root 0 3月 24 11:05 /test/local.txt
```
- 模式四将远程文件拷贝到本地当src包含冒号的时候就启动远程拷贝到本地
```bash
[root@server2 ~]# rsync root@192.168.88.10:/test/123 /backup/
root@192.168.175.10's password:
[root@server2 ~]# ll /backup/123
-rw-r--r-- 1 root root 0 3月 24 11:07 /backup/123
```
- 模式五从远程服务器拷贝到本地当src使用两个冒号的时候启用这种方式冒号后面跟的是服务端设置的模块
```bash
[root@server2 ~]# rsync -r root@192.168.88.10::test /backup/
Password:
#这时的密码就不是主机root用户的密码而是rsync设置的密码了
[root@server2 ~]# ls /backup/
123 local.txt
```
- 模式六,从本地拷贝到远程服务器
```bash
[root@server2 ~]# touch 456
[root@server2 ~]# rsync -r 456 root@192.168.88.10::test
Password:
[root@server1 ~]# ls /test/
123 456 local.txt
```
# 案例,定时备份
**客户端需求**
1.客户端提前准备存放的备份的目录,目录规则如下:/backup/主机\_ip\_时间
2.客户端在本地打包备份(系统配置文件、应用配置等)例如/etc/passwd,拷贝至/backup/主机\_ip\_时间
3.客户端最后将备份的数据进行推送至备份服务器
4.客户端每天凌晨1点定时执行该脚本
5.客户端服务器本地保留最近7天的数据,避免浪费磁盘空间
**服务端需求**
1.服务端部署rsync用于接收客户端推送过来的备份数据
⒉.服务端需要每天校验客户端推送过来的数据是否完整
3.服务端需要每天校验的结果通知给管理员
4.服务端仅保留6个月的备份数据,其余的全部删除
-------------------------------
客户端准备
- 创建目录
```bash
[root@server2 ~]# mkdir /backup
```
- 安装expect工具
```bash
[root@server2 ~]# yum install expect* -y
```
- 准备expect脚本
```bash
[root@server2 ~]# vim rsync.exp
#!/usr/bin/expect
#set: 进行赋值
set mulu [lindex $argv 0]
#位置参数,0 表示第一个参数
set timeout 10
spawn rsync -avzr /backup/$mulu root@192.168.88.10::test
#spawn: 启动新的进程
expect Password
#expect: 从进程接收字符串
send "123456\n"
#send: 用于向进程发送字符串
expect eof
```
- 准备备份脚本
```bash
[root@server2 ~]# vim beifen.sh
#!/bin/bash
# 准备压缩文件的目录
mulu=`ip a | grep global|awk -F'[ /]+' '{print $3}'`_`date +%F`
echo $mulu
mkdir -pv /backup/$mulu &> /dev/null
# 打包待发送的数据
tar zcf /backup/$mulu/conf.tar.gz /etc/passwd /etc/vimrc &> /dev/null
# 为了后面模拟一个月数据的变化
touch /backup/$mulu
# 发送数据
#rsync -avzr /backup/$mulu root@192.168.175.10::test
expect rsync.exp $mulu
# 保留七天以内的数据
find /backup -mtime +7 -delete
[root@server2 ~]# chmod +x beifen.sh
```
- 计划任务
```bash
[root@server2 ~]# cat /etc/crontab
......
0 1 * * * root /root/beifen.sh
```
服务端准备
- 安装rsync
```bash
[root@server1 ~]# yum install rsync.x86_64 -y
```
- 修改配置文件
```bash
[root@server1 ~]# vim /etc/rsyncd.conf
[test]
path = /test
uid = root
gid = root
max connections = 2
timeout = 300
read only = false
auth users = root
secrets file = /etc/rsync.passwd
strict modes = yes
use chroot = yes
```
- 创建目录
```bash
[root@server1 ~]# mkdir /test -pv
```
- 准备密码文件
```bash
[root@server1 ~]# cat /etc/rsync.passwd
root:123456
[root@server1 ~]# chmod 600 /etc/rsync.passwd
```
- 启动rsync
```bash
[root@server1 ~]# systemctl start rsyncd.service
[root@server1 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 5 *:873 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
LISTEN 0 5 :::873 :::*
```
- 验证服务端
```bash
[root@server2 ~]# rsync --list-only root@192.168.88.10::
test
```
-------------
- 模拟一个月的数据来验证结果
```bash
[root@server2 ~]# for i in {1..31};do date -s 2024/08/$i; /root/beifen.sh ; done
#修改时间,模拟一个月的时间
[root@server2 ~]# ll /backup
总用量 0
drwxr-xr-x 2 root root 25 8月 24 00:00 192.168.175.30_2022-08-24
drwxr-xr-x 2 root root 25 8月 25 00:00 192.168.175.30_2022-08-25
drwxr-xr-x 2 root root 25 8月 26 00:00 192.168.175.30_2022-08-26
drwxr-xr-x 2 root root 25 8月 27 00:00 192.168.175.30_2022-08-27
drwxr-xr-x 2 root root 25 8月 28 00:00 192.168.175.30_2022-08-28
drwxr-xr-x 2 root root 25 8月 29 00:00 192.168.175.30_2022-08-29
drwxr-xr-x 2 root root 25 8月 30 00:00 192.168.175.30_2022-08-30
drwxr-xr-x 2 root root 25 8月 31 00:00 192.168.175.30_2022-08-31
[root@server2 ~]# date
[root@server2 ~]# systemctl restart chronyd
#重置时间
[root@server2 ~]# date
[root@server1 ~]# ll /test
总用量 0
drwxr-xr-x 2 root root 25 8月 1 00:00 192.168.175.30_2022-08-01
drwxr-xr-x 2 root root 25 8月 2 00:00 192.168.175.30_2022-08-02
drwxr-xr-x 2 root root 25 8月 3 00:00 192.168.175.30_2022-08-03
drwxr-xr-x 2 root root 25 8月 4 00:00 192.168.175.30_2022-08-04
drwxr-xr-x 2 root root 25 8月 5 00:00 192.168.175.30_2022-08-05
drwxr-xr-x 2 root root 25 8月 7 00:00 192.168.175.30_2022-08-07
drwxr-xr-x 2 root root 25 8月 8 00:00 192.168.175.30_2022-08-08
drwxr-xr-x 2 root root 25 8月 9 00:00 192.168.175.30_2022-08-09
drwxr-xr-x 2 root root 25 8月 10 00:00 192.168.175.30_2022-08-10
drwxr-xr-x 2 root root 25 8月 11 00:00 192.168.175.30_2022-08-11
drwxr-xr-x 2 root root 25 8月 12 00:00 192.168.175.30_2022-08-12
drwxr-xr-x 2 root root 25 8月 20 2022 192.168.175.30_2022-08-20
drwxr-xr-x 2 root root 25 8月 21 2022 192.168.175.30_2022-08-21
drwxr-xr-x 2 root root 25 8月 22 2022 192.168.175.30_2022-08-22
drwxr-xr-x 2 root root 25 8月 23 2022 192.168.175.30_2022-08-23
drwxr-xr-x 2 root root 25 8月 24 2022 192.168.175.30_2022-08-24
drwxr-xr-x 2 root root 25 8月 25 2022 192.168.175.30_2022-08-25
drwxr-xr-x 2 root root 25 8月 27 2022 192.168.175.30_2022-08-27
drwxr-xr-x 2 root root 25 8月 28 2022 192.168.175.30_2022-08-28
drwxr-xr-x 2 root root 25 8月 29 2022 192.168.175.30_2022-08-29
drwxr-xr-x 2 root root 25 8月 30 2022 192.168.175.30_2022-08-30
drwxr-xr-x 2 root root 25 8月 31 2022 192.168.175.30_2022-08-31
```