###############################################################################
#
Name : Mahavairocana
#
Author : Mahavairocana
#
QQ : 10353512
#
WeChat : shenlan-qianlan
#
Blog : http://www.cnblogs.com/Mahavairocana/
#
Description : You are welcome to reprint, or hyperlinks to indicate the
#
source of the article, as well as author
information.
###############################################################################
一、服务简介:rsync官方站点:https://www.samba.org/ftp/rsync/rsync.html:
1:实现增量备份,配合inotify 或sersync,可以实现触发式的实时同步;
2:实现本地主机和远程主机上的文件同步(包括本地推到远程,远程拉到本地两种同步方式);
3:实现本地不同路径下文件的同步,但不能实现远程路径1到远程路径2之间的同步(scp可以实现)常用于软件备份,数据同步等功能;
4:使用-vvvv可以分析rsync执行的过程;
二、概念简介
1、两种同步模式
1.1、检查模式:按照指定规则检查哪些文件需要同步,默认使用quick check算法只检查文件大小、时间是否一致作为重新传输的必要条件,可以通过添加选项制定,如--size-only 只检查文件大小不同的文件进行传输(相对来说,大多检查模式都会影响rsync的性能)
1.2、同步模式:文件确定要同步后,在同步过程发发生之前要做哪些额外工作,如是否要删除冗余文件、是否追踪连接等;
2、三种工作方式:
2.1、本地文件系统上实现同步。
2.2、本地主机使用远程shell和远程主机通信。
2.3、本地主机通过网络套接字连接远程主机上的rsync daemon。
总结:2.1、 2.2两者的本质是通过管道通信,即使是远程shell。而方式(3)则是让远程主机上运行rsync服务,使其监听在一个端口上,等待客户端的连接。
常用示例:
初级用法:
[root@Mahavairocana ~]# rsync /etc/ /tmp # 本地同步
[root@Mahavairocana ~]# rsync -r /etc 10.0.0.1:/tmp # 本地/etc目录拷贝到远程主机的/tmp下
[root@Mahavairocana ~]# rsync -r 10.0.0.1:/etc /tmp # 将远程主机的/etc目录拷贝到本地/tmp下
[root@Mahavairocana ~]# rsync /etc/ # 列出本地/etc/目录下的文件列表
[root@Mahavairocana ~]# rsync 10.0.0.1:/tmp/ # 列出远程主机上/tmp/目录下的文件列表
高级用法:
[root@Mahavairocana ~]# rsync --no-motd -r -v -f "+ */" -f "+ linux-3.0.15*" -f "- *" -m rsync://rsync.kernel.org/pub/ #找出linux-3.0.15版本的内核相关文件。
rsync daemon是"rsync --daemon"或再加上其他一些选项启动的,它会读取配置文件,默认是/etc/rsyncd.conf,并默认监听在873端口上,当外界有客户端对此端口发起连接请求,通过这个网络套接字就可以完成连接,以后与该客户端通信的所有数据都通过该网络套接字传输。
rsync daemon的通信方式和传输通道与远程shell不同。远程shell连接的两端是通过管道完成通信和数据传输的,即使连接的一端是远程主机,当连接到目标端时,将在目标端上根据远程shell进程fork出rsync进程使其成为rsync server。而rsync daemon是事先在server端上运行好的rsync后台进程(根据启动选项,也可以设置为非后台进程),它监听套接字等待client端的连接,连接建立后所有通信方式都是通过套接字完成的。rsync中的server的概念从来就不代表是rsync daemon,server在rsync中只是一种通用称呼,只要不是发起rsync请求的client端,就是server端,你可以认为rsync daemon是一种特殊的server,其实daemon更应该称之为service。
远程shell daemon的方式严格地说是"远程shell通信方式+使用rsync daemon的功能"。所以它的通信方式和远程shell是一样的,在客户端发起远程shell连接,在server端fork远程shell进程以启动rsync进程,但这个rsync进程是临时的rsync daemon,它只读取配置文件中client所请求的模块部分,且只读取模块部分中的path和身份认证相关内容,(也就是说不会将全局配置项和其它模块项加载到内存,该模块下的其他配置也不会生效),当rsync操作完成,该rsync daemon就消逝并从内存中被清理。而且,远程shell daemon启动的临时daemon不会和已经在server端运行的rsync daemon冲突,它们可以并存。由于远程shell连接的最终目标是rsync模块,所以它只能使用rsync daemon语法。
3、使用场景
3.1 不适合对数据库文件进行实时同步,因为要计算比较校验码而对cpu的消耗很高,receiver端因为要从basis file中复制数据而对io的消耗很高。数据库文件,要实时同步应该使用replication功能。
3.2 可以对大量小文件进行实时同步,由于rsync是增量同步,所以对于receiver端已经存在的和sender端相同的文件,sender端是不会发送的,这样就使得sender端和receiver端都只需要处理少量的文件,由于文件小,所以无论是sender端的cpu还是receiver端的io都不是问题。
三、运行原理
3.1、增量算法传输原理
假设执行的rsync命令是将A文件推到β主机上使得B文件和A文件保持同步,即主机α是源主机,是数据的发送端(sender),β是目标主机,是数据的接收端(receiver)。在保证B文件和A文件同步时,大致有以下6个过程:
(1).α主机告诉β主机文件A待传输。
(2).β主机收到信息后,将文件B划分为一系列大小固定的数据块(建议大小在500-1000字节之间),并以chunk号码对数据块进行编号,同时还会记录数据块的起始偏移地址以及数据块长度。显然最后一个数据块的大小可能更小。
(3).β主机对文件B的每个数据块根据其内容都计算两个校验码:32位的弱滚动校验码(rolling checksum)和128位的MD4强校验码(现在版本的rsync使用的已经是128位的MD5强校验码)。并将文件B计算出的所有rolling checksum和强校验码跟随在对应数据块chunk[N]后形成校验码集合,然后发送给主机α。
(4).当α主机接收到文件B的校验码集合后,α主机将对此校验码集合中的每个rolling checksum计算16位长度的hash值,并将每216个hash值按照hash顺序放入一个hash table中,hash表中的每一个hash条目都指向校验码集合中它所对应的rolling checksum的chunk号码,然后对校验码集合根据hash值进行排序,这样排序后的校验码集合中的顺序就能和hash表中的顺序对应起来。
(5).随后主机α将对文件A进行处理。处理的过程是从第1个字节开始取相同大小的数据块,并计算它的校验码和校验码集合中的校验码进行匹配。如果能匹配上校验码集合中的某个数据块条目,则表示该数据块和文件B中数据块相同,它不需要传输,于是主机α直接跳转到该数据块的结尾偏移地址,从此偏移处继续取数据块进行匹配。如果不能匹配校验码集合中的数据块条目,则表示该数据块是非匹配数据块,它需要传输给主机β,于是主机α将跳转到下一个字节,从此字节处继续取数据块进行匹配。注意,匹配成功时跳过的是整个匹配数据块,匹配不成功时跳过的仅是一个字节。可以结合下一小节的示例来理解。
上面说的数据块匹配只是一种描述,具体的匹配行为需要进行细化。rsync算法将数据块匹配过程分为3个层次的搜索匹配过程。
首先,主机α会对取得的数据块根据它的内容计算出它的rolling checksum,再根据此rolling checksum计算出hash值。
然后,将此hash值去和hash表中的hash条目进行匹配,这是第一层次的搜索匹配过程,它比较的是hash值。如果在hash表中能找到匹配项,则表示该数据块存在潜在相同的可能性,于是进入第二层次的搜索匹配。
第二层次的搜索匹配是比较rolling checksum。由于第一层次的hash值匹配到了结果,所以将搜索校验码集合中与此hash值对应的rolling checksum。由于校验码集合是按照hash值排序过的,所以它的顺序和hash表中的顺序一致,也就是说只需从此hash值对应的rolling chcksum开始向下扫描即可。扫描过程中,如果A文件数据块的rolling checksum能匹配某项,则表示该数据块存在潜在相同的可能性,于是停止扫描,并进入第三层次的搜索匹配以作最终的确定。或者如果没有扫描到匹配项,则说明该数据块是非匹配块,也将停止扫描,这说明rolling checksum不同,但根据它计算的hash值却发生了小概率重复事件。
第三层次的搜索匹配是比较强校验码。此时将对A文件的数据块新计算一个强校验码(在第三层次之前,只对A文件的数据块计算了rolling checksum和它的hash值),并将此强校验码与校验码集合中对应强校验码匹配,如果能匹配则说明数据块是完全相同的,不能匹配则说明数据块是不同的,然后开始取下一个数据块进行处理。
之所以要额外计算hash值并放入hash表,是因为比较rolling checksum的性能不及hash值比较,且通过hash搜索的算法性能非常高。由于hash值重复的概率足够小,所以对绝大多数内容不同的数据块都能直接通过第一层次搜索的hash值比较出来,即使发生了小概率hash值重复事件,还能迅速定位并比较更小概率重复的rolling checksum。即使不同内容计算的rolling checksum也可能出现重复,但它的重复概率比hash值重复概率更小,所以通过这两个层次的搜索就能比较出几乎所有不同的数据块。假设不同内容的数据块的rolling checksum还是出现了小概率重复,它将进行第三层次的强校验码比较,它采用的是MD4(现在是MD5),这种算法具有"雪崩效应",只要一点点不同,结果都是天翻地覆的不同,所以在现实使用过程中,完全可以假设它能做最终的比较。
数据块大小会影响rsync算法的性能。如果数据块大小太小,则数据块的数量就太多,需要计算和匹配的数据块校验码就太多,性能就差,而且出现hash值重复、rolling checksum重复的可能性也增大;如果数据块大小太大,则可能会出现很多数据块都无法匹配的情况,导致这些数据块都被传输,降低了增量传输的优势。所以划分合适的数据块大小是非常重要的,默认情况下,rsync会根据文件大小自动判断数据块大小,但rsync命令的"-B"(或"--block-size")选项支持手动指定大小,如果手动指定,官方建议大小在500-1000字节之间。
(6).当α主机发现是匹配数据块时,将只发送这个匹配块的附加信息给β主机。同时,如果两个匹配数据块之间有非匹配数据,则还会发送这些非匹配数据。当β主机陆陆续续收到这些数据后,会创建一个临时文件,并通过这些数据重组这个临时文件,使其内容和A文件相同。临时文件重组完成后,修改该临时文件的属性信息(如权限、所有者、mtime等),然后重命名该临时文件替换掉B文件,这样B文件就和A文件保持了同步。
3.2、根据执行过程分析rsync工作流程
为了更直观地感受上文所解释的rsync算法原理和工作流程,下面将给出两个rsync执行过程的示例,并分析工作流程,一个是全量传输的示例,一个是增量传输的示例。
要查看rsync的执行过程,执行在rsync命令行中加上"-vvvv"选项即可。
以下是执行过程。
[root@Mahavairocana ~]# rsync -a -vvvv /etc/cron.d /var/log/anaconda /etc/issue Mahavairocana@10.0.0.1:/tmp # 使用ssh(ssh为默认的远程shell)执行远程rsync命令建立连接 cmd=<NULL> machine=10.0.0.1 user=Mahavairocana path=/tmp cmd[0]=ssh cmd[1]=-l cmd[2]=Mahavairocana cmd[3]=10.0.0.1 cmd[4]=rsync cmd[5]=--server cmd[6]=-vvvvlogDtpre.iLsf cmd[7]=. cmd[8]=/tmp opening connection using: ssh -l Mahavairocana 10.0.0.1 rsync --server -vvvvlogDtpre.iLsf . /tmp note: iconv_open("UTF-8", "UTF-8") succeeded. Mahavairocana@10.0.0.1's password: # 双方互相发送协议版本号,并协商使用两者较低版本 (Server) Protocol versions: remote=30, negotiated=30 (Client) Protocol versions: remote=30, negotiated=30 ######### sender端生成文件列表并发送给receiver端 ############# sending incremental file list [sender] make_file(cron.d,*,0) # 第一个要传输的文件目录:cron.d文件,注意,此处cron.d是待传输的文件,而不认为是目录 [sender] make_file(anaconda,*,0) # 第二个要传输的文件目录:anaconda文件 [sender] make_file(issue,*,0) # 第三个要传输的文件目录:issue文件 # 指明从文件列表的第1项开始,并确定这次要传输给receiver的项共有3个 [sender] flist start=1, used=3, low=0, high=2 # 为这3项生成列表信息,包括此文件id,所在目录,权限模式,长度,uid/gid,最后还有一个修饰符 [sender] i=1 /etc issue mode=0100644 len=23 uid=0 gid=0 flags=5 [sender] i=2 /var/log anaconda/ mode=040755 len=4096 uid=0 gid=0 flas=5 [sender] i=3 /etc cron.d/ mode=040755 len=51 uid=0 gid=0 flags=5 send_file_list done file list sent # 唯一需要注意的是文件所在目录,例如/var/log anaconda/,但实际在命令行中指定的是/var/log/anaconda。 # 此处信息中log和anaconda使用空格分开了,这个空格非常关键。空格左边的表示隐含目录(见man rsync的"-R"选项), # 右边的是待传输的整个文件或目录,默认情况下将会在receiver端生成anaconda/目录,但左边隐含目录则不会创建。 # 但可以通过指定特殊选项(如"-R"),让rsync也能在receiver端同时创建隐含目录,以便创建整个目录层次结构。 # 举个例子,如果A主机的/a目录下有b、c等众多子目录,并且b目录中有d文件,现在只想传输/a/b/d并保留/a/b的目录层次结构, # 那么可以通过特殊选项让此处的文件所在目录变为"/ a/",关于具体的实现方法,见"rsync -R选项示例"。 ############ sender端发送文件属性信息 ##################### # 由于前面的文件列表中有两个条目是目录,因此还要为目录中的每个文件生成属性信息并发送给receiver端 send_files starting [sender] make_file(anaconda/anaconda.log,*,2) [sender] make_file(anaconda/syslog,*,2) [sender] make_file(anaconda/program.log,*,2) [sender] make_file(anaconda/packaging.log,*,2) [sender] make_file(anaconda/storage.log,*,2) [sender] make_file(anaconda/ifcfg.log,*,2) [sender] make_file(anaconda/ks-script-1uLekR.log,*,2) [sender] make_file(anaconda/ks-script-iGpl4q.log,*,2) [sender] make_file(anaconda/journal.log,*,2) [sender] flist start=5, used=9, low=0, high=8 [sender] i=5 /var/log anaconda/anaconda.log mode=0100600 len=6668 uid=0 gid=0 flags=0 [sender] i=6 /var/log anaconda/ifcfg.log mode=0100600 len=3826 uid=0 gid=0 flags=0 [sender] i=7 /var/log anaconda/journal.log mode=0100600 len=1102699 uid=0 gid=0 flags=0 [sender] i=8 /var/log anaconda/ks-script-1uLekR.log mode=0100600 len=0 uid=0 gid=0 flags=0 [sender] i=9 /var/log anaconda/ks-script-iGpl4q.log mode=0100600 len=0 uid=0 gid=0 flags=0 [sender] i=10 /var/log anaconda/packaging.log mode=0100600 len=160420 uid=0 gid=0 flags=0 [sender] i=11 /var/log anaconda/program.log mode=0100600 len=27906 uid=0 gid=0 flags=0 [sender] i=12 /var/log anaconda/storage.log mode=0100600 len=78001 uid=0 gid=0 flags=0 [sender] i=13 /var/log anaconda/syslog mode=0100600 len=197961 uid=0 gid=0 flags=0 [sender] make_file(cron.d/0hourly,*,2) [sender] make_file(cron.d/sysstat,*,2) [sender] make_file(cron.d/raid-check,*,2) [sender] flist start=15, used=3, low=0, high=2 [sender] i=15 /etc cron.d/0hourly mode=0100644 len=
增量传输执行过程
[root@Mahavairocana ~]# rsync -vvvv /tmp/init 10.0.0.1:/tmp # 使用ssh(ssh为默认的远程shell)执行远程rsync命令建立连接 cmd=<NULL> machine=10.0.0.1 user=<NULL> path=/tmp cmd[0]=ssh cmd[1]=10.0.0.1 cmd[2]=rsync cmd[3]=--server cmd[4]=-vvvve.Lsf cmd[5]=. cmd[6]=/tmp opening connection using: ssh 10.0.0.1 rsync --server -vvvve.Lsf . /tmp note: iconv_open("UTF-8", "UTF-8") succeeded. root@10.0.0.1's password: # 双方互相发送协议版本号,并协商使用两者较低版本 (Server) Protocol versions: remote=30, negotiated=30 (Client) Protocol versions: remote=30, negotiated=30 [sender] make_file(init,*,0) [sender] flist start=0, used=1, low=0, high=0 [sender] i=0 /tmp init mode=0100644 len=8640 flags=0 send_file_list done file list sent send_files starting server_recv(2) starting pid=13689 # 在远程启动receiver进程 received 1 names [receiver] flist start=0, used=1, low=0, high=0 [receiver] i=0 1 init mode=0100644 len=8640 flags=0 recv_file_list done get_local_name count=1 /tmp generator starting pid=13689 # 在远程启动generator进程 delta-transmission enabled recv_generator(init,0) recv_files(1) starting gen mapped init of size 5140 # generator进程映射basis file文件(即本地的init文件),只有映射后各进程才能获取该文件相关数据块 generating and sending sums for 0 # 生成init文件的弱滚动校验码和强校验码集合,并发送给sender端 send_files(0, /tmp/init) # 以下generator生成的校验码集合信息 count=8 rem=240 blength=700 s2length=2 flength=5140 count=8 n=700 rem=240 # count=8表示该文件总共计算了8个数据块的校验码,n=700表示固定数据块的大小为700字节, # rem=240(remain)表示最终剩240字节,即最后一个数据块的长度 chunk[0] offset=0 len=700 sum1=3ef2e827 chunk[0] len=700 offset=0 sum1=3ef2e827 chunk[1] offset=700 len=700 sum1=57aceaaf chunk[1] len=700 offset=700 sum1=57aceaaf chunk[2] offset=1400 len=700 sum1=92d7edb4 chunk[2] len=700 offset=1400 sum1=92d7edb4 chunk[3] offset=2100 len=700 sum1=afe7e939 chunk[3] len=700 offset=2100 sum1=afe7e939 chunk[4] offset=2800 len=700 sum1=fcd0e7d5 chunk[4] len=700 offset=2800 sum1=fcd0e7d5 chunk[5] offset=3500 len=700 sum1=0eaee949 chunk[5] len=700 offset=3500 sum1=0eaee949 chunk[6] offset=4200 len=700 sum1=ff18e40f chunk[6] len=700 offset=4200 sum1=ff18e40f chunk[7] offset=4900 len=240 sum1=858d519d chunk[7] len=240 offset=4900 sum1=858d519d # sender收到校验码集合后,准备开始数据块匹配过程 send_files mapped /tmp/init of size 8640 # sender进程映射本地的/tmp/init文件,只有映射后各进程才能获取该文件相关数据块 calling match_sums /tmp/init # 开始调用校验码匹配功能,对/tmp/init文件进行搜索匹配 init built hash table # sender端根据接收到的校验码集合中的滚动校验码生成16位长度的hash值,并将hash值放入hash表 hash search b=700 len=8640 # 第一层hash搜索,搜索的数据块大小为700字节,总搜索长度为8640,即整个/tmp/init的大小 sum=3ef2e827 k=700 hash search s->blength=700 len=8640 count=8 potential match at 0 i=0 sum=3ef2e827 # 在chunk[0]上发现潜在的匹配块,其中i表示的是sender端匹配块的编号 match at 0 last_match=0 j=0 len=700 n=0 # 最终确定起始偏移0上的数据块能完全匹配上,j表示的是校验码集合中的chunk编号。 # 此过程中可能还进行了rolling checksum以及强校验码的匹配 potential match at 700 i=1 sum=57aceaaf match at 700 last_match=700 j=1 len=700 n=0
四、服务搭建
主机名:Mahavairocana_M IP:192.168.1.215
主机名:Mahavairocana_S IP:192.168.1.156
软件版本
inotify-tools-3.14.tar.gz
rsync-3.1.2.tar.gz
sersync2.5.4_64bit_binary_stable_final.tar.gz
5、配置详解
1、rsync搭建
执行命令
tar -xf rsync-3.1.2.tar.gz
./configure --prefix=/usr/local/rsync/ && make && make install
配置文件详解
vim /usr/local/rsync/rsync.conf
uid = nobody #rsyncd 守护进程运行系统用户全局配置,也可在具体的块中独立配置,
gid = nobody #rsyncd 守护进程运行系统用户全局配置,也可在具体的块中独立配置,
use chroot = no #允许 chroot,提升安全性,客户端连接模块,首先chroot到模块path参数指定的目录下 #chroot为yes时必须使用root权限,且不能备份path路径外的链接文件
max connections = 10 #最大连接数
strict modes = yes #是否检查口令文件的权限
pid file = /var/run/rsyncd.pid #pid文件的存放位置
lock file = /var/run/rsync.lock #支持max connections参数的锁文件
log file = /var/log/rsyncd.log #日志文件位置,启动rsync后自动产生这个文件,无需提前创建
[1.1] #模块名称
path = /data/ #本地自定义路径
comment = client file #模块名称与自定义名称相同
ignore errors #忽略错误
read only = no #设置rsync服务端文件为读写权限
write only = no #设置rsync服务端文件为读写权限
hosts allow = 192.168.1.0/24 #服务端IP地址
hosts deny = * #止数据同步的客户端IP地址,可以设置多个,用英文状态下逗号隔开
list = false #不显示rsync服务端资源列表
uid = root #设置rsync运行权限为root
gid = root #设置rsync运行权限为root
auth users = work #模块验证用户名称,可使用空格或者逗号隔开多个用户名
secrets file = /etc/rsync.pass #自动同步密码文件
密码文件:(特别注意,服务端密码文件跟客户端不相同,服务端需要指明相关用户,客户端不需要)
客户端密码文件
[root@Mahavairocana_S ~]# echo work > /etc/rsync.pass ; chmod 600 /etc/rsync.pass
服务端密码文件
[root@Mahavairocana_M rsync]# echo work:work > /etc/rsync.pass chmod 600 /etc/rsync.pass
同步命令
[root@Mahavairocana_S ~]# /usr/local/rsync/bin/rsync -aP /data/ work@192.168.1.215::1.1 --password-file=/etc/rsync.pass
启动服务
[root@Mahavairocana_M rsync]# /usr/local/rsync/bin/rsync --daemon --config /usr/local/rsync/rsync.conf
查看端口监听(默认873)
[root@Mahavairocana_M rsync]# netstat -ntpl | grep rsync | grep -v grep
tcp 0 0 0.0.0.0:873 0.0.0.0:* LISTEN 8119/rsync
tcp 0 0 :::873 :::* LISTEN 8119/rsync
rsync 常用命令
-v:显示rsync过程中详细信息。可以使用"-vvvv"获取更详细信息。
-P:显示文件传输的进度信息。(实际上"-P"="--partial --progress",其中的"--progress"才是显示进度信息的)。
-n --dry-run :仅测试传输,而不实际传输。常和"-vvvv"配合使用来查看rsync是如何工作的。
-a --archive :归档模式,表示递归传输并保持文件属性。等同于"-rtopgDl"。
-r --recursive:递归到目录中去。
-t --times:保持mtime属性。强烈建议任何时候都加上"-t",否则目标文件mtime会设置为系统时间,导致下次更新
:检查出mtime不同从而导致增量传输无效。
-o --owner:保持owner属性(属主)。
-g --group:保持group属性(属组)。
-p --perms:保持perms属性(权限,不包括特殊权限)。
-D :是"--device --specials"选项的组合,即也拷贝设备文件和特殊文件。
-l --links:如果文件是软链接文件,则拷贝软链接本身而非软链接所指向的对象。
-z :传输时进行压缩提高效率。
-R --relative:使用相对路径。意味着将命令行中指定的全路径而非路径最尾部的文件名发送给服务端,包括它们的属性。用法见下文示例。
--size-only :默认算法是检查文件大小和mtime不同的文件,使用此选项将只检查文件大小。
-u --update :仅在源mtime比目标已存在文件的mtime新时才拷贝。注意,该选项是接收端判断的,不会影响删除行为。
-d --dirs :以不递归的方式拷贝目录本身。默认递归时,如果源为"dir1/file1",则不会拷贝dir1目录,使用该选项将拷贝dir1但不拷贝file1。
--max-size :限制rsync传输的最大文件大小。可以使用单位后缀,还可以是一个小数值(例如:"--max-size=1.5m")
--min-size :限制rsync传输的最小文件大小。这可以用于禁止传输小文件或那些垃圾文件。
--exclude :指定排除规则来排除不需要传输的文件。
--delete :以SRC为主,对DEST进行同步。多则删之,少则补之。注意"--delete"是在接收端执行的,所以它是在
:exclude/include规则生效之后才执行的。
-b --backup :对目标上已存在的文件做一个备份,备份的文件名后默认使用"~"做后缀。
--backup-dir:指定备份文件的保存路径。不指定时默认和待备份文件保存在同一目录下。
-e :指定所要使用的远程shell程序,默认为ssh。
--port :连接daemon时使用的端口号,默认为873端口。
--password-file:daemon模式时的密码文件,可以从中读取密码实现非交互式。注意,这不是远程shell认证的密码,而是rsync模块认证的密码。
-W --whole-file:rsync将不再使用增量传输,而是全量传输。在网络带宽高于磁盘带宽时,该选项比增量传输更高效。
--existing :要求只更新目标端已存在的文件,目标端还不存在的文件不传输。注意,使用相对路径时如果上层目录不存在也不会传输。
--ignore-existing:要求只更新目标端不存在的文件。和"--existing"结合使用有特殊功能,见下文示例。
--remove-source-files:要求删除源端已经成功传输的文件。
2、inotify搭建
1、查看内核是否支持inotify
[root@Mahavairocana_M rsync]# ll /proc/sys/fs/inotify
-rw-r--r-- 1 root root 0 Dec 25 14:00 max_queued_events #表示调用inotify_init时分配给inotify instance中可排队的event的数目的最大值
-rw-r--r-- 1 root root 0 Dec 25 14:00 max_user_instances #表示每一个real user ID可创建的inotify instatnces的数量上限
-rw-r--r-- 1 root root 0 Dec 25 14:00 max_user_watches #表示每个inotify instatnces可监控的最大目录数量
2、安装
[root@Mahavairocana_M ~]# ./configure --prefix=/usr/local/inotify && make && make install
3、编辑同步脚本
[root@Mahavairocana_S data]# cat /home/inotify.sh
#!/bin/bash
/usr/local/inotify/bin/inotifywait -mrq --timefmt '%d/%m/%y %H:%M' --format '%T %w%f%e' -e close_write,modify,delete,create,attrib /data/ | while read files
do
/usr/local/rsync/bin/rsync -vzrtopg --delete --progress --password-file=/etc/rsync.pass /data/ work@192.168.1.215::1.1
echo "${files} was rsynced" >>/tmp/rsync.log 2>&1
done
4、验证结果
[root@Mahavairocana_M ~]# stat /222
File: `/222'
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: ca02h/51714d Inode: 1114115 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-12-25 14:21:50.000000000 +0800
Modify: 2017-12-25 14:21:49.000000000 +0800
Change: 2017-12-25 14:21:50.000000000 +0800
[root@Mahavairocana_S data]# stat 222
File: `222'
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: ca02h/51714d Inode: 1605636 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-12-25 14:21:49.000000000 +0800
Modify: 2017-12-25 14:21:49.000000000 +0800
Change: 2017-12-25 14:21:49.000000000 +0800
[root@Mahavairocana_S data]#
inotify 常用命令
inotifywait命令的选项:
-m:表示始终监控,否则应该是监控到了一次就退出监控了
-r:递归监控,监控目录中的任何文件,包括子目录。递归监控可能会超出max_user_watches的值,需要适当调整该值
@<file>:如果是对目录进行递归监控,则该选项用于排除递归目录中不被监控的文件。file是相对路径还是绝对路径由监控目录是相对还是绝对来决定
-q:--quiet的意思,静默监控,这样就不会输出一些无关的信息
-e:指定监控的事件。一般监控的就delete、create、attrib、modify、close_write
-e可监控的事件:
access:文件被访问
modify:文件被写入
attrib:元数据被修改。包括权限、时间戳、扩展属性等等
close_write:打开的文件被关闭,是为了写文件而打开文件,之后被关闭的事件
close_nowrite:read only模式下文件被关闭,即只能是为了读取而打开文件,读取结束后关闭文件的事件
close:是close_write和close_nowrite的结合,无论是何种方式打开文件,只要关闭都属于该事件
open:文件被打开
moved_to:向监控目录下移入了文件或目录,也可以是监控目录内部的移动
moved_from:将监控目录下文件或目录移动到其他地方,也可以是在监控目录内部的移动
move:是moved_to和moved_from的结合
moved_self:被监控的文件或目录发生了移动,移动结束后将不再监控此文件或目录
create:在被监控的目录中创建了文件或目录
delete:删除了被监控目录中的某文件或目录
delete_self:被监控的文件或目录被删除,删除之后不再监控此文件或目录
umount:挂载在被监控目录上的文件系统被umount,umount后不再监控此目录
isdir :监控目录相关操作
--exclude <pattern> :通过模式匹配来指定不被监控的文件,区分大小写
--excludei <pattern>:通过模式匹配来指定不被监控的文件,不区分大小写
--timefmt:监控到事件触发后,输出的时间格式,可指定可不指定该选项,一般设置为[--timefmt '%Y/%m/%d %H:%M:%S']
--format:用户自定义的输出格式,如[--format '%w%f %e%T']
%w:产生事件的监控路径,不一定就是发生事件的具体文件,例如递归监控一个目录,该目录下的某文件产生事件,将输出该目录而非其内具体的文件
%f:如果监控的是一个目录,则输出产生事件的具体文件名。其他所有情况都输出空字符串
%e:产生的事件名称
%T:以"--timefmt"定义的时间格式输出当前时间,要求同时定义"--timefmt"
3 、sersync搭建
sersync类似于inotify,同样用于监控,但它克服了inotify的几个缺点。 inotify最大的不足是会产生重复事件,或者同一个目录下多个文件的操作会产生多个事件(例如,当监控目录中有5个文件时,删除目录时会产生6个监控事件),从而导致重复调用rsync命令。而且vim文件时,inotify会监控到临时文件的事件,但这些事件相对于rsync来说是不应该被监控的。 sersync优点:可以过滤重复事件减轻负担、自带crontab功能、多线程调用rsync、失败重传。 1.sersync是使用c++编写,而且对linux系统文件系统产生的临时文件和重复的文件操作进行过滤,所以在结合rsync同步的时候,节省了运行时耗和网络资源。因此更快。 2.sersync配置很简单,其中bin目录下已经有静态编译好的2进制文件,配合bin目录下的xml配置文件直接使用即可。 3.sersync使用多线程进行同步,尤其在同步较大文件时,能够保证多个服务器实时保持同步状态。 4.sersync有出错处理机制,通过失败队列对出错的文件重新同步,如果仍旧失败,则按设定时长对同步失败的文件重新同步。 5.sersync自带crontab功能,只需在xml配置文件中开启,即可按要求隔一段时间整体同步一次。无需再额外配置crontab功能。 6.sersync可以二次开发。 建议: (1)当同步的目录数据量不大时,建议使用rsync+inotify (2)当同步的目录数据量很大时(几百G甚至1T以上)文件很多时,建议使用rsync+sersync sersync工具包无需任何安装,解压即可使用。 sersync目录/usr/local/sersync只有两个文件:一个是二进制程序文件,一个是xml格式的配置文件。 confxml.xml sersync2 其中confxml.xml是配置文件,文件内容很容易理解。以下是示例文件内容说明。 <?xml version="1.0" encoding="ISO-8859-1"?> <head version="2.5"> <host hostip="localhost" port="8008"></host> <debug start="false"/> # 是否开启调试模式,下面所有出现false和true的地方都分别表示关闭和开启的开关 <fileSystem xfs="false"/> # 监控的是否是xfs文件系统 <filter start="false"> # 是否启用监控的筛选功能,筛选的文件将不被监控 <exclude expression="(.*)\.svn"></exclude> <exclude expression="(.*)\.gz"></exclude> <exclude expression="^info/*"></exclude> <exclude expression="^static/*"></exclude> </filter> <inotify> # 监控的事件,默认监控的是delete/close_write/moved_from/moved_to/create folder <delete start="true"/> <createFolder start="true"/> <createFile start="false"/> <closeWrite start="true"/> <moveFrom start="true"/> <moveTo start="true"/> <attrib start="false"/> <modify start="false"/> </inotify> <sersync> # rsync命令的配置段 <localpath watch="/www"> # 同步的目录或文件,同inotify+rsync一样,建议同步目录 <remote ip="192.168.1.215" name="/data"/> # 目标地址和rsync daemon的模块名,所以远端要以daemon模式先运行好rsync <!--remote ip="IPADDR" name="module"--> # 除非下面开启了ssh start,此时name为远程shell方式运行时的目标目录 </localpath> <rsync> # 指定rsync选项 <commonParams params="-az"/> <auth start="false" users="work" passwordfile="/etc/rsync.pass"/> <userDefinedPort start="false" port="874"/><!-- port=874 --> <timeout start="false" time="100"/><!-- timeout=100 --> <ssh start="false"/> # 是否使用远程shell模式而非rsync daemon运行rsync命令 </rsync> <failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/><!--default every 60mins execute once--> # 错误重传 <crontab start="false" schedule="600"><!--600mins--> # 是否开启crontab功能 <crontabfilter start="false"> # crontab定时传输的筛选功能 <exclude expression="*.php"></exclude> <exclude expression="info/*"></exclude> </crontabfilter> </crontab> <plugin start="false" name="command"/> </sersync> <plugin name="command"> <param prefix="/bin/sh" suffix="" ignoreError="true"/> <!--prefix /opt/tongbu/mmm.sh suffix--> <filter start="false"> <include expression="(.*)\.php"/> <include expression="(.*)\.sh"/> </filter> </plugin> <plugin name="socket"> <localpath watch="/opt/tongbu"> <deshost ip="0.0.0.0" port="8009"/> </localpath> </plugin> <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> 以上配置文件采用的是远程shell方式的rsync连接方式,所以无需在目标主机上启动rsync daemon。设置好配置文件后,只需执行sersync2命令即可。该命令的用法如下: sersync2命令参数 参数-d:启用守护进程模式,让sersync2运行在后台 参数-r:在监控前,将监控目录与远程主机用rsync命令推送一遍, :即首先让远端目录和本地一致,以后再同步则通过监控实现增量同步 参数-n:指定开启守护线程的数量,默认为10个 参数-o:指定配置文件,默认使用confxml.xml文件 参数-m:单独启用其他模块,使用 -m refreshCDN 开启刷新CDN模块 参数-m:单独启用其他模块,使用 -m socket 开启socket模块 参数-m:单独启用其他模块,使用 -m http 开启http模块 不加-m参数,则默认执行同步程序
示例:
sersync2 -r -d -o rsync.xml
六、常用优化
1、使源目录保存较少文件
这是一个传统优化办法,因为rsync虽然是同步所有文件,但和同步最近更新的文件是一个道理,因此将源服务器上的目录删除,仅仅保持最近更新的文件,文件数量就变得不但很少,而且是稳定的,随着时间推移,这数量也不会涨得很快。但这样做有个缺点,就是rsync不能使用删除模式,如果有文件要删除,可以将其弄成空文件,假如有更严格要求,可以另一个程序来删除。
2、使用/dev/shm内存分区
在源目录保持较少文件的前提下,将文件不存在硬盘上而放入内存,就可以避免系统IO带来的问题,但是这个内存分区在系统reboot后会丢掉所有数据,虽然并不常常需要reboot,但是其中的风险也需要计算清楚。
3、使用推送方式
因为性能问题是出现在rsync的客户端,用生产服务器抓取源服务器的话,性能问题就会出现在生产服务器上,这当然不很妥当。假如在生产服务器上使用 rsync daemon,源服务器执行rsync命令将文件推送到生产服务器上,性能问题就转移到了源服务器上,这在一定程度可以保证生产服务器的稳定性。
4、仅用一台作同步比较
假如源服务器的文件要被同步到很多台生产服务器,那么会出现rsync并发。可以分析到这些生产服务器在同一时刻文件是一致的,因此每台机都和源服务器做一次比较就是浪费的。这时可以让源服务器和生产服务器同步一次,并且使用-v参数打印出log,其它生产服务器通过同步这个log记录的文件就可以避免数次比较过程。
5、使用inotify
inotify就不是rsync了,inotify是一个守护进程,它可以监控到文件目录下的文件变动情况,根据其输出然后用rsync做文件传输,就可以减掉文件比较这个环节。inotify使用并不复杂,对文件变更情况的监控是实时的,也不消耗很多性能。
6、双路同步
以上均是对rsync性能方面做优化,但是优化也会带来问题。在3、4、5号方案中,假如生产服务器有一台机器因为负载或其它问题reboot了,在 reboot过程中同步就失败了,这部分失败的文件假如没有其它处理,就永远不会再同步到生产服务器上。这时可以使用多一路rsync来处理,譬如使用 inotify,做到了实时同步,然后再每小时进行一次完整的rsync同步。这样就可以保证有很高的同步速度,又能使丢失文件的风险控制在一小时之内。
七、抓包分析