Rsync是一款远程同步软件,在同步文件(文件和目录)的时候可以保持原文件的权限、修改时间、包括链接文件也可以同步。
这个东西应用在什么地方呢?不管你是什么业务,如果你有几十台以上的服务器,并且这些服务器需要实时保持拥有的文件一致,那你就会用到这个工具。比如你有几十台web服务器,网页文件会经常修改,如何批量同步这些新的网页文件到所有服务器上呢?
Inotify又是什么呢?它是一种通知机制,随着时间的推移,你的原文件夹可能越来越大,如果每次同步都把整个目录扫描一遍那简直不敢想象,inotify就是内核提供的一种功能,可以实现对目录的监控,如果该目录有任何文件的删除、修改、新建它都会捕捉到这一动作,并可以把这一事件发送给其他应用程序。
主机名 | IP | 说明 |
Linux01.localhost |
10.10.6.12 |
推送文件 |
Linux02.localhost | 10.10.6.15 |
运行rsync守护进程,作为Server端,接收推送。 |
说明:这个模式你要了解,不是服务器端向客户端推送数据,是客户端其实就是使用rsync工具向运行rsync服务的服务器端推送数据。所以一般运行的Web服务器上都安装此服务,用于接收页面文件的更新。
安装Rsync
实现原理:
rsync采用的是C/S结构,不过S端是服务器端,运行rsync的守护进程,C端通过命令来向S端推送文件。
安装:
rpm-qarsync#检查是安装了rsync rpm-ersync#如果安装了,那么就删除,系统自带的版本比较低 wgethttps://download.samba.org/pub/rsync/rsync-3.1.2.tar.gz--no-check-certificate
tar-xzfrsync-3.1.2.tar.gz cdrsync-3.1.2 ./configure--prefix=/usr/local/rsync--disable-ipv6
如果不指定安装目录,则默认会安装到如下目录中:
make&&makeinstall
设置账户和目录:
groupadd-rrsync#创建rsync系统组 useradd-grsyncrsync-r-s/sbin/login#创建rsync系统账号并加入到rsync组
mkdirbackup#创建用于接收推送文件的目录 chownrsync.rsync./backup#设置改目录的属主和属组位rsync
编辑配置文件:编译安装后它使用的配置文件默认位置为/etc/rsyncd.conf,但是默认这个文件并不存在,需要你手动建立。
touch/etc/rsyncd.conf#守护进程使用的配置文件,必须是rsyncd.conf touch/etc/rsyncd.passwd#用户名和密码文件,这个名字可以随便 chmod600/etc/rsyncd.passwd#修改密码文件权限
vim/etc/rsyncd.conf#编辑配置文件
#[全局配置] #服务器IP和监听端口号 address=10.10.6.15 port=873 #服务器传输文件时服务器用哪个属主和属组去保存接收到的文件,也就是权限替换,如果在这里设 #置成root,则会保留权限。 uid=rsync gid=rsync #在文件传输之前,服务器守护进程将chroot到指定的PATH,优点是实时特殊的保护,缺点是需要roo#t权限 usechroot=no #最大并发数 maxconnection=10 #超时时长 timeout=300 #锁、日志和pid文件位置 lockfile=/var/run/rsync.lock logfile=/var/run/rsync.log pidfile=/var/run/rsync.pid #消息文件,当客户端连接到服务器是该文件的内容将会显示给客户端,这个文件不是必须的 motdfile=/etc/rsyncd.mod #存放虚拟用户和密码的文件 secretsfile=/etc/rsyncd.passwd #允许的网段 hostsallow=* #不允许的网段 #hostsdeny=0.0.0.0/32 #是否允许客户上传文件,true不允许,false允许。 readonly=false #[模块配置],所谓模块配置其实就是要使用的目录,客户端推送文件到服务器端的哪个目录 [backup] #需要接收同步的目录 path=/usr/local/backup #是否忽略错误 ignoreerrors list=false #虚拟的用户,也就是客户端用那个用户来连接服务器,可以用空格或者逗号分隔多个用户,该用户 #必须在上面secretsfile=/etc/rsyncd.passwd文件中 authusers=rsync_backup #该模块的描述,客户端连接后会显示给客户端 commment=hello
vim/etc/rsyncd.passwd#编辑密码文件
./rsync--daemon#启动服务
说明:rsync可以以守护进程的方式运行,也可以由xinetd来激活,如果你的服务器负载比较高建议rsync以独立的守护进程方式来运行。区别在于,如果以独立的守护进程方式运行,它会一直监听端口随时准备接受文件推送,如果由xinetd这个超级进程来管理的话,那没有推送的时候rsync是休眠状态,当有推送的时候,由xinetd这个超级进程激活rsync,对于繁忙的服务器来说这种方式会有额外开销。
连接测试:
在数据源服务器,这里的环境是Linux01,安装rsync。步骤同上。
touch/etc/rsyncd.passwd#建立密码文件 echo"123456">/etc/rsyncd.passwd#这个文件仅存储密码,服务器端和用户名对应的密码 chmod600/etc/rsyncd.passwd#修改权限
参数 | 说明 |
-v | 显示执行过程中的详细信息 |
-a | 归档模式,以递归方式传送文件,并保持文件所有属性,相当于rlptgoD |
-r | 对子目录以递归模式处理 |
-R | 使用相对路径 |
-b |
创建备份,如果目标有相同文件名是,在覆盖前,先对老文件进行重命名操作。 --backup-dir将文件备份到指定目录,如果不指定目录则在被同步的目录下建立同名备份,不过名字上会多一个~。 |
-l |
保留软连接 |
-H |
保留硬链接 |
-p |
保持文件权限 |
-o |
保持文件属主信息 |
-g |
保持文件属组信息 |
-t | 保留文件时间 |
-D | 保持设备文件信息 |
--include-from= | 从文件中读取需要传输的文件或者目录列表,文件内容为一行一个,如果包含的文件或者目录名称是中文,要把该文件用UTF-8格式保存 |
--include= | 指定哪些文件或者目录需要传输 |
--exclude-from= | 从文件中读取要排除的文件或者目录,文件内容为一行一个,如果排除的文件或者目录名称是中文,要把该文件用UTF-8格式保存 |
--eclude= | 指定排除哪些文件或者目录 |
--progress |
显示传输过程 |
--password-file= |
指定密码文件路径 |
--port= | 如果rsyncServer使用非标准端口,那么你在用客户端连接的时候就要指定端口 |
发送文件
查看接收到的文件
有没有注意到权限问题?发送文件的时候hello的属主和属组是chen,但是发送过去以后就变成rsync了。因为我们知道-a参数的含义是保留权限、属主和属组,那为什么传递过去之后就变了呢?
原因就在于配置文件里面的uid和gid设置,看下图:
@L_404_13@
这样的设置结果就是文件同步到服务器端以后,rsync服务器器会根据这个设置来修改文件的属主和属组信息,如果把这里写成root那么rsync就会修改属主和属组了,而会保留信息。
我们修改成root再测试一下
你会发现权限一样、时间一样、属主和属组也一样。
注意:前提也得是你服务器端有这个同名账户才行,如果没有,这里你查看到的就仅仅是一串数字,也就是权限信息。
下面我更新一下Liux01主机上的hello文件
下图是在Linux02上也就是rsync服务器端看到的hello文件内容
在Linux01上执行命令
rsync-avz-b--backup-dir=/aaahello--progressrsync_backup@10.10.6.15::backup--password-file=/etc/rsyncd.passwd
如果要同步目录的话,就把上面的hello文件换成目录
可以看到服务器端的hello文件已经更新了,并且在该目录下还建立了一个目录,里面放了是没有更新之前的hello文件。
因为我们加了一个-d的参数,这个参数就是对同名文件更新前先备份,备份到--backup-dir=指定目录,如果没有就新建一个。
现在我们说一下如何关闭rsync进程,它如果作为守护进程来运行的话,你得手动KILL掉进程,然后删除PID文件才行。为了方便我们写一个脚本来执行上述操作
#/bin/bash # #该脚本的执行前提是你的rsync服务端配置文件要是/etc/rsyncd.conf,如果不是,请替换成实际位 #置 #从配置文件中获取PID文件位置 PIDFILE=`cat/etc/rsyncd.conf|grep'pidfile'|awk-F'''{print$4}'` #echo$PIDFILE #判断该文件是否存在 if[-e$PIDFILE];then cat$PIDFILE|xargskill-9 rm-rf$PIDFILE echo"rsync服务已经关闭。" else echo"当前系统没有运行rsync服务。" fi
我们知道通过这个rsync是为了实现批量同步,但是我们发现同步命令一次指定同步一台主机,如何做到批量同步多台主机呢?rsync本身没有这个功能,需要自己写脚本实现:
其次写一个执行批量同步的脚本,并且能区分是删除还是其他更新操作
#/bin/bash # #该参数是服务器IP列表文件 SERVERLIST=$1 #源目录 SRC_DIR=data #目标目录 DES_DIR=backup #目标服务器上的用于备份的目录,该目录用于备份更新时出现同名文件的时候 BACKUP_DIR=/backup/aaa #连接服务器使用的用户名 USER=rsync_backup #判断文件是否存在 if[-e$1];then #读取逐行读取文件 forlinein$(cat$SERVERLIST);do echo$line if[$2='DELETE'];then result=`rsync-avz-b--backup-dir=$BACKUP_DIR$SRC_DIR--delete$USER@$line::$DES_DIR--password-file=/etc/rsyncd.passwd>>/dev/null` else result=`rsync-avz-b--backup-dir=$BACKUP_DIR$SRC_DIR$USER@$line::$DES_DIR--password-file=/etc/rsyncd.passwd>>/dev/null` fi if$result;then echo"推送文件到服务器:$line成功。" else echo"推送文件到服务器:$line失败。" fi done else echo"服务器IP列表文件不存在。" fi
对rsync各种参数的测试,我看到的也是别人转的,所以把链接贴在这里rsync深入分析
上面都是基于手动运行脚本或命令来进行同步的,那能否自动化执行呢?简单的办法是就是把命令或脚本加入到计划任务重crontab,或者使用inotify,我们推荐使用inotity,因为它不是单一定期的执行推送,关键它可以变化。
安装Inotify:
Inotify它是Linux内核的一个特性,在内核2.6.13开始引入该机制,用于监控文件系统的操作,比如读取、写入和创建等等,当它获取到这些操作以后以后通知应用程序。
首先看看当前系统是否支持
下载工具inotify-tools,这个为是Linux下inotify文件监控工具提供的C开发库函数,同时也包含一系列的命令行工具,使用这些工具可以来做监控文件系统的事件。它提供两种工具:
wget--no-check-certificate 如果遇到SSL无法连接之类的,请升级wget
tar-zxfinotify-tools-3.14.tar.gz cdinotifi-tools-3.14 /configure--prefix=/usr/local/inotify make&&makeinstall
inotifywait命令参数:
参数 | 说明 |
--fromfile | 从文件读取需要监视或者排除的文件或目录,一个文件一行,排除的文件以@开头 |
-m | 针对事件持续监听,如果不加该参数那么获取一次事件后就退出了。 |
-d | 运行在后台 |
-r | 递归监控目录 |
-o | 输出事件到文件中,而不是输出到STDOUT |
-s | 输出错误到系统日志中,而不是输出到STEDRR |
-q | 除了输出事件之外,不显示其他信息 |
超时时间 | |
--format | 设置事件输出格式 %w 表示发生事件的目录 %f 表示发生事件的文件 %e 所发生的事件 %Xe 事件以X分隔 %T 使用由-timefmt定义的时间格式 |
--timefmt | 指定时间输出格式,用于-fromat选项中的%T格式 %y-%m-%d %H:%M |
-excludei | 排除文件或目录,不区分大小写 |
-e -event |
如果使用该参数,你就需要手动指定要监控的事件,多个事件用逗号分隔 |
inotifywatch命令参数:
说明 | ||
-fromfile | -z | 输出表格的行和列 |
同上 | ||
-e | 设置指定的监听事件,具体事件同上 | |
-r | 递归监视 | |
-a |
以指定事件的升序排列 | |
-d |
以指定事件的降序排列 |
要实现监控,并且捕捉文件变化,然后根据变化来进行同步,这里主要是思路问题:
我们这里先测试一下inotifywait的效果,为了让inotifywait可以直接执行请修改环境变量。
监控脚本
#/bin/bash # inotifywait-mrq-emodify,create,move,delete--fromfile'/tmp/filelist'--timefmt'%y-%m-%d%H:%M'--format'%T%w%f%e'--outfile'/tmp/i.log'
要监控的目录列表文件
测试,这个脚本目前是在前台运行,所以是这种状况,你也可以设置为后台运行,只要在脚本后面加一个 &
可以看到我们建立了一个文件,然后查脚本中事件信息输出的日志,你会发现有一个事件发生了。
下面我们结合rsync来完整的写一个监控脚本。
网上有一篇文章写的不错,我这里把链接放过来,我是在他的脚本基础上做了一点修改,我也测试过不按照他那么写是否可行结果失败了,这个就跟rsync的同步机制有关。
原文出处真正的inotify+rsync实时同步 彻底告别同步慢
#/bin/bash #运行此脚本的时候服务器列表文件要输入绝对路径,否则后面切换路径后会找到该文件。 #该参数是服务器IP列表文件 SERVER_LIST=$1 #源目录 SRC_DIR=/tmp/data #目标目录 DES_DIR=backup #目标服务器上的用于备份的目录,该目录用于备份更新时出现同名文件的时候 BACKUP_DIR=/backup/aaa #连接服务器使用的用户名 USER=rsync_backup #密码文件 PASSWD_FILE=/etc/rsyncd.passwd if[!-n"$SERVER_LIST"];then echo"请传递服务器IP列表文件,要用绝对路径。" exit5 else if[-d$SRC_DIR]&&[-e$PASSWD_FILE];then echo"必要文件检查通过......" else echo"检查源路径或者密码文件失败,脚本无法执行,请检查。" exit5 fi fi #切换到源目录 cd$SRC_DIR inotifywait-mrq--timefmt'%y-%m-%d%H:%M'--format'%T%w%f%e'-emodify,delete,attrib,close_write,move./|whilereadfile do INFO_EVENT=$(echo$file|awk'{print$5}') INFO_PATH=$(echo$file|awk'{print$5}') echo"-------------------------------$(date)------------------------------------" echo$file forlinein$(cat$SERVER_LIST);do #文件建立、修改、移出事件 if[[$INFO_EVENT=~'CREATE']]||[[$INFO_EVENT=~'MODIFY']]||[[$INFO_EVENT=~'CLOSE_WRITE']]||[[$INFO_EVENT=~'MOVED_TO']];then rsync-avzcR--password-file=$PASSWD_FILE$(dirname${INFO_PATH})$USER@$line::$DES_DIR fi #删除、移动出事件 if[[$INFO_EVENT=~'DELETE']]||[[$INFO_EVENT=~'MOVED_FROM']];then rsync-avzR--delete--password-file=$PASSWD_FILE$(dirname${INFO_PATH})$USER@$line::$DES_DIR fi #修改属性事件 if[[$INFO_EVENT=~'ATTRIB']];then if[!-d"$INFO_FILE"];then rsync-avzcR--password-file=$PASSWD_FILE$(dirname${INFO_PATH})$USER@$line::$DES_DIR fi fi done done
服务器列表文件
[[VARIABLES=~VALUE]]
用=~这种操作符支持SHELL的正则表达式,在字符串比较的时候右边可以是一个模式而不一定是字符串。也就是变量内容中包括VALUE的内容,那么就匹配模式。不过在这种形式下必须使用双中括号。
在Inotify事件中有CREATE事件和CREATE.ISDIR事件,如果你使用=~那么就都会匹配。另外在IF多条件判断的时候,建议都使用独立的双中括号,这样可以避免逻辑错误。
include和exclude的精确匹配:
我在工作中遇到一个问题,服务器(Windows服务器)上有几十个文件夹,需要把其中几个同步到文件服务器上,同时这些文件夹中有log目录,里面存放日志,我们不需要备份日志,只需要把指定文件夹中的除log目录的其他文件备份。
目录结构如下(我只是模拟了目录结构,并不是实际公司环境目录):
要求是把Folder_A、B、E进行备份,同时它们里面的log_folder不备份。
rsync--port=28950-avz--progressadmin@192.168.100.10::Services/backup/Service--password-file=/etc/rsyncd.passwd--include-file=./includeFile--exclude-file=./excludeFile
意思是使用28950端口连接服务器,使用递归并保留权限,同时显示过程,备份100.10服务器中rsyncServer配置文件中[Services]段PATH指定的目录到本地/backup/Services目录中,使用密码文件为rsyncd.passwd,使用了包含文件为includeFile,排除文件为excludeFile
includeFile
Folder_A Folder_B Folder_E
excludeFile
log Folder_C Folder_D
说明:你想排除哪些文件或者目录就只用--exclude-from就行,但是如果说只想包含哪些文件的话你单独使用--include-from是不行的,必须用--exclude-from进行排除。
如果rsyncServer服务器是Windows的话,就要这样写路径
rsync--port28950-avz--progressadmin@192.168.100.20::test/cygdrive/d/rsyncscripts/test/backup--password-file=rsyncPwd.txt--include-from=includeFile.txt--exclude-from=excludeFile.txt
/cygdirve/d/rsyncscripts/test/backup 等于 d:/rsyncscripts/test/back
特别注意:
另外如果服务器上有中文目录的话,首先保存文件列表的文件要是UTF-8格式,同时文件的写法也要注意:文件第一行不要写真实目录名或者文件名,你随便写一些字母即可,从第二行开始写真实的文件名称或者目录名。
xxxxxxxxxxxxxx 文件1 文件2 目录1 目录2 File1 Folder1
我不知道为什么,反正我的环境中rsyncServer安装在一台Windows上,然后另外台Windows安装rsync客户端,从客户端上同步,因为包含一些中文名的目录,所以出了很多问题如果你的include文件和exclude文件第一个不加任意字符,那么同步过来的文件或者目录就会少。如果你的目录都是英文的则不需要这样操作。目录中的子目录或者文件如果有中文也无需在第一行添加任意字符。