Rsync+inotify

1.什么是rsync

rsync是可以实现增量备份的工具。配合任务计划,rsync能实现定时或间隔同步,配合inotify或sersync,可以实现触发式的实时同步。

rsync可以实现scp的远程拷贝(rsync不支持远程到远程的拷贝,但scp支持)、cp的本地拷贝、rm删除和"ls -l"显示文件列表等功能。但需要注意的是,rsync的最终目的或者说其原始目的是实现两端主机的文件同步,因此实现的scp/cp/rm等功能仅仅只是同步的辅助手段,且rsync实现这些功能的方式和这些命令是不一样的。事实上,rsync有一套自己的算法,其算法原理以及rsync对算法实现的机制可能比想象中要复杂一些。平时使用rsync实现简单的备份、同步等功能足以,没有多大必要去深究这些原理性的内容。但是想要看懂rsync命令的man文档、使用"-vvvv"分析rsync执行过程,以及实现rsync更强大更完整的功能,没有这些理论知识的支持是绝对不可能实现的。本篇文章将简单介绍rsync的使用方法和它常用的功能。在本篇文章之后的下几篇文章中,将介绍inotify+rsync和sersync,再之后将详细解释rsync相关的原理,其中包括官方技术报告的翻译(即算法原理)、rsync同步的整个过程(也是官方推荐文章的翻译),然后专门使用一篇文章通过示例来详细解释rsync算法原理,最后给出rsync的man文档翻译。希望各位朋友能藉此深入rsync。

回归正题,以下是rsync相关基础内容。

2.rsync同步基本说明

rsync的目的是实现本地主机和远程主机上的文件同步(包括本地推到远程,远程拉到本地两种同步方式),也可以实现本地不同路径下文件的同步,但不能实现远程路径1到远程路径2之间的同步(scp可以实现)。

不考虑rsync的实现细节,就文件同步而言,涉及了源文件和目标文件的概念,还涉及了以哪边文件为同步基准。例如,想让目标主机上的文件和本地文件保持同步,则是以本地文件为同步基准,将本地文件作为源文件推送到目标主机上。反之,如果想让本地主机上的文件和目标主机上的文件保持同步,则目标主机上的文件为同步基准,实现方式是将目标主机上的文件作为源文件拉取到本地。当然,要保持本地的两个文件相互同步,rsync也一样能实现,这就像Linux中cp命令一样,以本地某文件作为源,另一文件作为目标文件,但请注意,虽然rsync和cp能达到相同的目的,但它们的实现方式是不一样的。

既然是文件同步,在同步过程中必然会涉及到源和目标两文件之间版本控制的问题,例如是否要删除源主机上没有但目标上多出来的文件,目标文件比源文件更新(newer than source)时是否仍要保持同步,遇到软链接时是拷贝软链接本身还是拷贝软链接所指向的文件,目标文件已存在时是否要先对其做个备份等等。

rsync同步过程中由两部分模式组成:决定哪些文件需要同步的检查模式以及文件同步时的同步模式。

(1).检查模式是指按照指定规则来检查哪些文件需要被同步,例如哪些文件是明确被排除不传输的。默认情况下,rsync使用"quick check"算法快速检查源文件和目标文件的大小、mtime(修改时间)是否一致,如果不一致则需要传输。当然,也可以通过在rsync命令行中指定某些选项来改变quick check的检查模式,比如"--size-only"选项表示"quick check"将仅检查文件大小不同的文件作为待传输文件。rsync支持非常多的选项,其中检查模式的自定义性是非常有弹性的。

(2).同步模式是指在文件确定要被同步后,在同步过程发生之前要做哪些额外工作。例如上文所说的是否要先删除源主机上没有但目标主机上有的文件,是否要先备份已存在的目标文件,是否要追踪链接文件等额外操作。rsync也提供非常多的选项使得同步模式变得更具弹性。

相对来说,为rsync手动指定同步模式的选项更常见一些,只有在有特殊需求时才指定检查模式,因为大多数检查模式选项都可能会影响rsync的性能。

3. rsync三种工作方式

以下是rsync的语法:

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

由此语法可知,rsync有三种工作方式:

(1).本地文件系统上实现同步。命令行语法格式为上述"Local"段的格式。

(2).本地主机使用远程shell和远程主机通信。命令行语法格式为上述"Access via remote shell"段的格式。

(3).本地主机通过网络套接字连接远程主机上的rsync daemon。命令行语法格式为上述"Access via rsync daemon"段的格式。

前两者的本质是通过管道通信,即使是远程shell。而方式(3)则是让远程主机上运行rsync服务,使其监听在一个端口上,等待客户端的连接。

但是,还有第四种工作方式:通过远程shell也能临时启动一个rsync daemon,这不同于方式(3),它不要求远程主机上事先启动rsync服务,而是临时派生出rsync daemon,它是单用途的一次性daemon,仅用于临时读取daemon的配置文件,当此次rsync同步完成,远程shell启动的rsync daemon进程也会自动消逝。此通信方式的命令行语法格式同"Access via rsync daemon",但要求options部分必须明确指定"--rsh"选项或其短选项"-e"。

以下是对rsync语法的简单说明,由于rsync支持一百多个选项,所以此处只介绍几个常用选项。完整的选项说明以及rsync的使用方法见我翻译的"man rsync"。

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

其中,第一个路径参数一定是源文件路径,即作为同步基准的一方,可以同时指定多个源文件路径。最后一个路径参数则是目标文件路径,也就是待同步方。路径的格式可以是本地路径,也可以是使用user@host:path或user@host::path的远程路径,如果主机和path路径之间使用单个冒号隔开,表示使用的是远程shell通信方式,而使用双冒号隔开的则表示的是连接rsync daemon。另外,连接rsync daemon时,还提供了URL格式的路径表述方式rsync://user@host/path。

如果仅有一个SRC或DEST参数,则将以类似于"ls -l"的方式列出源文件列表(只有一个路径参数,总会认为是源文件),而不是复制文件。

如果对rsync不熟悉,可暂先只了解本地以及远程shell格式的user@host:path路径格式。例如:

[root@xuexi ~]# rsync /etc/fstab /tmp                # 在本地同步
[root@xuexi ~]# rsync -r /etc 172.16.10.5:/tmp       # 将本地/etc目录拷贝到远程主机的/tmp下,以保证远程/tmp目录和本地/etc保持同步
[root@xuexi ~]# rsync -r 172.16.10.5:/etc /tmp       # 将远程主机的/etc目录拷贝到本地/tmp下,以保证本地/tmp目录和远程/etc保持同步
[root@xuexi ~]# rsync /etc/                          # 列出本地/etc/目录下的文件列表
[root@xuexi ~]# rsync 172.16.10.5:/tmp/              # 列出远程主机上/tmp/目录下的文件列表

另外,使用rsync一定要注意的一点是,源路径如果是一个目录的话,带上尾随斜线和不带尾随斜线是不一样的,不带尾随斜线表示的是整个目录包括目录本身,带上尾随斜线表示的是目录中的文件,不包括目录本身。例如:

[root@xuexi ~]# rsync -a /etc /tmp
[root@xuexi ~]# rsync -a /etc/ /tmp

第一个命令会在/tmp目录下创建etc目录,而第二个命令不会在/tmp目录下创建etc目录,源路径/etc/中的所有文件都直接放在/tmp目录下。

4. rsync例子

本地
Local:  rsync [OPTION...] SRC... [DEST]

# =cp动作
rsync color.sh /tmp/
# =rm动作
rsync -r -delete color.sh a/


Access via remote shell:
  Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST]
  Push: rsync [OPTION...] SRC... [USER@]HOST:DEST
# =scp动作
scp -P22 -rp /etc/hosts root@192.168.0.1:/tmp # 推送
scp -P22 root@192.168.0.252:/etc/hosts /opt/a # 拉取
rsync -avz -e 'ssh -p22' /etc/hosts root@192.168.0.252:/tmp # 推送
rsync -e 'ssh -p22' root@192.168.0.252:/etc/hosts /opt/ # 拉取

# avz 常用参数表示  -e表示使用通道
-a --archive  :归档模式,表示递归传输并保持文件属性。等同于"-rtopgDl"。
-z        :传输时进行压缩提高效率。
-v:显示rsync过程中详细信息。可以使用"-vvvv"获取更详细信息。
-e          :指定所要使用的远程shell程序,默认为ssh。

 

5. rsync常用参数

-v:显示rsync过程中详细信息。可以使用"-vvvv"获取更详细信息。
-P:显示文件传输的进度信息。(实际上"-P"="--partial --progress",其中的"--progress"才是显示进度信息的)。
-n --dry-run  :仅测试传输,而不实际传输。常和"-vvvv"配合使用来查看rsync是如何工作的。
-a --archive  :归档模式,表示递归传输并保持文件属性。等同于"-rtopgDl"。
-r --recursive:递归到目录中去。
-t --times:保持mtime属性。强烈建议任何时候都加上"-t",否则目标文件mtime会设置为系统时间,导致下次更新
          :检查出mtime不同从而导致增量传输无效。
-o --owner:保持owner属性(属主)。
-g --group:保持group属性(属组)。
-p --perms:保持perms属性(权限,不包括特殊权限)。
-D        :是"--device --specials"选项的组合,即也拷贝设备文件和特殊文件。
-l --links:如果文件是软链接文件,则拷贝软链接本身而非软链接所指向的对象。
-z        :传输时进行压缩提高效率。
-R --relative:使用相对路径。意味着将命令行中指定的全路径而非路径最尾部的文件名发送给服务端,包括它们的属性。用法见下文示例。
--size-only :默认算法是检查文件大小和mtime不同的文件,使用此选项将只检查文件大小。
-u --update :仅在源mtime比目标已存在文件的mtime新时才拷贝。注意,该选项是接收端判断的,不会影响删除行为。
-d --dirs   :以不递归的方式拷贝目录本身。默认递归时,如果源为"dir1/file1",则不会拷贝dir1目录,使用该选项将拷贝dir1但不拷贝file1。
--max-size  :限制rsync传输的最大文件大小。可以使用单位后缀,还可以是一个小数值(例如:"--max-size=1.5m")
--min-size  :限制rsync传输的最小文件大小。这可以用于禁止传输小文件或那些垃圾文件。
--exclude   :指定排除规则来排除不需要传输的文件。
--delete    :以SRC为主,对DEST进行同步。多则删之,少则补之。注意"--delete"是在接收端执行的,所以它是在
            :exclude/include规则生效之后才执行的。
-b --backup :对目标上已存在的文件做一个备份,备份的文件名后默认使用"~"做后缀。
--backup-dir:指定备份文件的保存路径。不指定时默认和待备份文件保存在同一目录下。
-e          :指定所要使用的远程shell程序,默认为ssh。
--port      :连接daemon时使用的端口号,默认为873端口。
--password-file:daemon模式时的密码文件,可以从中读取密码实现非交互式。注意,这不是远程shell认证的密码,而是rsync模块认证的密码。
-W --whole-file:rsync将不再使用增量传输,而是全量传输。在网络带宽高于磁盘带宽时,该选项比增量传输更高效。
--existing  :要求只更新目标端已存在的文件,目标端还不存在的文件不传输。注意,使用相对路径时如果上层目录不存在也不会传输。
--ignore-existing:要求只更新目标端不存在的文件。和"--existing"结合使用有特殊功能,见下文示例。
--remove-source-files:要求删除源端已经成功传输的文件。

常用参数
avz 相当于 vzrtopg
生产参数使用: avz 或者 -vzrtopg

 

6. Daemon模式(socket监听模式)

远程shell连接的两端是通过管道完成通信和数据传输的,即使连接的一端是远程主机,
当连接到目标端时,将在目标端上根据远程shell进程fork出rsync进程使其成为rsync
server。而rsync daemon是事先在server端上运行好的rsync后台进程(根据启动选项,
也可以设置为非后台进程),它监听套接字等待client端的连接,连接建立后所有通信方式
都是通过套接字完成的。

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
连接命令有两种类型:
一种是rsync风格使用双冒号的"rsync user@host::src dest"
一种是url风格的"rsync://user@host:port/src dest"。
对于rsync风格的连接命令,如果想要指定端口号,则需要使用选项"--port"。


上述语法中,其中daemon端的路径,如user@host::src,它的src代表的是模块名,
而不是真的文件系统中的路径。关于rsync中的模块,相信见了下面的配置文件就会知道

7. Daemon配置文件

默认配置文件
/etc/rsync.conf
默认"rsync --daemon"读取的配置文件为/etc/rsyncd.conf,有些版本的系统上可能该文
件默认不存在。rsyncd.conf的配置见man rsyncd.conf。以下是部分内容:



[root@xuexi ~]# cat /etc/rsyncd.conf
# /etc/rsyncd: configuration file for rsync daemon mode
 
# See rsyncd.conf man page for more options.
 
# configuration example:
 
# uid = nobody
# gid = nobody
# use chroot = yes
# max connections = 4
# pid file = /var/run/rsyncd.pid
# exclude = lost+found/
# transfer logging = yes
# timeout = 900
# ignore nonreadable = yes
# dont compress   = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2
 
# [ftp1]
#        path = /home/ftp
#        comment = ftp export area

在上述示例配置文件中,先定义了一些全局选项,然后定义了[ftp1],这个用中括号包围的
"[ftp1]"就是rsync中所谓的模块,ftp1为模块ID,必须保证唯一,每个模块中必须定义一
项"path",path定义的是该模块代表的路径,例如此示例文件中,如果想请求ftp1模块,
则在客户端使用"rsync user@host::ftp1",这表示访问user@host上的/home/ftp目录,
如果要访问/home/ftp目录下的子目录www,则"rsync user@host::ftp1/www"。

  常用全局参数

  

######### 全局配置参数 ##########
port=888    # 指定rsync端口。默认873
uid = rsync # rsync服务的运行用户,默认是nobody,文件传输成功后属主将是这个uid
gid = rsync # rsync服务的运行组,默认是nobody,文件传输成功后属组将是这个gid
use chroot = no # rsync daemon在传输前是否切换到指定的path目录下,并将其监禁在内
max connections = 200 # 指定最大连接数量,0表示没有限制
timeout = 300         # 确保rsync服务器不会永远等待一个崩溃的客户端,0表示永远等待
motd file = /var/rsyncd/rsync.motd   # 客户端连接过来显示的消息
pid file = /var/run/rsyncd.pid       # 指定rsync daemon的pid文件
lock file = /var/run/rsync.lock      # 指定锁文件
log file = /var/log/rsyncd.log       # 指定rsync的日志文件,而不把日志发送给syslog
dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2  # 指定哪些文件不用进行压缩传输

###########下面指定模块,并设定模块配置参数,可以创建多个模块###########
[longshuai]        # 模块ID
path = /longshuai/ # 指定该模块的路径,该参数必须指定。启动rsync服务前该目录必须存在。rsync请求访问模块本质就是访问该路径。
ignore errors      # 忽略某些IO错误信息
read only = false  # 指定该模块是否可读写,即能否上传文件,false表示可读写,true表示可读不可写。所有模块默认不可上传
write only = false # 指定该模式是否支持下载,设置为true表示客户端不能下载。所有模块默认可下载
list = false       # 客户端请求显示模块列表时,该模块是否显示出来,设置为false则该模块为隐藏模块。默认true
hosts allow = 10.0.0.0/24 # 指定允许连接到该模块的机器,多个ip用空格隔开或者设置区间
hosts deny = 0.0.0.0/32   # 指定不允许连接到该模块的机器
auth users = rsync_backup # 指定连接到该模块的用户列表,只有列表里的用户才能连接到模块,用户名和对应密码保存在secrts file中,
                          # 这里使用的不是系统用户,而是虚拟用户。不设置时,默认所有用户都能连接,但使用的是匿名连接
secrets file = /etc/rsyncd.passwd # 保存auth users用户列表的用户名和密码,每行包含一个username:passwd。由于"strict modes"
                                  # 默认为true,所以此文件要求非rsync daemon用户不可读写。只有启用了auth users该选项才有效。
[xiaofang]    # 以下定义的是第二个模块
path=/xiaofang/
read only = false
ignore errors
comment = anyone can access

注意事项
(1).客户端推到服务端时,文件的属主和属组是配置文件中指定的uid和gid。但是客户端从服务端拉的时候,文件的属主和属组是客户端正在操作rsync的用户身份,因为执行rsync程序的用户为当前用户。
(2).auth users和secrets file这两行不是一定需要的,省略它们时将默认使用匿名连接。但是如果使用了它们,则secrets file的权限必须是600。客户端的密码文件也必须是600。
(3).关于secrets file的权限,实际上并非一定是600,只要满足除了运行rsync daemon的用户可读即可。是否检查权限的设定是通过选项strict mode设置的,如果设置为false,则无需关注文件的权限。但默认是yes,即需要设置权限。

  启动daemon服务

rsync --daemon

  客户端连接方式

Pull: rsync [OPTION...] [USER@]HOST::SRC... [DEST]
        rsync [OPTION...] rsync://[USER@]HOST[:PORT]/SRC... [DEST]

  查看列表

rsync --list-only --port 888 rsync_backup@192.168.0.55::testfile/ --passwrod-file=/etc/rsync.passwd
# Pull
rsync -avz --port=888 rsync_backup@192.168.0.55::testfile/ --password-file=/etc/rsync.passwd
rsync -avz rsync://rsync_backup@192.168.0.55:888/testfile /data/ --password-file=/etc/rsync.passwd

  Push: rsync [OPTION...] SRC... [USER@]HOST::DEST
        rsync [OPTION...] SRC... rsync://[USER@]HOST[:PORT]/DEST
# Push
rsync -avz --port 888 /data/ rsync_backup@192.168.0.55::testfile --password-file=/etc/rsync.passwd
rsync -avz rsync://rsync_backup@192.168.0.55:888/testfile /data/ --password-file=/etc/rsync.passwd

  

8. 示例

Server端
1、添加用户
 
useradd rsync -s /sbin/nologin
2、创建目录
mkdir -p /data/testfile/
chown -R rsync: /data/testfile/

3、创建身份验证文件

注意:
1、rsync服务是由那个用户启动的,该文件所属用户及用户组必须同启动用户
2、权限必须是600
echo "rsync_backup:123456" >> /etc/rsyncd.passwd
chmod 600 /etc/rsyncd.passwd

4、rsync配置文件(/etc/rsyncd.conf有直接vi没有直接创建)

# vi /etc/rsyncd.conf
######### 全局配置参数 ##########
port=888
uid = rsync
gid = rsync
use chroot = no
max connections = 200
timeout =300 
motd file = /var/rsyncd/rsync.motd
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log
dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2

###########下面指定模块,并设定模块配置参数,可以创建多个模块###########
[testfile]
path = /data/testfile/ # 目录必须提前创建
ignore errors
read only = false
write only = false
#list = false
hosts allow = 192.168.0.0/24
#hosts deny = 0.0.0.0/32
auth users = rsync_backup
secrets file = /etc/rsyncd.passwd
5、启动服务
rsync --daemon

  

Client端
1、免密登录文件
echo "123456" >> /etc/rsyncd.passwd # 只放密码即可
通过--password-file=/etc/rsyncd.passwd 指定文件
连接方法看上方
# 一致性同步参数
--delete    :以SRC为主,对DEST进行同步。多则删之,少则补之。注意"--delete"是在接收端执行的,所以它是在
            :exclude/include规则生效之后才执行的。
本地有啥就推送啥,保持客户端与服务端的一致性
风险,就是客户端如果删除了,服务端一样会删除,如果出现问题可能没办法快速恢复
所以使用前,必须确定好需求

2、安装inotify

  (1)查看系统是否支持inotify

[root@ecs-9139-zk-0002 ~]# ll /proc/sys/fs/inotify
total 0
-rw-r--r-- 1 root root 0 Dec  7 10:35 max_queued_events
-rw-r--r-- 1 root root 0 Dec  7 10:35 max_user_instances
-rw-r--r-- 1 root root 0 Dec  7 10:35 max_user_watches

/proc/sys/fs/inotify/max_user_instances 初始化 ifd 的数量限制
/proc/sys/fs/inotify/max_queued_events ifd 文件队列长度限制
/proc/sys/fs/inotify/max_user_watches 注册监听目录的数量限制
既然是文件描述符,当然也受 /etc/security/limits.conf 和 /proc/sys/fs/file-max 限制

  (2)检查是否有安装inotify 如果没有就安装

[root@ecs-9139-zk-0002 ~]# rpm -qa inotify-tools
[root@ecs-9139-zk-0002 ~]#  yum install inotify-tools –y
yum没有就用源码安装
wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz
tar -xf inotify-tools-3.14.tar.gz
cd inotify-tools-3.14
./configure --prefix=/usr/local/inontify-tools-3.14
make&&make install
ln -s /usr/local/inontify-tools-3.14 /usr/local/inontify

  (3)测试监听路径

inotifywait -mrq --timefmt ‘%y %m %d %H %M --format ‘%T %w%f’ -e creat /backup
[root@ecs-9139-zk-0002 test]# inotifywait -mrq --format "%w%f" -e create /opt/test
T 是指时间 w 是指路径 f 是指文件  详情看下方参数

  inotify常用参数

参数
说明
含义
-r
--recursive
#递归查询目录
-q
--quiet
#打印很少的信息,仅仅打印监控事件信息
-m
--monitor  
#始终保持事件监听状态
--excludei
 
#排除文件或目录时,不区分大小写
--timefmt
 
#指定事件输出格式
--format
 
#打印使用指定的输出类似格式字符串
-e
--event[ -e|--event ... ]
access
modify
attrib
close
open
move_to
move
 
create
delete
umount
#通过此参数可以指定要监控的事件
 
#文件或目录被读取
#文件或目录的内容被修改
#文件或目录属性被改变
#文件或目录封闭,无论读/写模式
#文件或目录被打开
#文件或目录被移动至另外一个目录
#文件或目录被移动另一个目录或从另一个目录移动至当前目录
#文件或目录被创建在当前目录
#文件或目录被删除
#文件系统被卸载

 

3、简单的模拟监控脚本
#!/bin/bash

listen_path=/opt/test/
backup_server=192.168.0.55
backup_port=888
moude_name=testfile
user_name=rsync_backup
user_pwd_file=/etc/rsync.passwd


inotifywait -mrq --format "%w%f" -e create,delete,close_write $listen_path |while read line
do
    if [ -f $line ]
    then
        rsync -avz --port $backup_port $listen_path $user_name@$backup_server::$moude_name --password-file=/etc/rsync.passwd
    else
        rsync -avz --port $backup_port $listen_path $user_name@$backup_server::$moude_name --delete --password-file=/etc/rsync.passwd
    fi
done

4、问题分析

inotify+rsync分析
rq --format '%w%f'-e create,close_write,delete /backup |while read file
#把发生更改的文件列表都接收到file 然后循环,但有什么鬼用呢?下面的命令都没有引用这个$file 下面做的是全量rsync
do 
    cd /backup && rsync -az --delete /backup/ rsync_backup@192.168.24.101::backup/--password-file=/etc/rsync.password 
done

#注意看 这里的rsync 每次都是全量的同步(这就坑爹了),而且 file列表是循环形式触发rsync ,等于有10个文件发生更改,就触发10次rsync全量同步(简直就是噩梦),那还不如直接写个死循环的rsync全量同步得了。

#有很多人会说 日志输出那里明明只有差异文件的同步记录。其实这是rsync的功能,他本来就只会输出有差异需要同步的文件信息。不信你直接拿这句rsync来跑试试。

#这种在需要同步的源目录文件量很大的情况下,简直是不堪重负。不仅耗CPU还耗时,根本不可以做到实时同步。
备注:backup为rsync server配置module,除了编写脚本以外,还需要配置一个rsync server,rsync server配置参考《http://www.ttlsa.com/linux/rsync-install-on-linux/》


改良方法
要做到实时,就必须要减少rsync对目录的递归扫描判断,尽可能的做到只同步inotify监控到已发生更改的文件。结合rsync的特性,所以这里要分开判断来实现一个目录的增删改查对应的操作。


每两小时做1次全量同步
ntab -e
* */2 * * * rsync -avz --password-file=/etc/rsync-client.pass 
因为inotify只在启动时会监控目录,他没有启动期间的文件发生更改,他是不知道的,所以这里每2个小时做1次全量同步,防止各种意外遗漏,保证目录一致。
改良后我们公司这种百万级小文件也能做到实施同步了。

 5、改良示例

in/bash
src=/data/                           # 需要同步的源路径
des=data                             # 目标服务器上 rsync --daemon 发布的名称,rsync --daemon这里就不做介绍了,网上搜一下,比较简单。
rsync_passwd_file=/etc/rsyncd.passwd            # rsync验证的密码文件
ip1=192.168.0.18                 # 目标服务器1
ip2=192.168.0.19                 # 目标服务器2
user=root                            # rsync --daemon定义的验证用户名
cd ${src}                              # 此方法中,由于rsync同步的特性,这里必须要先cd到源目录,inotify再监听 ./ 才能rsync同步后目录结构一致,有兴趣的同学可以进行各种尝试观看其效果
/usr/local/bin/inotifywait -mrq --format  '%Xe %w%f' -e modify,create,delete,attrib,close_write,move ./ | while read file         # 把监控到有发生更改的"文件路径列表"循环
do
        INO_EVENT=$(echo $file | awk '{print $1}')      # 把inotify输出切割 把事件类型部分赋值给INO_EVENT
        INO_FILE=$(echo $file | awk '{print $2}')       # 把inotify输出切割 把文件路径部分赋值给INO_FILE
        echo "-------------------------------$(date)------------------------------------"
        echo $file
        #增加、修改、写入完成、移动进事件
        #增、改放在同一个判断,因为他们都肯定是针对文件的操作,即使是新建目录,要同步的也只是一个空目录,不会影响速度。
        if [[ $INO_EVENT =~ 'CREATE' ]] || [[ $INO_EVENT =~ 'MODIFY' ]] || [[ $INO_EVENT =~ 'CLOSE_WRITE' ]] || [[ $INO_EVENT =~ 'MOVED_TO' ]]         # 判断事件类型
        then
                echo 'CREATE or MODIFY or CLOSE_WRITE or MOVED_TO'
                rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::${des} &&         # INO_FILE变量代表路径哦  -c校验文件内容
                rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip2}::${des}
                 #仔细看 上面的rsync同步命令 源是用了$(dirname ${INO_FILE})变量 即每次只针对性的同步发生改变的文件的目录(只同步目标文件的方法在生产环境的某些极端环境下会漏文件 现在可以在不漏文件下也有不错的速度 做到平衡) 然后用-R参数把源的目录结构递归到目标后面 保证目录结构一致性
        fi
        #删除、移动出事件
        if [[ $INO_EVENT =~ 'DELETE' ]] || [[ $INO_EVENT =~ 'MOVED_FROM' ]]
        then
                echo 'DELETE or MOVED_FROM'
                rsync -avzR --delete --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::${des} &&
                rsync -avzR --delete --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip2}::${des}
                #看rsync命令 如果直接同步已删除的路径${INO_FILE}会报no such or directory错误 所以这里同步的源是被删文件或目录的上一级路径,并加上--delete来删除目标上有而源中没有的文件,这里不能做到指定文件删除,如果删除的路径越靠近根,则同步的目录月多,同步删除的操作就越花时间。这里有更好方法的同学,欢迎交流。
        fi
        #修改属性事件 指 touch chgrp chmod chown等操作
        if [[ $INO_EVENT =~ 'ATTRIB' ]]
        then
                echo 'ATTRIB'
                if [ ! -d "$INO_FILE" ]                 # 如果修改属性的是目录 则不同步,因为同步目录会发生递归扫描,等此目录下的文件发生同步时,rsync会顺带更新此目录。
                then
                        rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::${des} &&            
                        rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip2}::${des}
                fi
        fi
done

  

  

 

posted @ 2022-03-10 14:43  总要做些什么  阅读(574)  评论(0编辑  收藏  举报