rsync(remote sync)是类unix系统中的一款远程数据同步工具,使用所谓的“rsync算法”来使本地和远程主机之间的文件达到同步(也可在同一主机内部实现数据同步),这个算法只传送两个文件的不同部分,而不是每次都整份传送,因此速度很快。

  rsync同步数据时,需要扫描所有文件后对比,进行差量传输,因此不适宜同步海量小文件,因为这个扫描对比的过程将会非常耗时。


一、rsync的特性

  ①可以镜像保存整个目录树或文件系统;

  ②较高的数据传输效率;

  ③可以借助于ssh实现安全数据传输;

  ④支持匿名传输;


二、rsync命令的工作模式

  ⑴shell模式,也称作本地模式,同一主机内实现数据同步

    rsync [OPTION...] SRC... [DEST]

    例:rsync -avz /etc/httpd/ /tmp/test

  ⑵远程shell模式,可以利用ssh协议承载其远程传输过程;

    rsync [OPTION...] SRC... [USER@]HOST:DEST

    rsync [OPTION...] [USER@]HOST:SRC... [DEST]

    例:rsync -avz -e 'ssh -p 7788' tesla@192.168.30.10:/etc/fstab /tmp/test

  ⑶列表模式,仅列出源中的内容,-nv

  ⑷服务模式,此时rsync工作为守护进程,能接收客户端的数据同步请求;

   ①从服务端拉取数据(pull):

       rsync [OPTION...] [USER@]HOST::SRC... [DEST]   #守护进程模式中服务器的路径以模块名打头

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

       例:rsync -avz tom@192.168.30.20::tools/test.txt /tmp/

   ②向服务端推送数据(push):

       rsync [OPTION...] SRC... [USER@]HOST::DEST

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

       例:rsync -avz /mydata rsync://tom@192.168.30.20/tools/

  注意:远程shell模式使用单冒号,守护进程模式使用双冒号


三、rsync命令的选项

    -n:同步测试,不执行真正的同步过程;

    -v:详细输出模式

    -q:静默模式

    -c:checksum,开启校验功能

    -r:递归复制  #源路径若为目录,需要指定该选项(或-a)

    -a:归档,保留文件的原有属性;相当于-rptlgoD

    -p:保留文件的权限

    -t:保留文件的时间戳

    -l:保留符号链接

    -g:保留属组

    -o:保留属主

    -D:保留设备文件

    -e ssh:使用ssh作为传输承载,更安全

        如 -e 'ssh -p 2345'

    -z:压缩后传输

    --delete:删除那些DST中SRC没有的文件,此选项能使源和目标完全一致,常用于快速删除大量数据

    --existing:仅仅更新那些已经存在于DST的文件

    --exclude=PATTERN:指定排除不需要传输的文件模式

      如 --exclude=a --exclude={b,c} --exclude={d..g} --exclude=*.txt

    --exclude-from=FILE:排除FILE中指定模式的文件,FILE中的内容要使用相对路径

    --password-file=FILE:从FILE中得到密码,仅能应用于rsync服务模式中

    --bwlimit=KBPS  #实际环境中应限制速率,以免导致巨大的CPU消耗

      例:--bwlimit=100(不用带单位)

    --progress:显示进度条

    --stats:显示如何执行压缩和传输

    说明:

      ①rsync命令中,如果源路径是目录,且其末尾有“/”,则会复制目录中的内容,而非目录本身;如果末尾没有“/”,则会同步目录本身及目录中的所有文件;目标路径末尾是否有“/”无关紧要;

      ②文件访问时间等属性、读写等权限、文件内容等有任何变动,都会被认为修改

      ③目标目录下如果文件比源目录还新,则不会同步

[root@node2 ~]# rpm -ql rsync
/etc/xinetd.d/rsync   #rsync若工作于守护进程,可接受超级守护进程管理
/usr/bin/rsync
/usr/share/doc/rsync-3.0.6
/usr/share/doc/rsync-3.0.6/COPYING
/usr/share/doc/rsync-3.0.6/NEWS
/usr/share/doc/rsync-3.0.6/OLDNEWS
/usr/share/doc/rsync-3.0.6/README
/usr/share/doc/rsync-3.0.6/support
...
/usr/share/man/man5/rsyncd.conf.5.gz   #可参考该文档创建配置文件
[root@node2 ~]# ls /etc/httpd
conf  conf.d  logs  modules  run  ssl
[root@node2 ~]# rsync /etc/httpd/ /tmp/test
skipping directory .   #源路径若为目录,需要指定-r或-a选项,否则不予同步
[root@node2 ~]# rsync -av /etc/httpd/ /tmp/test
sending incremental file list
./
logs -> ../../var/log/httpd
modules -> ../../usr/lib64/httpd/modules
run -> ../../var/run/httpd
conf.d/
conf.d/README
conf.d/php.conf
conf.d/ssl.conf
conf.d/welcome.conf
conf.d/welcome.conf.back
conf/
conf/.htpasswd
conf/httpd.conf
conf/magic
ssl/
ssl/httpd.crt
ssl/httpd.csr
ssl/httpd.key

sent 67856 bytes  received 245 bytes  136202.00 bytes/sec
total size is 66998  speedup is 0.98
[root@node2 ~]# ls /tmp/test
conf  conf.d  logs  modules  run  ssl
[root@node2 ~]# touch /etc/httpd/abc
[root@node2 ~]# rsync -av /etc/httpd/ /tmp/test
sending incremental file list
./
abc   #只会复制变动的部分

sent 481 bytes  received 37 bytes  1036.00 bytes/sec
total size is 66998  speedup is 129.34
[root@node2 ~]# rsync -av /etc/httpd /tmp/test   #源目录不带/会连同复制目录本身
sending incremental file list
httpd/
httpd/abc
httpd/logs -> ../../var/log/httpd
httpd/modules -> ../../usr/lib64/httpd/modules
httpd/run -> ../../var/run/httpd
httpd/conf.d/
httpd/conf.d/README
...

sent 67924 bytes  received 265 bytes  136378.00 bytes/sec
total size is 66998  speedup is 0.98
[root@node2 ~]# ls /tmp/test
abc  conf  conf.d  httpd  logs  modules  run  ssl
[root@node2 ~]# mkdir /tmp/empty   #创建一个空目录
[root@node2 ~]# rsync -av --delete /tmp/empty/ /tmp/test   #这种用法可用于快速清除大量数据
sending incremental file list
./
deleting ssl/httpd.key
deleting ssl/httpd.csr
deleting ssl/httpd.crt
deleting ssl/
deleting httpd/ssl/httpd.key
...
total size is 0  speedup is 0.00
[root@node2 ~]# ls /tmp/test   #test目录已被清空
[root@node2 ~]# rsync /etc/fstab root@192.168.30.10:/tmp/ceshi   #远程shell模式
root@192.168.30.10's password:
[root@node2 ~]# rsync -a tesla@192.168.30.10:/etc/selinux/config /tmp/test
tesla@192.168.30.10's password: 
[root@node2 ~]# ls /tmp/test
config
[root@node1 ~]# ls /tmp/ceshi
fstab


四、rsync的Client-Server模式

  1、rsync服务端

    ⑴为rsync提供配置文件

      /etc/rsyncd.conf   #修改该配置文件后无须重启守护进程,每一次客户端连接都会读取该文件

      配置文件分两段:

        全局配置段:一个

        模块配置段:多个

      配置示例

        # Global Settings

        uid = rsync   #以什么用户身份存取模块目录

        gid = rsync

        use chroot = no  #chroot为yes时必须使用root身份

        max connections = 10

        timeout = 300  #该选项可以确保rsync服务器不会永远等待一个崩溃的客户端

        strict modes = yes

        pid file = /var/run/rsyncd.pid

        [lock file =  /var/run/rsyncd.lock]

        log file = /var/log/rsyncd.log

        log format = %t %a %m %f %b

        motd file = /etc/rsyncd/rsyncd.motd   #该文件定义客户端连接时所看到的信息,非必须


        # Directory to be synced

        [tools]    #模块名

        path = /data   #需要做镜像的目录

        comment = some important software  #可给模块指定描述信息

        ignore errors = yes

        read only = no

        write only = no

        hosts allow = 172.16.0.0/16   #可以是ip、网段、可解析的主机名、域名

        hosts deny = *  #表示所有

        list = false(或no)  #当客户请求列出可以使用的模块列表时,该模块是否应该被列出

        uid = root  #进程以什么身份对该模块进行存取;若不指定,则继承全局配置段中的设定

        gid = root

        exclude = DIR1 DIR2 FILE1...  #排除不要同步的文件或目录,多个文件或目录用空格隔开

    ⑵服务端可启用用户认证的功能

      ①在全局或模块配置段中添加:

         auth users = USERNAME LIST

         secrets file = /etc/rsyncd.passwd

         说明:USERNAME LIST为以逗号分隔的在rsyncd.passwd中存在的用户名的列表

      ②创建用户密码文件/etc/rsyncd.passwd

         格式:username:password

         这里的用户名和密码与操作系统的用户名密码无关,可任意指定

         此文件不能允许其它用户有访问权限(将其权限设置为600),且密码不能超过8个字符

    ⑶创建存取用户和模块目录

        useradd -M -s /sbin/nologin rsync

        mkdir -p /data

        chown -R rsync.rsync /data

    ⑷启动服务

        当rsync服务器负载较低时,可交由超级守护进程xinetd管理,这也是默认方式

          chkconfig rsync on(或编辑/etc/xinetd.d/rsync文件,将disable 改为 no)

          service xinetd start   #默认监听于873/tcp

        当rsync服务器负载较高时,可启动为独立守护进程

          rsync --daemon [--config=FILE] [--port=PORT]

        有时还需要在防火墙上开放端口:

          iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 873 -j ACCEPT

[root@node2 ~]# vim /etc/rsyncd.conf

# Global Settings
uid = nobody
gid = nobody
use chroot = no
max connections = 10
strict modes = yes
timeout = 300
pid file = /var/run/rsyncd.pid
log file = /var/log/rsyncd.log

# Directory to be synced
[tools]
path = /data
ignore errors = yes
read only = no
write only = no
hosts allow = 192.168.30.0/24
hosts deny = *
list = false
auth users = tom, jerry
secrets file = /etc/rsyncd.passwd
[root@node2 ~]# vim /etc/rsyncd.passwd   #创建密码文件

tom:hello
jerry:linux
rose:titanic
[root@node2 ~]# chmod 600 /etc/rsyncd.passwd
[root@node2 ~]# service xinetd restart
Stopping xinetd:                                           [  OK  ]
Starting xinetd:                                           [  OK  ]
[root@node2 ~]# ss -tnl   #873端口已监听
...
LISTEN      0      64                     :::873


  2、rsync客户端

    ⑴生成连接服务端需要的密码文件

         echo "hello" >> /etc/rsync.passwd

         chmod 600 /etc/rsync.passwd

    ⑵同步文件

         推送:

           rsync -avz /tmp/ tom@192.168.30.20::tools --password-file=/etc/rsync.passwd

           rsync -avz /tmp/ rsync://tom@192.168.30.20/tools --password-file=/etc/rsync.passwd

         拉取:

           rsync -avz tom@192.168.30.20::tools /tmp/ --password-file=/etc/rsync.passwd

           rsync -avz rsync://tom@192.168.30.20/tools /tmp/ --password-file=/etc/rsync.passwd


[root@node1 ~]# echo "hello" >> /etc/rsync.passwd
[root@node1 ~]# chmod 600 /etc/rsync.passwd
[root@node1 ~]# rsync -avz tom@192.168.30.20::tools/test.txt /tmp/ceshi --password-file=/etc/rsync.passwd  #从rsync服务器拉取数据
...
[root@node1 ~]# ls /tmp/ceshi
test.txt

  测试中遇到一个问题,客户端向服务器端推送数据不成功,检查发现配置文件的模块配置段中未指定uid,因此直接继承了全局配置段中的uid设定,而全局配置段中的uid = nobody,它对模块目录/data没有写入权限,从而造成客户端无法推送数据。

      解决办法:修改模块目录属主属组

[root@node1 ~]# rsync -avz iptables.nat tom@192.168.30.20::tools/ -password-file=/etc/rsync.passwd   #提示向服务器推送数据不成功
rsync: mkstemp ".iptables.nat.6elLqN" (in tools) failed: Permission denied (13)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1039) [sender=3.0.6]
[root@node2 ~]# ls -ld /data
drwxrwxr-x+ 2 root root 4096 Nov 24 22:17 /data
[root@node2 ~]# chown -R nobody.nobody /data
[root@node1 ~]# rsync -avz iptables.nat tom@192.168.30.20::tools/
...
[root@node2 ~]# ls /data
fstab  iptables.nat  test.txt


六、rsync+inotify 实现数据实时同步

  rsync不能实时地去监测、同步数据,虽然它可以通过crontab(周期性任务计划)方式触发同步,但是两次触发动作之间必然会有时间差,这样就可能导致客户端和服务端数据不一致,无法在应用故障时完全的恢复数据。而rsync+inotify就能够很好的解决这个问题。

  inotify是一种强大的、细粒度的、异步的文件系统事件监控机制,Linux内核从2.6.13开始引入,允许监控工具(如inotifywait)监控文件系统下文件的各种变化事件,如添加、删除、修改、移动,当有变动发生时,就触发rsync同步,从而解决数据同步的实时性问题。

  查看系统是否支持inotify机制

    ls /proc/sys/fs/inotify/,若出现以下三个文件,则支持,否则不支持:

      max_queued_events  max_user_instances  max_user_watches

  数据源是主动同步的一方,而备份源是被动的一方,我们要在数据源上触发rsync同步操作,由此,应该将数据源作为rsync客户端,将备份源作为rsync服务器端

  1、rsync服务器端配置(略,见上方)

  2、客户端配置

    ⑴安装软件包:

     yum -y install inotify-tools  #inotifywait由inotify-tools包提供

    ⑵提供密码文件:

     vim /etc/rsync_client.passwd   #只需要输入一个密码,就是打算用于连接rsync服务器的用户对应的密码

     chmod 600 /etc/rsync_client.passwd

    ⑶编写同步脚本

     vim /root/scripts/rsync.sh

     chmod +x /root/scripts/rsync.sh

     /root/scripts/rsync.sh &

     echo "nohup /root/scripts/rsync.sh &" >> /etc/rc.local   #让数据同步脚本随开机执行

  3、inotifywait

    用法:inotifywait [-hcmrq] [-e <event> ] [-t <seconds> ] [--format <fmt> ] [--timefmt <fmt> ] <file> [ ... ]

    选项:

      -m:监视

      -r:递归监视

      -q:减少冗余信息

      -e/--event:要监视的事件列表;

        可监视的事件:create,delete,modify,move,access,attrib(元数据被修改),open,close

      -t seconds:过期时长,即超出该时长退出监视,缺省为0,表示无限期监视

      --format:指定事件信息的输出格式

        %w:发生事件的目录或文件

        %f:发生事件的文件

        %e:发生的事件

        %T:使用由-timefmt定义的时间格式

      --timefmt:指定时间格式,具体用法可man inotifywait

      --exclude <pattern>:指定排除不需要监视的文件模式

      --fromfile <file>:从file中读取要监视或排除监视的文件(或目录),一行一个,不能使用正则表达式,以@开头的表示排除监视

    例:inotifywait -mrq --timefmt '%Y/%m/%d-%H:%M:%S' --format '%T %w %f %e' -e modify,delete,create,move,attrib /tmp/test


  以下node1为客户端,node2为服务端:

[root@node1 ~]# yum -y install inotify-tools   #来自于epel源
...

Installed:
  inotify-tools.x86_64 0:3.14-1.el6                                                                                                                                        

Complete!
[root@node1 ~]# rpm -ql inotify-tools
/usr/bin/inotifywait   #文件系统监视工具
/usr/bin/inotifywatch   #统计文件系统访问的次数
/usr/lib64/libinotifytools.so.0
/usr/lib64/libinotifytools.so.0.4.1
/usr/share/doc/inotify-tools-3.14
/usr/share/doc/inotify-tools-3.14/AUTHORS
/usr/share/doc/inotify-tools-3.14/COPYING
/usr/share/doc/inotify-tools-3.14/ChangeLog
/usr/share/doc/inotify-tools-3.14/NEWS
/usr/share/doc/inotify-tools-3.14/README
/usr/share/man/man1/inotifywait.1.gz
/usr/share/man/man1/inotifywatch.1.gz
[root@node1 ~]# vim /etc/rsync_client.passwd

hello
[root@node1 ~]# chmod 600 /etc/rsync_client.passwd

[root@node1 ~]# vim scripts/rsync.sh   #创建数据同步脚本

#!/bin/bash

src=/tmp/test/
log_file=/var/log/rsync_client.log

server=192.168.30.20
user=tom
pwd_file=/etc/rsync_client.passwd
module=tools

inotify_fun(){
    /usr/bin/inotifywait -mrq --timefmt '%Y/%m/%d-%H:%M:%S' --format '%T %w %f %e' \
          -e modify,delete,create,move,attrib $src | while read file
      do
          /usr/bin/rsync -avz --delete --bwlimit=200 --password-file=${pwd_file} $src $user@$server::$module
      done
}

inotify_fun >> ${log_file} 2>&1 &

[root@node1 ~]# chmod +x !$   #给脚本设置执行权限
chmod +x scripts/rsync.sh

echo "nohup /root/scripts/rsync.sh &" >> /etc/rc.local
[root@node1 ~]# bash -n scripts/rsync.sh   #语法检查
[root@node1 ~]# scripts/rsync.sh &
[1] 6155
[root@node1 ~]# echo "nohup /root/scripts/rsync.sh &" >> /etc/rc.local
[root@node1 ~]# cp a.txt anaconda-ks.cfg /tmp/test 
[root@node1 ~]# ls /tmp/test
anaconda-ks.cfg  a.txt  tesla.txt
[root@node2 ~]# ls /data
anaconda-ks.cfg  a.txt  tesla.txt
[root@node1 ~]# rm -f /tmp/test/a.txt
[root@node2 ~]# ls /data
anaconda-ks.cfg  tesla.txt