使用sersync +rsync进行实时文件同步
Table of Contents
其实sersync好久不更新了,现在都用lsyncd了,请看这篇文章:CentOS7部署Lsyncd+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
的同步命令,把更新变化的文件推送到B、C、D服务器。
另外,还可以用git hooks,svn hooks,即所谓的钩子,即把A作为发布机,git/svn在上面更新文件后,可以“顺便”调用一下rsync
同步命令,这样就能做到每次发布的时候“顺便”把文件也同步到B、C和D了。
所以我们现在清楚了,“发布机”要作为rsync的客户端,其它机器都作为rsync的服务器端,这样,每当“发布机”文件有变化,都可以“推(push)”到各个服务器中。
配置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
#并发连接数(0表示无限制)
max connections = 0
#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,这是网段,或子网掩码)
hosts allow = 10.37.129.5/24
#除了允许的ip或ip段外禁止其他ip或ip段
hosts 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
############# 自定义的传输模块1 ##################
[wwwroot]
#同步路径
path = /data/wwwroot
#注释
comment = website
#不接受的目录(该目录位于path指定的目录下)
exclude = cache
############# 自定义的传输模块2 ##################
[wwwroot2]
path = /data/wwwroot2
comment = website
exclude = cache
以上配置文件为我用到的配置,可能并没有把rsync的所有配置项都写在上面,如果你需要什么特殊设置,可以man rsyncd.conf
查看还有什么选项可用(注意不是man rsync
,这样查看就是客户端的)。
个别参数解释:
use chroot = no
如果为yes, rsync会首先进行chroot设置,将根映射在path参数路径下,对客户端而言,系统的根就是path参数指定的路径。但这样做需要root权限,并且在同步符号连接资料时只会同步名称,不会同步内容,所以我们一般设置为no。
大部分参数都可写在模块里面,这样可以分别控制各模块的认证,允许ip等等,可查看:rsync文件同步详解。
A服务器创建用户登录服务器端的密码文件(里面的内容就是用于登录服务器端的密码):
sudo echo "123456" > /etc/rsyncd.password
在B、C服务器创建用户密码对:
sudo echo "xiebruce:123456" > /etc/rsyncd.secrets
注意,服务器端的用户密码文件是“用户名:密码”,而客户端只需要密码,至于.secrets
结束还是.password
结束都无所谓,你不写后缀,或者你以abc
结束都没问题,只要引用的时候用相同的名字引用就行,只是我们写成.secrets
和.password
方便自己知道这是个什么文件。
把A的服务器的密码文件权限设置为600
:
sudo chmod 600 /etc/rsyncd.password
sudo chown root:root /etc/rsyncd.password
把B、C服务器的用户密码文件权限设置为600
:
sudo chmod 600 /etc/rsyncd.secrets
sudo chown root:root /etc/rsyncd.secrets
注意一定要两边都设置,否则同步的时候无法使用(会提示密码文件不能具有其他权限)。
曾经被坑过,C机(同步目标机)的/etc/rsyncd.secrets
的所有者和所属组不是root:root
结果导致A机的lsyncd启动不了,因为无法连接B机,不要以为你在C机是用root启动rsyncd就没事,权限还是会有问题。
在B、C服务器上分别启动rsync的服务器端服务(默认使用/etc/rsyncd.conf
):
rsync --daemon
也可以使用--config=/path/to/rsyncd.conf
rsync --daemon --config=/path/to/rsyncd.conf
特别注意:只有用了--daemon
才能用--config
,因为rsync有客户端模式和服务器端模式,只有用了--daemon
才是服务器端模式,否则就是客户端模式。如果又想运行在服务器端模式,又想它在前台运行,则添加一个--no-detach
就可以。
前台运行rsyncd(适用于docker,默认配置文件在/etc/rsyncd.conf
,可以不用指定配置文件路径)
rsync --daemon --config=/path/to/rsyncd.conf --no-detach
但一般我们不会用上面那种启动方法,而是用systemctl来启动(注意rsyncd.service
文件是在/lib/systemd/system/
目录下的,Centos/Debian都是,不过Debian的service文件叫rsync.service
,即少个d,意味着systemctl操作的时候,要少写个d):
systemctl start rsyncd
设置开机自启动:
systemctl enable rsyncd
三台服务器都要允许873端口,如果是虚拟机做实验,可直接关闭防火墙:
centos7默认防火墙:
systemctl stop firewalld
关闭iptable防火墙:
chkconfig iptables off && service iptables stop
rsync客户端
rsync客户端执行以下命令即可A中变化的文件同步到B服务器(C服务器同理,把ip改一下即可):
rsync -avz --partial --delete /data/wwwroot [email protected]::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扫描文件过多的问题。
注意,rsync不一定要配置服务器,也就是说,如果你的服务器没有运行rsyncd服务,一样可以在你电脑上通过rsync命令传输文件到你的服务器。
我们知道,能传输文件,服务器必须要有一个后台服务来接收文件的,也就是说rsync能传,那就说明服务器肯定有后台服务,其实这个后台服务就是sshd,也就是说它可以通过ssh通道来传文件的,跟scp一样,具体可查看:使用rsync代替scp上传文件到服务器或从服务器下载文件(支持跨越跳板机),但是要注意,虽然服务器不用有sshd服务就可以,但也需要安装rsync(不用启动后台服务,但需要有rsync这个程序存在才行,否则一样不能传输,因为sshd还是要调用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
启动后会给出一些提示:
现在,你可以测试一下在A服务器的同步目录上添加文件,修改文件内容,看B,C服务器是否会修改?我这里是成功的。
实例解释一下配置文件里的这一句:
<failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/>
前面配置文件里的注释也说了,由于各种原因(如网络很差或延迟非常大)可能会有传输失败的情况,那为什么记录传输失败的文件不叫.log
,而叫.sh
呢?
下图就是我传输失败后自动生成的/tmp/rsync_fail_log.sh
文件的内容:
前面说过,sersync只是检测有哪些文件变化了,最终它还是会组装出rsync的同步命令,上图就是它组装的同步命令执行失败后,被保存到/tmp/rsync_fail_log.sh
文件中,并且每隔timeToExecute
分钟执行一次(注意这个单位是min)。
如果你遇到这种失败的语句,你可以复制出来自己手动执行一下,看出来什么问题(如果选项没有-v
那你就加上-v
)。
另外,这一句是指定是否开启xfs格式,如果你的文件系统是xfs格式,那就要设置为true,否则设置为false:
<fileSystem xfs="true"/>
我们可以执行df -Th
来查看文件系统是什么格式,通常来说linux有两种文件系统,一种是以前用的ext4
,一种是新的xfs
:
xfs文件系统:
ext4文件系统:
以下是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