使用sersync +rsync进行实时文件同步

使用sersync +rsync进行实时文件同步

rsync的使用

基本介绍

rsync是一个文件同步工具,rsync在同步的时候,只同步发生变化的文件或者目录(每次发生变化的数据相对整个同步目录数据来说是很小的,rsync在遍历查找比对文件时,速度很快),因此,效率很高。

rsync有两种工作模式,客户端和服务器端,即rsync的客户端和服务器端是同一个程序,名字都叫rsync,你用它启动了服务作为守护进程,它就是一个服务器端,你没启动服务,而是直接调用它的命令,那么它就是客户端。

方案讨论

假设有A、B两台服务器,我们要把A的文件同步到B,由于rsync的工作模式为客户端从服务器端下载文件(pull操作),或者客户端把文件推送到服务器端(push操作),所以我们要讨论一个问题,A、B谁做客户端,谁做服务器端?

方案一:
假设A做服务器端,B做客户端,那么B要从A中同步文件,就要启动定时任务,每隔一段时间执行一次同步命令,该命令会把A中的变化数据同步过来(实际上是做rsync客户端做pull操作)。

方案二:
假设A做客户端,B做服务器端,A定时运行同步命令,把变化文件推送到B(rsync客户端做push操作)

这两个方案感觉都可以,那到底哪个好呢?
假设我们还有C、D两台服务器也要从A同步文件,也就是B、C和D都从A同步文件,假设用方案一,那么B、C和D都要设置一个定时任务,定时从A中拉取文件进行同步,但这有一个问题,无法实时同步,因为B、C和D都不知道A什么时候更新了文件,只能定时去同步。

如果使用方案二,则B、C和D都是rsync的服务器端(都要启动一个rsync守护进程),而客户端只有一个,就是A。假如我们在A中添加定时任务,定时执行同步命令,把A中的文件推送到B、C和D,那感觉和方案一没什么区别,也是无法实时同步文件。

但是,在方案二中,我们可以利用sersync来检测哪些文件更新了,然后用sersync调用rsync的同步命令,把更新变化的文件推送到。
另外,还可以用git hooks,svn hooks,即所谓的钩子,即把A作为发布机,git/svn在上面更新文件后,可以“顺便”调用一下rsync同步命令,这样就能做到每次发布的时候“顺便”把文件也同步到B、C和D了。

配置rsync服务器端

根据前面的分析,我们使用方案二,A作为客户端,B、C和D作为rsync服务器端,,由于是开虚拟机做实验,为了方便,我们把D去掉,只配置三台,因为B、C、D的配置是一样的,我们假设三台服务器分别为:
A:10.37.129.5(rsync客户端)
B:10.37.129.6(rsync服务器端)
C:10.37.129.7(rsync服务器端)

以下为服务器端配置,需要在B服务器和C服务器分别做一遍。

rsync是git的依赖,如果你用yum安装过git,那rsync肯定安装了,如果没安装你就先安装rsync:

sudo yum -y install rsync

如果已经安装过了,那你也可以更新一下:

sudo yum update rsync

用vim打开配置文件:

sudo vim /etc/rsyncd.conf

配置文件中已经有一个注释的example,可以把它删掉,把下面内容加到配置文件中:

#指定运行的用户名或ID号(rsync客户端推送过来的文件所有者会被创建为uid指定的所有者)
uid = www
#指定运行的组名或组ID号(rsync客户端推送过来的文件所属组会被创建为gid指定的所属组)
gid = www
#切换目录
use chroot = no
#最大连接数
max connections = 10
#pid文件路径
pid file = /var/run/rsyncd.pid
#锁文件路径
lock file = /var/run/rsyncd.lock
#日志文件路径(可通过log format参数设置日志格式)
log file = /var/run/rsyncd.log
#传输日志
transfer logging = yes
#超时时间
timeout = 900
#忽略无法读取的文件
ignore nonreadable = yes
#忽略部分io错误
ignore errors
#是否只读(false就接受上传,即puhs,否则只接受下载,即pull)
read only = false
#下载(pull)操作时,如果没写下载哪个模块,则会列出模块
list = false
#允许的客户端ip或ip段(24也可写成255.255.255.0,这是网段,或子网掩码)
host allow = 10.37.129.5/24
#除了允许的ip或ip段外禁止其他ip或ip段
host deny = 0.0.0.0/32 #也可以直接写*号
#认证用户(客户端执行同步操作时,需要用user@ip来指定用户名,就跟ssh登录一个道理,这里写users是因为可配置多个用户,用逗号隔开即可)
auth users = xiebruce
#认证密码文件(后面会创建该文件,其实内容就是“用户名:密码”,一行一个用户)
secrets file = /etc/rsyncd.secrets
#如果用-az指定了打包压缩同步的文件,则指定这些后缀可以不压缩这些文件。
# dont compress   = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2

############# 自定义的传输模块2 ##################
[wwwroot]
    #同步路径
    path = /data/wwwroot
    #注释
    comment = website
    #不接受的目录(该目录位于path指定的目录下)
    exclude = cache
############# 自定义的传输模块2 ##################
[wwwroot2]
    path = /data/wwwroot2
    comment = website
    exclude = cache

以上配置文件为我用到的配置,可能并没有把rsync的所有配置项都写在上面,如果你需要什么特殊设置,可以man rsync查看还有什么选项可用。

个别参数解释:
use chroot = no如果为yes, rsync会首先进行chroot设置,将根映射在path参数路径下,对客户端而言,系统的根就是path参数指定的路径。但这样做需要root权限,并且在同步符号连接资料时只会同步名称,不会同步内容,所以我们一般设置为no。

大部分参数都可写在模块里面,这样可以分别控制各模块的认证,允许ip等等,可查看:rsync文件同步详解

A服务器创建服务器端用户密码文件:

sudo echo "xiebruce:123456" > /etc/rsyncd.secrets

在B、C服务器创建对应的客户端密码文件:

sudo echo "123456" > /etc/rsyncd.password

注意,服务器端的用户密码文件是“用户名:密码”,而客户端只需要密码,至于.secrets结束还是.password结束都无所谓,你不写后缀,或者你以abc结束都没问题,只要引用的时候用相同的名字引用就行,只是我们写成.secrets.password方便自己知道这是个什么文件。

把A的服务器端的密码文件权限设置为600

sudo chmod 600 /etc/rsyncd.secrets

把B、C服务器的客户端的密码文件权限设置为600

sudo chmod 600 /etc/rsyncd.password

注意一定要两边都设置,否则同步的时候无法使用(会提示密码文件不能具有其他权限)。

在B、C服务器上分别启动rsync的服务器端服务:

rsync --daemon

三台服务器都要允许873端口,如果是虚拟机做实验,可直接关闭防火墙:
centos7默认防火墙:

systemctl stop firewalld

关闭iptable防火墙:

chkconfig iptables off && service iptables stop

rsync客户端

rsync客户端执行以下命令即可A中变化的文件同步到B服务器(C服务器同理,把ip改一下即可):

 rsync -avz --partial --delete /data/wwwroot xiebruce@10.37.129.6::wwwroot/ --password-file=/etc/rsyncd.password
  • 该命令意思是把/data/wwwroot目录的数据,同步到10.37.129.6服务器的wwwroot模块下(至于该模块是对应哪个目录,rsyncd.config里有指定)。
  • xiebruce是认证用户名(对应服务器的auth users指定的用户名的其中一个用户名即可)
    --partial是指不要删除那些“由于各种原因只传了一部分(即没传完)的文件”,以便后面重新开始传输时,继续传输剩下未传的部分,其实也就是我们所说的“断点续传”,所以--partial选项必须要加上,如果有单个文件上百M,你也不希望传了80多M后断了,然后重新传吧?
  • --delete表示删除只存在于rsync服务器端(这里指B服务器)的文件(也就是客户端没有而服务端有的文件,不想删除就不要指定该选项)。
  • --password-file指定密码文件,否则需要手动输入。
  • -avz这是多个选项
    -a指archive,意为归档,打包(注意打包是打包,并不是压缩,打包只是把多个文件打包成一个文件)。
    -v指verbose,在各种linux命令中都是很常见选项,指输出详情。
    -z指compress,即压缩后再传输(这才是压缩,前面的-a是打包)

rsync配置好了,手动同步也正常了,但是我们总不可能每次更新了文件,都登录到服务器执行一下这条命令吧?这太麻烦了,于是有人想,创建一个crontab定时任务,每隔5分钟或10分钟同步一次不就行了?是的,这样确实可以,但这样做的缺点有两个:
1. 无法实时同步,必须等10分钟,对于紧急修复bug的更新也无法及时同步。
2. 每次同步rsync都需要扫描整个目录有哪些文件变化了(因为变化的文件才会同步),如果文件数量多达上百万文件的话(对于一些框架,这个文件数量并不奇怪,比如node_modules目录),但有时候文件可能只有一个文件变化了而已,所以这样无意义的扫描只是在做无用功,增加服务器的负担。

还好,sersync可以帮我们解决rsync扫描文件过多的问题。

sersync的使用

sersync简介

sersync是国人写的一个软件,可以记录下被监听目录中发生变化的(包括增加、删除、修改)具体某一个文件或某一个目录的名字。
github:https://github.com/wsgzao/sersync
官方博客,因为是个人写的,所以也就是一个个人博客,并没什么详细的说明:https://wsgzao.github.io/post/sersync/

Inotify是一个Linux内核特性,它监控文件系统,并且及时向专门的应用程序发出相关的事件警告,比如删除、读、写和卸载操作等。您还可以跟踪活动的源头和目标等细节,sersync正是通过Inotify这个Linux系统特性来工作的。

sersync与rsync配合,可以减少rsync扫描文件的数量(因为rsync只同步变化的文件,而要知道哪些文件发生了变化,需要每个文件都扫描一遍才知道),而sersync可以在文件变化的时候就检测出来哪个文件或者说哪几个文件发生了变化,而不需要把所有文件都扫描一遍,所以sersync的存在,就是用检测哪个文件变化了,然后自动拼接一个rsync命令并执行一次同步(当然它还有附加功能)。

sersync之前,有一个叫Inotify-tools的工具,也是基于系统的inotify的,但是Inotify-tools只能监控指定的目录是否发生变化,进而自动执行事先编写好的rsync同步命令,至于要同步哪些文件,Inotify-tools没有告诉rsync,rsync只能自己去扫描,所以这跟定时同步其实没有太大区别,只是比定时同步更加实时而已,但还是无法解决rsync扫描文件做无用功的问题,因为我前面也说了,有可能只是一个文件发生了变化而已,有可能只是加了个英文句点而已,如果说加一个句点导致rsync去扫描100万个文件就是为了找出哪个文件增加了一个句点,那这也太浪费资源了,做的都是无用功。

使用sersync

根据前面所说,我们需要在在A服务器上安装sersync,当文件变化时,sersync变会自动拼接一个rsync命令并执行,从而完成文件同步。sersync减少rsync扫描的原理,是用rsync的--include参数直接告诉rysnc要同步哪些文件,从而rsync只会扫描这些指定的文件,而不会扫描整个同步目录。

下载sersync:sersync2.5.4_64bit_binary_stable_final.tar.gz

sersync无需编译,解压出来是一个GNU-Linux-x86的目录(另担心x86,64位服务器一样可执行),里面有两个文件,一个是sersync2可执行文件,另一个是配置文件:

GNU-Linux-x86
|-- confxml.xml
`-- sersync2

虽然不用安装,但按统一规则,自己编译或安装的软件都放到/usr/local目录下,创建目录:

sudo mkdir /usr/local/sersync

然后把GNU-Linux-x86目录下的两个文件(不包括目录本身)移动到/usr/local/sersync目录中,目录结构如下:

/usr/local/sersync
├── confxml.xml
└── sersync2

创建软链接,把sersync2加入到环境变量中:

ln -s /usr/local/sersync/sersync2 /usr/local/bin/sersync2

配置文件我把所有选项都加上了解释,由于配置文件较长,需要花点时间把所有选项以及注释看一遍,你会发现其实并没有什么难的:

<?xml version="1.0" encoding="ISO-8859-1"?>
<head version="2.5">
    <!-- hostip与port是针对插件的保留字段,对于同步功能没有任何作用,保留默认即可。  -->
    <host hostip="localhost" port="8008"></host>

    <!-- 是否开启debug模式 -->
    <debug start="false"/>

    <!-- 如果是xfs文件系统,则需要设置为true才能同步,rehat/REEL/CentOS/Fedora新版本默认都是xfs文件系统,可使用df -Th命令查看 -->
    <fileSystem xfs="true"/>

    <!-- 过滤器,设置为true则会对里面的exclude对应的正则匹配到的文件进行过滤,即不同步 -->
    <filter start="true">
        <!-- <exclude expression="(.*)\.svn"></exclude> -->
        <!-- <exclude expression="(.*)\.gz"></exclude> -->
        <!-- <exclude expression="^info/*"></exclude> -->
        <!-- <exclude expression="^static/*"></exclude> -->
        <exclude expression="^cache/*"></exclude>
    </filter>

    <!-- inotify是linux的内核功能,这里用于设置创建/删除/修改/移动文件时,是否视为文件改变(进而进行同步) -->
    <inotify>
        <!-- 删除一个文件是否视为文件改变(很明显我们要设置为true) -->
        <delete start="true"/>
        <!-- 创建一个文件夹是否视为文件改变(很明显我们要设置为true) -->
        <createFolder start="true"/>
        <!-- 创建一个文件是否触发文件改变事件(这里要设置false,因为创建一个文件除了有createFile事件还会有closeWrite事件,我们只要把closeWrite事件设置为true即可监控到创建一个文件) -->
        <createFile start="false"/>
        <!-- 创建文件或修改文件后再关闭会触发该事件,比如vim打开一个文件,修改后用(:wq)保存,则会触发该事件,当然创建新文件一样会触发 -->
        <closeWrite start="true"/>
        <!-- 从别的地方移到被监控目录是否视为文件改变,毫无疑问要设置为true -->
        <moveFrom start="true"/>
        <!-- 被监控目录中的某个文件被移动到其他地方算不算文件改变?毫无疑问要设置为true -->
        <moveTo start="true"/>
        <!-- 文件属性改变了,是否视为文件改变?这个我们可以认为文件没有改,所以设置false -->
        <attrib start="false"/>
        <!-- 文件内容被修改了是否视为文件改变?感觉文件改变肯定要设置为true,但其实不用,因为这个改变有可能是vim(:w)保存,还没有关闭文件,所以保存的时候没必要同步,而关闭的时候会触发closeWrite,所以修改的文件也是通过closeWrite来同步的 -->
        <modify start="false"/>
    </inotify>

    <!-- servsync的模块 -->
    <sersync>
        <!-- 指定要监控(即同步)的本地目录 -->
        <localpath watch="/data/wwwroot">
            <!-- ip指定同步到远程的哪个服务器,name填写远程服务器中rsync配置文件中的自定义模块名称(即中括号括起来的那个名称) -->
            <remote ip="10.37.129.6" name="wwwroot"/>
            <!-- 如果你要同步到多台服务器,继续填写即可,每个服务器一个remote标签 -->
            <remote ip="10.37.129.7" name="wwwroot2"/>
            <!--<remote ip="192.168.8.40" name="tongbu"/>-->
        </localpath>

        <!-- rsync模块配置 -->
        <rsync>
            <!-- 公共参数,即我们手动执行rsync的时候要带的选项就填在这里,servsync会自动组装 -->
            <commonParams params="-azP"/>
            <!-- 密码文件及指定用户名(用户名就是rsync服务器端配置文件中的"auth user =" 指定的用户名) -->
            <auth start="true" users="xiebruce" passwordfile="/etc/rsyncd.password"/>
            <!-- 如果你rsync服务器不是默认端口873,那么就要在这里指定具体的端口,当然是默认的你也可以指定一下 -->
            <userDefinedPort start="false" port="873"/>
            <!-- rsync超时时间 -->
            <timeout start="false" time="100"/><!-- timeout=100 -->
            <!-- 是否使用ssh方式传输 -->
            <ssh start="false"/>
        </rsync>
        <!-- 对于失败的传输,会进行重新传送,再次失败就会写入rsync_fail_log,然后每隔一段时间(timeToExecute进行设置,单位sec)执行该脚本再次重新传送,然后清空该脚本。可以通过path来设置日志路径。 -->
        <failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once-->

        <!-- 定期整体同步功能,schedule表示crontab执行间隔,单位是min -->
        <crontab start="false" schedule="600"><!--600mins-->
            <!-- 同步过滤器,要开启请把start设置为true,用于 整体同步时,排除一些文件或目录,比如缓存目录可以不需要同步 -->
            <crontabfilter start="false">
                <exclude expression="*.php"></exclude>
                <exclude expression="info/*"></exclude>
            </crontabfilter>
        </crontab>
        <!-- 同步完成后,执行一个插件,name表示执行哪些插件,而这个插件必须在后边用plugin标签定义 -->
        <plugin start="false" name="command"/>
    </sersync>

    <!-- 定义一个command插件(command插件类型的一种,另外的类型有socket,refreshCDN,http(目前由于兼容性问题,http插件暂时不能用)) -->
    <plugin name="command">
        <!-- command插件其实就是“.sh”结尾的shell脚本文件,prefix和subffix用于拼成一条执行shell命令的命令 -->
        <param prefix="/bin/sh" suffix="" ignoreError="true"/>  <!--prefix /data/wwwroot/mmm.sh suffix-->
        <!-- 该脚本做操作时要过滤的文件正则 -->
        <filter start="false">
            <include expression="(.*)\.php"/>
            <include expression="(.*)\.sh"/>
        </filter>
    </plugin>

    <!-- 定义一个socket插件,注意插件定义了但没有调用的话,是不会被执行的 -->
    <plugin name="socket">
        <localpath watch="/data/wwwroot">
            <deshost ip="192.168.138.20" port="8009"/>
        </localpath>
    </plugin>

    <!-- 定义一个refreshCDN插件,主要用于同步数据到cdn -->
    <plugin name="refreshCDN">
        <localpath watch="/data0/htdocs/cms.xoyo.com/site/">
            <cdninfo domainname="ccms.chinacache.com" port="80" username="xxxx" passwd="xxxx"/>
            <sendurl base="http://pic.xoyo.com/cms"/>
            <regexurl regex="false" match="cms.xoyo.com/site([/a-zA-Z0-9]*).xoyo.com/images"/>
        </localpath>
    </plugin>
</head>

启动sersync服务:

sersync2 -o /usr/local/sersync/confxml.xml -d

启动后会给出一些提示:

Xnip2019-01-20_17-20-20.jpg

现在,你可以测试一下在A服务器的同步目录上添加文件,修改文件内容,看B,C服务器是否会修改?我这里是成功的。

实例解释一下配置文件里的这一句:

 <failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/>

前面配置文件里的注释也说了,由于各种原因(如网络很差或延迟非常大)可能会有传输失败的情况,那为什么记录传输失败的文件不叫.log,而叫.sh呢?

下图就是我传输失败后自动生成的/tmp/rsync_fail_log.sh文件的内容:

Xnip2019-01-20_17-29-34.jpg

前面说过,sersync只是检测有哪些文件变化了,最终它还是会组装出rsync的同步命令,上图就是它组装的同步命令执行失败后,被保存到/tmp/rsync_fail_log.sh文件中,并且每隔timeToExecute分钟执行一次(注意这个单位是min)。

如果你遇到这种失败的语句,你可以复制出来自己手动执行一下,看出来什么问题(如果选项没有-v那你就加上-v)。

另外,这一句是指定是否开启xfs格式,如果你的文件系统是xfs格式,那就要设置为true,否则设置为false:

<fileSystem xfs="true"/>

我们可以执行df -Th来查看文件系统是什么格式,通常来说linux有两种文件系统,一种是以前用的ext4,一种是新的xfs
xfs文件系统:

Xnip2019-01-20_21-13-55.jpg

ext4文件系统:

Xnip2019-01-20_21-12-18.jpg

以下是sersync的一些选项解释:
1.查看帮助:

./sersync2 -h

2.启动sersync,-d:daemon,表示以守护进程方式启动,不指定配置文件,则默认会在当前目录下查找名为confxml.xml的配置文件:

./sersync2 -d

3.在开启实时监控的之前对主服务器目录与远程目标机目录进行一次整体同步:

./sersync2 -r

如果需要将sersync运行前,已经存在的所有文件或目录全部同步到远程,要以-r参数运行sersync,将本地与远程整体同步一次。如果设置了过滤器,即在xml文件中,filter为true,则暂时不能使用-r参数进行整体同步。-r参数将会无效。

4.指定配置文件,如果不指定,则默认查找当前目录下的confxml.xml文件:

./sersync2 -o XXXX.xml

5.指定线程数,例如./sersync -n 5指定线程总数为5,如果不指定,默认启动线程池数量是10,如果cpu使用过高,可以通过这个参数调低,如果机器配置较高,也可以适当把该参数调高:

./sersync2 -n num

6.不进行同步,只运行插件(如果不知道什么是插件,请认真看配置文件的注释)

./sersync2 -m pluginName

例如./sersync -m command,则在监控到文件事件后,不对远程目标服务器进行同步,而是直接运行command插件。

7.多个参数可以配合使用

./sersync2 -n 8 -o abc.xml -r -d

表示,设置线程池工作线程为8个,指定abc.xml作为配置文件,在实时监控前作一次整体同步,以守护进程方式在后台运行。

8.通常情况下,先手动执行一遍rsync整体同步,然后再开启sersync。

其实sersync好久不更新了,现在都用lsyncd了,请看这篇文章:CentOS7部署Lsyncd+rsync实现服务器文件实时同步

本文参考:
1. https://www.cnblogs.com/regit/p/8074221.html
2. http://blog.51cto.com/liubao0312/1677586
3. http://www.codesky.net/article/201207/171024.html

打赏

Leave a Reply

avatar

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
Notify of

扫码在手机查看
iPhone请用自带相机扫
安卓用UC/QQ浏览器扫

使用sersync +rsync进行实时文件同步