Rsync+inotify 文件实时同步

题记:文件的同步是一个经常性的需求,如在使用了负载均衡后,后端的服务器的文件需要实时同步,虽然负载均衡设备有持久连接的功能,避免了同一个client两次访问得到的数据不同的尴尬,但是后端服务器的数据没有同步的话,不能保证同一时间,多用户访问的数据是一致的……rsync和inotify的结合只是实现文件实时同步的一种方式。

Rsync

简介

rsync是一款常用的数据镜像备份的软件,其采用了“Rsync”算法,单机上其支持跨分区传输文件,也可以跨主机传输文件。常用的模式是rsync client和 rsync server进行文件同步。方式是可以client去server上取数据,也可以client推送数据给server。特点如下

  • 可以支持增量备份也可以执行完整备份。
  • 可以保持文件的原有权限、时间等属性
  • 提供加密传输
  • 支持指定传输文件的方式(rcp/scp/socket)
  • 支持匿名传输

安装简单,现在系统本身就预带了rsync,没有预装建议直接使用yum安装,也可以自行重新编译安装。

rsync应用模式

本地shell
故名思议,就是在本地使用rsync复制、备份文件
rsync -av /var/www/html /tmp
rsync -av /var/www/html/ /tmp

  • -a表示–archive 表示将文件夹下递归传输
  • -v表示–verbose 表示输出详细模式信息

以上两条命令的区别是:第一条表示复制完整目录到/tmp下,包含目录本身,第二条表示复制目录下的内容到/tmp下而不包含目录本身

远程shell
跨主机使用rsync复制、备份文件
rsync -av /var/www/html 192.168.162.51:PATH2
若以root用户身份执行这条命令,则Rsync会要求输入192.168.162.51主机root密码。验证之后会在root的用户目录下创建PATH2,将本机的/var/www/html整个目录包含目录本身复制到PATH2.默认使用SSH传输。和scp使用类似

列表模式
rsync -a [ip]:PATH
可以看到此ip主机的PATH路径内所有文件,类似ls 长格式显示。没指定ip则表示本机

服务器模式
基于c/s架构,rsync server需要启动rsync守护进程,用于接受文件传输的请求,同时需要设定配置文件,指定本地被同步的相关设置,如同步文件的path、模块、权限、pid文件路径、秘钥文件路径等等,同时在server端设定在配置文件中指定的秘钥文件。使用较多,rsync srver常用于同步、备份中心。可以在client结合crond定时传送文件,如下。

rsync+cron定时同步

两台服务器,rsync server和rsync client,分别配置.
server 192.168.162.51
client 192.168.162.52
需求实现:client(192.168.162.52)每分钟去server(192.168.162.51)同步/var/www/html/,保证httpd网页文件一致

rsync server
rsync服务配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost ~]# cat /etc/rsyncd.conf
#Globle settings
uid = nobody
gid = nobody
use chroot = no
max connections = 10
strict modes = yes
pid file = /var/run/rsyncd.pid
log file = /var/log/rsyncd.log
lock file = /var/run/rsyncd.lock
#directory to be rsynced
[web]
path = /var/www/html
ignore errors = yes
read only = no
write only = no
hosts allow = 192.168.162.52
hosts deny = *
list = false
uid = root
gid = root
auth users = lamp
secrets file = /etc/rsync.passwd

用户和秘钥配置文件(由rsyncd.conf文件指定):

1
2
[root@localhost ~]# cat /etc/rsync.passwd
lamp:lamp

守护进程启动:
执行rsync --daemon

1
2
3
[root@localhost ~]# ps -ef | grep rsync
root 14570 1 0 00:22 ? 00:00:00 rsync --daemon
root 15299 15001 0 00:59 pts/0 00:00:00 grep rsync

或者 安装xinetd

1
2
yum -y install xinetd
service xinetd restart

文件情况:

1
2
[root@localhost html]# ls
access.c index.html wwwaccessewew.c

rsync client
文件情况:

1
2
[root@localhost html]# ls
index.html qsqsq.c

配置秘钥文件:

1
2
[root@localhost ~]# cat /etc/rsync.passwd
lamp

使用shell手动同步:

1
2
3
4
5
6
7
[root@localhost html]# rsync -vzrtopg --delete --progress --exclude "*access*" lamp@192.168.162.51::web /var/www/html/ --password-file=/etc/rsync.passwd
receiving incremental file list
deleting qsqsq.c
./
sent 70 bytes received 120 bytes 126.67 bytes/sec
total size is 14 speedup is 0.07

同步后文件情况:

1
2
[root@localhost ~]# ls /var/www/html/
index.html

  • -vzrtopg:verbose输出可见 z表示使用压缩处理 r表示对子目录进行递归 t保持文件的时间信息 o保持属主信息 p保持文件权限 g保持属组信息
  • –delete参数:可以看到client上原本的 qsqsq.c由于server上没有会被删除掉,不携带此参数则不会被删除
  • –exclude参数 server上匹配到“access”的文件都会被exclude(不被同步)。
  • –progress 显示数据同步的过程
  • lamp@192.168.162.51::web 表示用lamp用户对192.168.162.51这个主机上的web模块进行备份

编辑crond配置文件或者使用crontab -e添加配置,使用crontab -l查看:

1
2
[root@localhost ~]# crontab -l
*/1 * * * * rsync -vzrtopg --delete --progress --exclude "*access*" lamp@192.168.162.51::web /var/www/html/ --password-file=/etc/rsync.passwd

之后便可以定时自动同步了。

Inotify

简介

从文件管理器到安全工具,文件系统监控对于的许多程序来说都是必不可少的。从 Linux 2.6.13 内核开始,Linux就推出了inotify,允许监控程序打开一个独立文件描述符,并针对事件集监控一个或者多个文件,例如打开、关闭、移动/重命名、删除、创建或者改变属性。

后面用的inotify-tools就是调用了inotify的一个应用程序,由于其将其封装了一层,更便于我们使用。
特点

  • 使用一个独立的文件描述符
  • 所使用的文件描述符可以通过系统调用获得,并且没有相关设备或者文件
  • 能够监视文件或者目录
  • 使用文件描述符,允许程序员使用标准 select 或者 poll 函数来监视事件
    摘自IBM developerWorks

事件结构
在/usr/include/sys/inotify.h(red hat系列)
/usr/include/x86_64-linux-gnu/sys/inotify.h(debian系列)定义了inotify事件结构

1
2
3
4
5
6
7
8
struct inotify_event
{
int wd; /* The watch descriptor */
uint32_t mask; /* Watch mask */
uint32_t cookie; /* A cookie to tie two events together */
uint32_t len; /* The length of the filename found in the name field */
char name __flexarr; /* The name of the file, padding to the end with NULs */
}

测试
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#define EVENT_SIZE (sizeof (struct inotify_event))
#define BUF_LEN (1024*(EVENT_SIZE +16))
int main(int argc,char * argv[])
{
int length,i=0;
int fd;
int wd;
char buffer[BUF_LEN];
fd=inotify_init();
if( fd < 0 )
perror("inotify_init() error");
wd=inotify_add_watch(fd,"/home/zhxfei",
IN_MODIFY|IN_CREATE|IN_DELETE);
printf("inotify is ok\n");
length = read(fd,buffer,BUF_LEN); //程序堵塞至此等待事件发生
printf("inotify is ok\n");
if(length<0)
perror("read() error!");
while(i<length)
{
struct inotify_event *event=(struct inotify_event *)&buffer[i];
if(event->len)
{
if(event->mask & IN_CREATE)
{
if(event->mask & IN_ISDIR)
printf("directory %s is creat!\n",event->name);
else
printf("file %s is create!\n",event->name);
}
else if(event->mask & IN_DELETE)
{
if(event->mask & IN_ISDIR)
printf("directory %s is delete!\n",event->name);
else
printf("file %s is delete!\n",event->name);
}
else if(event->mask & IN_MODIFY)
{
if(event->mask & IN_ISDIR)
printf("directory %s is modify!\n",event->name);
else
printf("file %s is modify!\n",event->name);
}
}
i += EVENT_SIZE + event->len;
}
(void)inotify_rm_watch(fd,wd);
(void)close(fd);
exit(0);
}

编译:gcc inotify_test1.c -o inotify_test1.out
./inotify_test1.out运行即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
zhxfei@zhxfei-HP-ENVY-15-Notebook-PC:~/code/c/inotify$ ./inotify_test1.out
inotify is ok
**echo 2>2**
inotify is ok
file 2 is create!
inotify is ok
**echo 2>2**
inotify is ok
file 2 is modify!
inotify is ok
**rm 2 -rf**
inotify is ok
file 2 is delete!

可见程序阻塞在read()等待事件发生

rsync+inotify

简介

通过inotify-tools这个工具结合rsync即可实现实时文件同步,结构如图所示。

部署

rsync部署如上,不再赘述;
注意:rsync client安装inotify-tools
在rsync client上编辑inotify.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#/bin/bash
#
host=192.168.162.52
src=/var/www/html/
dst=web
user=lamp
/usr/local/inotify/bin/inotifywait -mrq --timefmt '%y%m%d %H:%M' --format '%T %w%f%e' -e modify,delete,close_write,attrib $src \
| while read files
do
rsync -vzrtopg --delete --progress --password-file=/etc/rsync.passwd $src $user@${host}::$dst
echo "${files} was rsynced" >> /tmp/rsync.log
done
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
[root@localhost ~]# ./inotify.sh &
[1] 22738
[root@localhost html]# ps -ef | grep inotify
root 22738 22737 0 09:25 pts/2 00:00:00 /usr/local/inotify/bin/inotifywait -mrq --timefmt %y%m%d %H:%M --format %T %w%f%e -e modify,delete,close_write,attrib /var/www/html/
[root@localhost html]# ls
access.c index.html qsqsq.c wwwaccessewew.c
[root@localhost html]# echo 1>1
[root@localhost html]# sending incremental file list
./
deleting html/wwwaccessewew.c
deleting html/qsqsq.c
deleting html/index.html
deleting html/access.c
deleting html/
1
1 100% 0.00kB/s 0:00:00 (xfer#1, to-check=4/6)
sent 160 bytes received 30 bytes 18.10 bytes/sec
total size is 31 speedup is 0.16
sending incremental file list
sent 116 bytes received 8 bytes 11.81 bytes/sec
total size is 31 speedup is 0.25

Rsync server日志:

1
2
3
4
5
6
7
8
2016/08/18 09:35:22 [14818] name lookup failed for 192.168.162.51: Temporary failure in name resolution
2016/08/18 09:35:22 [14818] connect from UNKNOWN (192.168.162.51)
2016/08/18 09:35:22 [14818] rsync to web/ from lamp@unknown (192.168.162.51)
2016/08/18 09:35:22 [14818] receiving file list
2016/08/18 09:35:22 [14818] ./
2016/08/18 09:35:22 [14818] sent 183 bytes received 206 bytes total size 31
[root@localhost html]# ls
1 access.c index.html qsqsq.c wwwaccessewew.c

坚持原创技术分享,您的支持将鼓励我继续创作!