2019-06-27-打造文件实时同步架构之sersync篇

前文讲述的rsync主要用于较大量数据同步,一般简单的服务器数据传输会使用ftp/sftp等方式,但是这样的方式效率不高,不支持差异化增量同步也不支持实时传输。针对数据实时同步需求大多数人会选择rsync+inotify-tools的解决方案,但是这样的方案也存在一些缺陷,(下文会具体指出),sersync是国人基于前两者开发的工具,不仅保留了优点同时还强化了实时监控,文件过滤,简化配置等功能,帮助用户提高运行效率,节省时间和网络资源。

inotify+rsync模式

如果要实现定时同步数据,可以在客户端将rsync加入定时任务,但是定时任务的同步时间粒度并不能达到实时同步的要求。在Linux kernel 2.6.13后提供了inotify文件系统监控机制。通过rsync+inotify组合可以实现实时同步。

inotify实现工具有几款:inotify本身、sersync、lsyncd。其中sersync是金山的周洋开发的工具,克服了inotify的缺陷,且提供了几个插件作为可选工具。此处先介绍inotify的用法以及它的缺陷,通过其缺陷引出sersync,并介绍其用法。

安装inotify-tools

inotify由inotify-tools包提供。在安装inotify-tools之前,请确保内核版本高于2.6.13,且在/proc/sys/fs/inotify目录下有以下三项,这表示系统支持inotify监控,关于这3项的意义,下文会简单解释。

1
2
3
4
5
[root@c7-test01 ~]# ls -l /proc/sys/fs/inotify/
total 0
-rw-r--r-- 1 root root 0 Jun 3 18:30 max_queued_events
-rw-r--r-- 1 root root 0 Jun 3 18:30 max_user_instances
-rw-r--r-- 1 root root 0 Jun 3 18:30 max_user_watches

epel源上提供了inotify-tools工具,可以先安装epel-release源,然后通过yum方式安装,也可以通过下载源码编译方式安装。由于我们部署了本地yum源,所以选择第一种方式。

1
2
[root@c7-test01 ~]# yum install -y epel-release
[root@c7-test01 ~]# yum install -y inotify-tools

inotify-tools工具只提供了两个命令inotifywait和inotifywatch。如下:

1
2
3
[root@c7-test01 ~]# rpm -ql inotify-tools
/usr/bin/inotifywait
/usr/bin/inotifywatch

其中,inotifywait命令用于等待文件发生变化,所以可以实现监控(watch)的功能,该命令是inotify的核心命令。inotifywatch用于收集文件系统的统计数据,例如发生了多少次inotify事件,某文件被访问了多少次等等,一般用不上。inotify相关的内核参数如下:

1)/proc/sys/fs/inotify/max_queued_events:调用inotify_init时分配到inotify instance中可排队的event数的最大值,超出的事件被丢弃,但会触发队列溢出Q_OVERFLOW事件。

2)/proc/sys/fs/inotify/max_user_instances:每一个real user可创建的inotify instances数量的上限。

3)/proc/sys/fs/inotify/max_user_watches:每个inotify实例相关联的watches的上限,即每个inotify实例可监控的最大目录、文件数量。如果监控的文件数目巨大,需要根据情况适当增加此值。

inotify的不足

inotify是监控工具,监控目录或文件的变化,然后触发一系列的操作。假如有一台站点发布服务器A,还有3台web服务器B/C/D,目的是让服务器A上存放站点的目录中有文件变化时,自动触发同步将它们推到web服务器上,这样能够让web服务器最快的获取到最新的文件。需要搞清楚的是,监控的是A上的目录,推送到的是B/C/D服务器,所以在站点发布服务器A上装好inotify工具。除此之外,一般还在web服务器BCD上将rsync配置为daemon运行模式,让其在873端口上处于监听状态(并非必须,即使是sersync也非必须如此)。也就是说,对于rsync来说,监控端是rsync的客户端,其他的是rsync的服务端。

以上描述的只是最可能的使用情况,并非一定需要如此。况且,inotify是独立的工具,它和rsync无关,它只是为rsync提供一种比较好的实时同步方式而已。

虽然inotify已经整合到了内核中,在应用层面上也常拿来辅助rsync实现实时同步功能,但是inotify因其设计太过细致从而使得它配合rsync并不完美,所以需要尽可能地改进inotify+rsync脚本或者使用sersync工具。

另外,inotify存在bug—当向监控目录下拷贝复杂层次目录(多层次目录中包含文件),或者向其中拷贝大量文件时,inotify经常会随机性地遗漏某些文件。这些遗漏掉的文件由于未被监控到,所有监控的后续操作都不会执行,例如不会被rsync同步。实际上,上面描述的问题不是inotify的缺陷,而是inotify-tools包中inotifywait工具的缺陷。

Sersync模式

sersync主要用于服务器同步,web镜像等功能。目前使用的比较多的同步解决方案是inotify-tools+rsync ,另外一个是google开源项目Openduckbill(依赖于inotify- tools),这两个都是基于脚本语言编写的。相比较上面两个项目,sersync优点是:

1)sersync是使用c++编写,而且对linux系统文件系统产生的临时文件和重复的文件操作进行过滤,所以在结合rsync同步的时候,节省了运行时耗和网络资源

2)sersync配置起来很简单,其中bin目录下已经有基本上静态编译的二进制文件,配合bin目录下的xml配置文件直接使用即可。

3)相比较其他脚本开源项目,使用多线程进行同步,尤其在同步较大文件时,能够保证多个服务器实时保持同步状态。

4)有出错处理机制,通过失败队列对出错的文件重新同步,如果仍旧失败,则按设定时长对同步失败的文件重新同步。

5)自带crontab功能,只需在xml配置文件中开启,即可按您的要求,隔一段时间整体同步一次。无需再额外配置crontab功能。

6)具备socket与http插件扩展,满足您二次开发的需要。

sersync架构图如下所示,其架构说明如下:

1 ) 线程组线程是等待线程队列的守护线程,当事件队列中有事件产生的时候,线程组守护线程就会逐个唤醒同步线程。当队列中 Inotify 事件较多的时候,同步线程就会被全部唤醒一起工作。这样设计的目的是为了能够同时处理多个 Inotify 事件,从而提升服务器的并发同步能力。同步线程的最佳数量=核数 x 2 + 2。

2 ) 之所以称之为线程组线程,是因为每个线程在工作的时候,会根据服务器上新写入文件的数量去建立子线程,子线程可以保证所有的文件与各个服务器同时同步。当要同步的文件较大的时候,这样的设计可以保证每个远程服务器都可以同时获得需要同步的文件。

3 ) 服务线程的作用有三个:

  • 处理同步失败的文件,将这些文件再次同步,对于再次同步失败的文件会生成 rsync_fail_log.sh 脚本,记录失败的事件。
  • 每隔10个小时执行 rsync_fail_log.sh 脚本一次,同时清空脚本。
  • crontab功能,可以每隔一定时间,将所有路径整体同步一次。

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

Sersync安装

安装规划如下:

  • 服务器A(主服务器):192.168.101.11
  • 服务器B(从服务器/备份服务器):192.168.101.251
  • rsync默认TCP端口为873

Step1:服务器B上安装rsync

1
[root@c7-test01 ~]# yum install -y rsync

Step2:配置/etc/rsyncd.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@c7-test01 ~]# cat /etc/rsyncd.conf 
#服务器B上的rsyncd.conf文件内容
uid=root
gid=root
##最大连接数
max connections=36000
##默认为true,修改为no,增加对目录文件软连接的备份
use chroot=no
##定义日志存放位置
log file=/var/log/rsyncd.log
##忽略无关错误
ignore errors = yes
##设置rsync服务端文件为读写权限
read only = no
##认证的用户名与系统帐户无关在认证文件做配置,如果没有这行则表明是匿名
auth users = rsync
##密码认证文件,格式(虚拟用户名:密码)
secrets file = /etc/rsync.pass
##这里是认证的模块名,在client端需要指定,可以设置多个模块和路径
[rsync]
##自定义注释
comment = rsync
##同步到B服务器的文件存放的路径
path=/app/data/site/
[img]
comment = img
path=/app/data/site/img

Step3:创建rsync认证文件,可以设置多个,每行一个用户名:密码,注意中间以“:”分割

1
[root@c7-test01 ~]# echo "rsync:rsync" > /etc/rsync.pass

Step4:设置文件所有者和读写权限

1
2
[root@c7-test01 ~]# chmod 600 /etc/rsyncd.conf 
[root@c7-test01 ~]# chmod 600 /etc/rsync.pass

Step5:启动服务器B上rsync服务,并查询监听端口

1
2
3
4
5
6
7
8
9
[root@c7-test01 ~]# systemctl enable rsyncd && systemctl start rsyncd
Created symlink from /etc/systemd/system/multi-user.target.wants/rsyncd.service to /usr/lib/systemd/system/rsyncd.service.
[root@c7-test01 ~]# netstat -an | grep 873
tcp 0 0 0.0.0.0:873 0.0.0.0:* LISTEN
tcp6 0 0 :::873 :::* LISTEN
[root@c7-test01 ~]# lsof -i tcp:873
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
rsync 1960 root 4u IPv4 25279 0t0 TCP *:rsync (LISTEN)
rsync 1960 root 5u IPv6 25280 0t0 TCP *:rsync (LISTEN)

以下安装步骤是在服务器A上执行!!!

Step6:在服务器A上安装rsync服务

1
[root@c7-server01 ~]# yum install -y rsync

Step7:安装inotify-tools工具

1
[root@c7-server01 ~]# yum install -y inotify-tools

Step8:安装sersync软件包

1
2
3
4
5
6
7
wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/sersync/sersync2.5.4_64bit_binary_stable_final.tar.gz
[root@c7-server01 local]# tar zxvf sersync2.5.4_64bit_binary_stable_final.tar.gz
GNU-Linux-x86/
GNU-Linux-x86/sersync2
GNU-Linux-x86/confxml.xml
[root@c7-server01 local]# mv GNU-Linux-x86 sersync
[root@c7-server01 local]# cd sersync/

Step9:配置密码文件并修改权限为600。这个密码用于访问服务器B,需要的密码和上面服务器B的密码必须一致:

1
2
[root@c7-server01 sersync]# echo "rsync" > /app/local/sersync/user.pass
[root@c7-server01 sersync]# chmod 600 /app/local/sersync/user.pass

Step10:配置confxml.xml文件

Step11:在服务器A上运行sersync服务

1
2
3
4
5
6
[root@c7-server01 sersync]# cd /app/local/sersync/
[root@c7-server01 sersync]# ./sersync2 -r -d
-d:启用守护进程模式
-r:在监控前,将监控目录与远程主机用rsync命令推送一遍
-n: 指定开启守护线程的数量,默认为10个
-o:指定配置文件,默认使用confxml.xml文件

效果验证

1
2
3
4
#在服务器A(192.168.101.11)的/tmp目录创建10个文件,比如:tets01..test10
[root@c7-server01 sersync]# touch /tmp/test{01..10}

# 在服务器B(192.168.101.251)的/app/data/site/目录下查看效果

最后,在服务器A上设置sersync开机启动,整体文件实时同步的架构部署完毕。

1
echo "/app/local/sersync/sersync2 -r -d -o /opt/sersync/confxml.xml >/app/local/sersync/rsync.log 2>&1 &" >> /etc/rc.local
-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!