首页 > 技术文章 > 三十、sersync高级同步工具实时数据同步架构

dangjingwei 2019-06-18 23:15 原文

一、项目介绍

     Sersync项目利用inotity与rsync技术实现对服务器数据实时同步的解决方案,其中inotity用于监控sersync所在服务器上的文件变化。

      Sersync项目的优点:

   1. 相比较单纯的inotity工具,sersync是使用C++编写的,对linux系统文件产生的临时文件和重复的文件操作有过滤功能,在结合rsync的时候,会减少运行时消耗的本地及网络资源,速度快。

   2.配置简单

   3.使用多线程进行同步(即可以并发同步多个不同的文件),尤其在同步较大的文件时,能够保证多个服务器实时保持同步状态。

   4.sersync自带出错处理机制,通过失败 队列对出错的文件重新同步,还出错,每10个小时再来一遍。

   5.sersync自带crontab功能,只需在xml配置中开启,就可以同步。

   6.sersync自动socket与http的协议扩展,可满足二次开发需求。

二、基本框架

三、 设计简析

1.线程组线程是等待线程对立的守护线程,当事件队列中有数据产生的时候,线程组守护线程就会逐个唤醒同步线程,当队列中inotify事件较多的时候,同步线程就会被全部唤醒一起工作。这样设计的目的是能够同时处理多个inotify事件,从而提升服务器的并发同步能力。之所以称之为线程组线程,是因为每个线程在工作的时候,会根据服务器上新写入文件的数量建立子线程,子线程可以保证所有的文件与各个服务器同时同步,当要同步的文件较大的时候,这样的设计可以保证各个远程服务器可以同事获得要同步的文件。

2.服务器线程的作用有三个(保证主服务器和从服务器数据一致且实时):

2.1 处理同步失败的文件,将这些文件再次同步,对于再次同步失败的文件会生成rsync_fail_log.sh脚本,记录失败的事件

2.2 同时每个10小时执行脚本一次,同时清空脚本。

2.3 还有就是crontab功能,可以每隔一定事件,将所有路径整体同步一次。

3.过滤队列的建立是为了过滤短时间内产生的重复的inotify信息,例如在删除文件夹的时候,inotify就会同事产生删除文件夹里的文件与删除文件夹的事件,通过过滤队列,当删除文件夹时间产生的时候,会将之前加入队列的删除文件的事件全部过滤掉,这样只产生一条删除文件夹事件,从而减轻了同步的负担。同时对于修改文件的操作的时候,会产生临时文件的重复操作。

四、sersync安装配置

4.1 sersync同步需求逻辑图

当前版本的sersync依赖于rsync进行数据同步,如下图所示,在同步主服务器(Master)上开启sersync,sersync负责监控配置路径中的文件系统事件变化,然后调用rsync命令把更新的文件同步到目标服务器(Slave),因此,需要在主服务器配置sersync,在同步目标服务器配置rsync server(注意:是rsync服务器)

如图所示,用户会实时网左边的同步主服务器(M)上写入或更新文件数据,此时需要在左边的同步服务器(M)上配置sersync服务,在右边的同步目标服务器S1和S2服务器上配置rsync守护进程,这样在主服务器M上产生的写入或更新的文件就会被sersync服务实时的同步到多个目标服务器(S1,S2等)。一般的Linux服务器一般安装了rsync软件,因此在主服务器(M)上有rsync命令即可,在目标服务器(S1、S2)上只需要进行简单的配置,并开启rsync守候进程即可。

4.2安装环境准备

角色服务器配置 IP机器名
sersync服务(M) VM   192.168.0.103 djw
rsync服务(S1) VM   192.168.0.100 djw1
rsync服务(S2) VM   192.168.0.104 djw2

 

4.3 配置同步服务器

部署总结:
步骤一、 配置slave上的rsync服务
步骤二、 配置master上sersync客户端

4.3.1 slave上部署rsync服务

          本次测试使用的服务器为djw1和djw2 server,即IP为192.168.0.100,192.168.0.104

    vim /etc/rsyncd.conf 写入如下测试内容:

# Minimal configuration file for rsync daemon

# See rsync(1) and rsyncd.conf(5) man pages for help

# This line is required by the /etc/init.d/rsyncd script
# GLOBAL OPTIONS
uid = root                         
gid = root                                  
use chroot = no
read only = false
#limit access to private LANs
hosts allow=192.168.0.0/24
hosts deny=*
ignore errors
max connections = 2000
pid file = /var/run/rsyncd.pid
auth users = rsync_backup
secrets file = /etc/rsyncd.password
#lock file = /var/run/rsync.lock
motd file = /etc/rsyncd/rsyncd.motd
#This will give you a separate log file
log file = /var/log/rsync.log
#This will log every file transferred - up to 85,000+ per user, per sync
transfer logging = yes
log format = %t %a %m %f %b
syslog facility = local3
timeout = 300
# MODULE OPTIONS
[bbs]
comment = bbs by www 2015年10月27日15:53:24 
path = /var/www/html/bbs                       
[blog]
comment = blog by www 2015年10月27日15:53:24 
path = /var/www/html/blog
上面的rsync服务的配置文件表明允许sersync主服务器(IP为192.168.0.103)访问,rsync同步模块名为[bbs],[blog]将同步过来的文件分别放入
对应的path指定的目录 /var/www/html/bbs,/var/www/html/blog下,如果有多台目标服务器,则每台都需要进行类似的rsync服务配置,上面的
uid,gid要换成本服务器对应的同步用户。注意rsync服务账户(上述用了root用户)要有对被同步目录(/var/www/html)的写入更新权限。

创建待同步的目录
[root@li-centos6.5 /var/www]
# mkdir -p /var/www/html/bbs /var/www/html/blog

[root@li-centos6.5 /var/www]
# tree /var/www/html
/var/www/html
├── bbs
└── blog
# 此步骤在djw1,djw2 上都要执行,否则,rsync服务会因为没有path路径而无法启动。

置相关权限认证

echo "rsync_backup:123456">/etc/rsyncd.password
chmod 600 /etc/rsyncd.password
# order for check
cat /etc/rsyncd.password
ll /etc/rsyncd.password
配置好后,使用下面的命令开启rsync守护进程
rsync --daemon
ps -ef|grep rsync
netstat -tunpl|grep :873
置开机自启动
echo "/usr/bin/rsync --daemon">>/etc/rc.local
grep demoan /etc/rc.local
4.3.2  master上配置rsync客户端(Master操作)
4.3.2.1master上配置rsync权限
在master(192.168.0.100)上配置rsync客户端相关权限

echo '123456' > /etc/rsync.password
chmod 600 /etc/rsync.password 
cat /etc/rsync.password 
ll /etc/rsync.password

4.3.2.2
master上手工测试rsync同步情况(此步骤非常关键且重要,如果这里测试都不成功,后面的sersync配好也不会同步数据
1. 分别创建待同步数据
touch /var/www/html/bbs/bbs.log /var/www/html/blog/blog.log
tree /var/www/html/

   2. 执行同步命令(操作之前停用防火墙)


rsync -avz /var/www/html/bbs/ rsync_backup@192.168.0.101::bbs/ --password-file=/etc/rsync.password
rsync -avz /var/www/html/bbs/ rsync_backup@192.168.0.104::bbs/ --password-file=/etc/rsync.password

rsync -avz /var/www/html/blog/ rsync_backup@192.168.0.101::blog/ --password-file=/etc/rsync.password
rsync -avz /var/www/html/blog/ rsync_backup@192.168.0.104::blog/ --password-file=/etc/rsync.password

同步完后,可以到两台slave服务器上查看结果,如下:

[root@li-centos6.5 /var/www/html]

# tree /var/www/html  # 检查目录和文件同步情况
├── bbs
│   └── bbg.log
└── blog
    └── blog.log
[root@li-centos6.7 /var/www/html]
# tree /var/www/html.  # 检查目录和文件同步情况
├── bbs
│   └── bbg.log
└── blog
    └── blog.log
4.3.3 master上配置rsync客户端
4.3.3.1 下载sersync

下载sersync的可执行文件版本,里面有配置文件和可执行文件,如下:
cd /usr/local/src && http://down.whsir.com/downloads/sersync2.5.4_64bit_binary_stable_final.tar.gz

4.3.3.2 安装sersync

tar xf sersync2.5.4_64bit_binary_stable_final.tar.gz

mv GNU-Linux-x86 /usr/local/sersync
tree /usr/local/sersync/ 
/usr/local/sersync/
├── confxml.xml
└── sersync2

4.3.3.3 规范sersync目录结构(非必须)

cd /usr/local/sersync/ && mkdir conf bin logs
mv confxml.xml ./conf/. && mv sersync2 ./bin/sersync
tree /usr/local/sersync[root@djw sersync]# tree /usr/local/sersync
/usr/local/sersync
├── bin
│   └── sersync
├── conf
│   └── confxml.xml
└── logs
4.3.3.4 配置sersync
# /bin/cp conf/confxml.xml conf/confxml.xml.luo.$(date +%F)   # 备份配置文件
[root@djw sersync]# tree conf/
conf/
├── confxml.xml
└── confxml.xml.luo.2019-06-20
初始化的配置文件内容如下:
[root@djw conf]# cat -n confxml.xml
     1  <?xml version="1.0" encoding="ISO-8859-1"?>
     2  <head version="2.5">
     3      <host hostip="localhost" port="8008"></host>
     4      <debug start="false"/>
     5      <fileSystem xfs="false"/>
     6      <filter start="false">
     7          <exclude expression="(.*)\.svn"></exclude>
     8          <exclude expression="(.*)\.gz"></exclude>
     9          <exclude expression="^info/*"></exclude>
    10          <exclude expression="^static/*"></exclude>
    11      </filter>
    12      <inotify>
    13          <delete start="true"/>
    14          <createFolder start="true"/>
    15          <createFile start="false"/>
    16          <closeWrite start="true"/>
    17          <moveFrom start="true"/>
    18          <moveTo start="true"/>
    19          <attrib start="false"/>
    20          <modify start="false"/>
    21      </inotify>
    22
    23      <sersync>
    24          <localpath watch="/opt/tongbu">
    25              <remote ip="127.0.0.1" name="tongbu1"/>
    26              <!--<remote ip="192.168.8.39" name="tongbu"/>-->
    27              <!--<remote ip="192.168.8.40" name="tongbu"/>-->
    28          </localpath>
    29          <rsync>
    30              <commonParams params="-artuz"/>
    31              <auth start="false" users="root" passwordfile="/etc/rsync.pas"/>
    32              <userDefinedPort start="false" port="874"/><!-- port=874 -->
    33              <timeout start="false" time="100"/><!-- timeout=100 -->
    34              <ssh start="false"/>
    35          </rsync>
    36          <failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once-->
    37          <crontab start="false" schedule="600"><!--600mins-->
    38              <crontabfilter start="false">
    39                  <exclude expression="*.php"></exclude>
    40                  <exclude expression="info/*"></exclude>
    41              </crontabfilter>
    42          </crontab>
    43          <plugin start="false" name="command"/>
    44      </sersync>
    45
    46      <plugin name="command">
    47          <param prefix="/bin/sh" suffix="" ignoreError="true"/>  <!--prefix /opt/tongbu/mmm.sh suffix-->
    48          <filter start="false">
    49              <include expression="(.*)\.php"/>
    50              <include expression="(.*)\.sh"/>
    51          </filter>
    52      </plugin>
    53
    54      <plugin name="socket">
    55          <localpath watch="/opt/tongbu">
    56              <deshost ip="192.168.138.20" port="8009"/>
    57          </localpath>
    58      </plugin>
    59      <plugin name="refreshCDN">
    60          <localpath watch="/data0/htdocs/cms.xoyo.com/site/">
    61              <cdninfo domainname="ccms.chinacache.com" port="80" username="xxxx" passwd="xxxx"/>
    62              <sendurl base="http://pic.xoyo.com/cms"/>
    63              <regexurl regex="false" match="cms.xoyo.com/site([/a-zA-Z0-9]*).xoyo.com/images"/>
    64          </localpath>
    65      </plugin>
    66  </head>

1) 修改24~28行的内容


24         <localpath watch="/opt/tongbu"> # 定义本地要同步的目录
25             <remote ip="127.0.0.1" name="tongbu1"/> # 定义要同步的服务器IP和模块名(例如上述的blog、bbs)
26             <!--<remote ip="192.168.8.39" name="tongbu"/>-->
27             <!--<remote ip="192.168.8.40" name="tongbu"/>-->
28         </localpath>

修改后如下:


<localpath watch="/var/www/html/blog"> # 定义本地要同步的目录
<remote ip="192.168.0.100" name="blog"/> # 定义要同步的服务器IP和模块名(例如上述的blog、bbs)
<remote ip="192.168.0.104" name="blog"/>
</localpath>
<localpath watch="/var/www/html/bbs"> # 定义本地要同步的目录
<remote ip="192.168.0.100" name="bbs"/> # 定义要同步的服务器IP和模块名(例如上述的blog、bbs)
<remote ip="192.168.0.104" name="bbs"/>

2) 修改31~34行(认证部分)

31             <auth start="false" users="root" passwordfile="/etc/rsync.pas"/>
32                 <userDefinedPort start="false" port="874"/><!-- port=874 -->
33                 <timeout start="false" time="100"/><!-- timeout=100 -->
34             <ssh start="false"/>

修改后的内容如下:

<auth start="true" users="rsync_backup" passwordfile="/etc/rsync.password"/> <!--slave服务器的用户名-->
	    <userDefinedPort start="false" port="874"/><!-- port=874 -->
	    <timeout start="true" time="100"/><!-- timeout=100 -->
<ssh start="false"/>

3) 修改36~37行
36 <failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once-->


修改后的内容如下:


36 <failLog path="/usr/local/sersync/logs/rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once-->
当同步失败后,日志记录到/usr/local/sersync/logs/rsync_fail_log.sh文件中,并且每60分钟对失败的log进行重新同步。

4.3.3.4 开启sersync守护进程同步数据

配置sersync环境变量

echo 'export PATH=/usr/local/sersync/bin:$PATH'>>/etc/profile
tail -1 /etc/profile
source /etc/profile
which sersync

启动sersync命令:
sersync -r -d -o /usr/local/sersync/conf/confxml.xml

[root@djw conf]# sersync -r -d -o /usr/local/sersync/conf/confxml.xml
set the system param
execute:echo 50000000 > /proc/sys/fs/inotify/max_user_watches
execute:echo 327679 > /proc/sys/fs/inotify/max_queued_events
parse the command param
option: -r      rsync all the local files to the remote servers before the sersync work
option: -d      run as a daemon
option: -o      config xml name:  /usr/local/sersync/conf/confxml.xml
daemon thread num: 10
parse xml config file
host ip : localhost     host port: 8008
daemon start,sersync run behind the console
config xml parse success
please set /etc/rsyncd.conf max connections=0 Manually
sersync working thread 12  = 1(primary thread) + 1(fail retry thread) + 10(daemon sub threads)
Max threads numbers is: 32 = 12(Thread pool nums) + 20(Sub threads)
please according your cpu ,use -n param to adjust the cpu rate
------------------------------------------
rsync the directory recursivly to the remote servers once
working please wait...
execute command: cd /var/www/html/blog && rsync -artuz -R --delete ./ 192.168.0.101::blog >/dev/null 2>&1

测试结果:发现问题,多实例的情况下仅第一个模块的路径能同步,其他模块下面的路径不能同步。
 sersync -r -d -o /usr/local/sersync/conf/confxml_bbs.xml

配置多实例的同步情况(针对多个模块同步的情况)


sersync –d –o /usr/local/serysnc/conf/blog_confxml.xml
sersync –d –o /usr/local/serysnc/conf/bbs_confxml.xml
… …

不同的config文件是将模块分开放置,即:4.3.3.3步骤中的第一步中的代码分开在几个不同的文件中,这样启动的时候指定模块同步。

将上述命令,写入/etc/rc.local中,随系统自启动

/bin/cp /etc/rc.local /etc/rc.local_luo_$(date +%F)
cat >>/etc/rc.local<<EOF
# sersync data to 192.168.0.101,192.168.1.102
sersync –d –o /usr/local/serysnc/conf/confxml_bbs.xml
sersync –d –o /usr/local/serysnc/conf/confxml_blog.xml
EOF

tail -3 /etc/rc.local

至此,已经完成了Master上对Slave1,Slave2上多实例(bbs,blog多模块)的同步。

五、最后,配置文件中的 /usr/local/serysnc/conf/confxml.xml逐行了解,可以百度网络上。
这里要说明一下:
1)sersync可选功能是通过xml配置文件来实现的
2)插件的定义:在现有软件上实现某个功能的时候,通过配置调用其他软件或者工具的功能,让其他软件在这个调用的时候执行其功能,这个软件在原软件上就叫做插件,表示插入的东东,嘿嘿!
3)在xml文件中的46行开始,都是插件的功能。


 

推荐阅读