通过rsync+inotify-tools+ssh实现触发式远程实时同步


文件的同步镜像在很多地方都需要用到,因此rsync这款免费软件得到了广泛的应用,包括在Windows平台上,都已经有了支持rsync的“cwRsyncServer”。
但是,我们一般都是通过结合crontab计划任务来实现文件同步的,这样做的缺点是效率低,不能做到实时同步。
现在,在Linux平台下我们可以利用2.6内核的inotify监控文件系统机制,通过inotify-tools来实现实时同步了。
具体操作如下:

1.安装所需软件
目前各大Linux发行版本都已经具有了rsync与inotify-tools的软件包,推荐通过RPM,yum,apt-get等方式进行安装。
RHEL:
[root@server1 ~]# rpm -ivh rsync-*
[root@server1 ~]# rpm -ivh inotify-tools-*

CentOS:
[root@server1 ~]# yum install rsync inotify-tools

Ubuntu:
[root@server1 ~]# apt-get install rsync inotify-tools

采用源码方式安装的步骤如下:
[root@server1 ~]# wget ftp://ftp.samba.org/pub/rsync/rsync-3.0.8.tar.gz
[root@server1 ~]# tar xzvf rsync-3.0.8.tar.gz
[root@server1 ~]# cd rsync-3.0.8
[root@server1 ~]# ./configure
[root@server1 ~]# make
[root@server1 ~]# make install

[root@server1 ~]# wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz
[root@server1 ~]# tar xzvf inotify-tools-3.14.tar.gz
[root@server1 ~]# cd inotify-tools-3.14
[root@server1 ~]# ./configure
[root@server1 ~]# make
[root@server1 ~]# make install

2.配置ssh key信任
建议通过普通用户进行操作,理由是通过root操作本身就危险,免密码登陆的root就更危险了。

在两台服务器上创建rsync用户
[root@server1 ~]# useradd -m rsync
[root@server1 ~]# passwd rsync
[root@server2 ~]# useradd -m rsync
[root@server2 ~]# passwd rsync

[root@server1 ~]# su - rsync
[rsync@server1 ~]$ ssh-keygen -t rsa
在提示保存私钥(key)和公钥(public key)的位置时,使用默认值;
在提示是否需要私钥密码(passphrase)时,直接敲回车,即不使用私钥密码。
之后,将生成一对密钥,id_rsa(私钥文件)和id_rsa.pub(公钥文件),保存在/home/rsync/.ssh/目录下。

将公钥添加到远程主机的 authorized_keys 文件中
将文件上传到远程主机(假设远程主机IP为192.168.10.4)
[rsync@server1 ~]$ scp ~/.ssh/id_rsa.pub rsync@192.168.10.4:/home/rsync/

使用rsync用户SSH到登陆到远程主机,并将公钥添加到 authorized_keys 文件中
[rsync@server2 ~]$ mkdir .ssh
[rsync@server2 ~]$ chmod 700 .ssh
[rsync@server2 ~]$ mv ~/id_rsa.pub ~/.ssh/authorized_keys

重启SSH服务
[root@server1 ~]# /etc/init.d/sshd restart
[root@server2 ~]# /etc/init.d/sshd restart

3.创建inotify_rsync.sh脚本
[root@server1 ~]# vim inotify_rsync.sh

#!/bin/sh
SRC=/home/rsync/test
DST=rsync@192.168.10.4:/home/rsync/test

su - rsync
inotifywait -mrq -e modify,delete,create,attrib ${src} | while read D E F  
        do  
                /usr/bin/rsync -ahqzt --delete $SRC $DST
        done

相关注解如下:
/usr/local/bin/inotifywait -mrq -e modify,delete,create,attrib ${src}
-m 是保持一直监听
-r 是递归查看目录
-q 是打印出事件
-e create,move,delete,modify,attrib 是指 “监听 创建 移动 删除 写入 权限” 事件

/usr/bin/rsync -ahqzt --delete $SRC $DST
-a 存档模式
-h 保存硬连接
-q 制止非错误信息
-z 压缩文件数据在传输
-t 维护修改时间
-delete 删除于多余文件

要排除同步某个目录时,为rsync添加--exculde=PATTERN参数,注意,路径是相对路径,具体查看man rsync。
要排除某个目录的事件监听的处理时,为inotifywait添加--exclude或--excludei参数,具体查看man inotifywait。

inotifywait 命令产生三个返回值,分别是“日期,时间,文件” 这3个返回值会做为参数传给read,因此脚本中的“while read D E F” 写法细化了返回值。

赋予脚本可执行权限
[root@server1 ~]# chmod +x inotify_rsync.sh
执行脚本
[root@server1 ~]# /root/inotify_rsync.sh &
设置脚本开机自启动
[root@server1 ~]# cat "/root/inotify_rsync.sh &" >> /etc/rc.local

4.测试
首先在server1服务器的/home/rsync/test目录下创建文件或目录,然后再到server2的/home/rsync/test目录下查看,如果看到就说明成功了。
[rsync@server1 ~]$ cd test
[rsync@server1 test]$ touch a.txt
注意:第一次SSH连接的时候可能需要输入一次密码,之后就不需要输入了。

[rsync@server2 ~]$ cd test
[rsync@server2 test]$ ls
a.txt

看到了a.txt文件,说明文件同步已经成功!

,

  1. #1 by Eman on 2011/05/25 - 15:50

    就跟着这篇文章做一个笔记吧,如果有生成了key并添加到authorized_keys后还是需要密码登陆的情况,要注意检查 .ssh 目录和文件的权限,属主是否正确,目录权限是否为700,文件权限是否为600。

  2. #2 by Eman on 2011/06/01 - 15:40

    其实通过 ssh-copy-id -i ~/.ssh/id_rsa.pub rsync@192.168.10.4 就可以自动创建并添加到authorized_keys文件中,不需要文章中那繁琐的四个步骤。

  3. #3 by Eman on 2011/07/12 - 13:40

    本文的思路是两边都创建一个rsync用户,然后通过rsync用户来做同步,但实际情况中往往本端server1却需要root用户来执行,这个时候可直接通过
    ssh -i /home/rsync/.ssh/id_rsa rsync@192.168.10.4 方式指定生成的rsync用户的私钥key来登录。
    另外也可以切换到root用户身份在server1上生成public key并添加到被登录端server2的rsync用户的authorized_keys中;

  4. #4 by jerry on 2012/04/12 - 15:04

    您好,博主,请问rsync+inotify,就您这个实验来说,是不是Server1和Server2上面都要安装rsync+inotify?

    • #5 by mcsrainbow on 2012/04/12 - 17:30

      看你用什么方式,可以“取”也可以“推”,都只需要在执行rsync命令的一方安装就OK了。

  5. #6 by annan on 2012/04/27 - 13:57

    你的这个实时同步只是单向而不是双向的吧?这种方式能实现双向同步吗?

  6. #8 by sunpeng on 2012/06/05 - 18:04

    如果有多个目录需要同步,脚本应该如何写呢?

  7. #9 by neverno on 2012/10/12 - 14:17

    while D E F
    是 while read D E F 吧~
    细化返回结果后不输出个 log 文件,细化变得毫无意义。

    • #10 by mcsrainbow on 2012/10/12 - 15:05

      谢谢指出,已经修改了。

  8. #11 by mcsrainbow on 2014/05/12 - 14:00

    有人将inotify与rsync集成,制作了一个软件包lsyncd,可以直接通过yum从EPEL仓库安装了。

  9. #12 by Neo on 2014/11/21 - 11:49

    博主您好,在实现开机启动的这个功能时,按照文章中去rc.local里添加/root/inotify_rsync.sh &这一行,重启后检测,发现同步的功能没有实现,可是ps -ef grep inotify_rsync.sh后还是能看到两个进程root 1559 1558 0 11:20 ? 00:00:00 /bin/sh /root/inotify_rsync.sh
    root 1561 1559 0 11:20 ? 00:00:00 /bin/sh /root/inotify_rsync.sh
    不知道为什么没有实现功能,而如果再手动执行/root/inotify_rsync.sh & 或者 去掉开机启动的那一行,直接执行/root/inotify_rsync.sh &,都可以实现检测与同步的功能,断开终端以后再连上也没问题。本机上rc.local与启动的软连接都没问题,也想过把这个功能与博主另一个文章《在CentOS上编写init.d service script》,可是也是有问题,特别是,单独启动脚本后,就没有在/var/run里创建pid文件,不知道怎么办,机子是centos6.5, 希望博主能看看,谢谢了

    • #13 by mcsrainbow on 2014/11/21 - 12:05

      把你的两个脚本都通过附件发到我邮箱guosuiyu@gmail.com,帮你看看。

(will not be published)
*