1)在node1 node2上实现双向无密码验证
[root@node1 ~]# ssh-keygen
[root@node1 ~]# ssh-copy-id -i .ssh/id_rsa.pub node2

[root@node2 ~]# ssh-keygen
[root@node2 ~]# ssh-copy-id -i .ssh/id_rsa.pub node1

2)node1 node2 安装软件 rsync
[root@node1 ~]# yum install -y rsync
[root@node2 ~]# yum install -y rsync

本地同步
语法:rsync -avz  [源] [目的]

在node2上测试本地同步

[root@node2 ~]# ll /test1
总用量 0
-rw-r--r-- 1 root root 0 3月  27 16:33 dfqwer
-rw-r--r-- 1 root root 0 3月  27 16:33 qwer
-rw-r--r-- 1 root root 0 3月  27 16:33 rd
[root@node2 ~]# ll /test2
总用量 0

本地同步开始

[root@node2 ~]# rsync -avz /test1/ /test2/         /test1是源  /test2是目的
sending incremental file list
./
dfqwer
qwer
rd

sent 180 bytes  received 72 bytes  504.00 bytes/sec
total size is 0  speedup is 0.00
[root@node2 ~]#

查看目的

[root@node2 ~]# ll /test2/
总用量 0
-rw-r--r-- 1 root root 0 3月  27 16:33 dfqwer
-rw-r--r-- 1 root root 0 3月  27 16:33 qwer
-rw-r--r-- 1 root root 0 3月  27 16:33 rd
[root@node2 ~]#

异地同步

从本地推送到别的机器上
语法:      rsync     -avz    [源]      IP:[目的]

从别的机器上拉取到自己的本机上
语法:      rsync     -avz   IP:[源]       [目的]

实验1:从本地推送到别的机器上(node2推送到node1)

[root@node2 /]# ll /lianshou/   本机
总用量 0
-rw-r--r-- 1 root root 0 3月  27 16:42 lllllll
-rw-r--r-- 1 root root 0 3月  27 16:42 ooooooo

[root@node1 ~]# ll /lianshou/   对方
总用量 0

[root@node2 /]# rsync -avz /lianshou/ node1:/lianshou/  本机推送到对方

sending incremental file list
 ./
 lllllll
 ooooooosent 133 bytes  received 53 bytes  124.00 bytes/sec
 total size is 0  speedup is 0.00[root@node1 ~]# ls /lianshou/               对方查看接受到的东西
 lllllll  ooooooo

实验2:从对方机器上拉取内容到本机

[root@node1 ~]# ll /lianshou/                 对方的内容
 总用量 0
 -rw-r--r-- 1 root root 0 3月  27 16:42 lllllll
 -rw-r--r-- 1 root root 0 3月  27 16:42 ooooooo
 -rw-r--r-- 1 root root 0 3月  27 17:08 sdfasdfasdfasd
 -rw-r--r-- 1 root root 0 3月  27 17:08 ttttttt[root@node2 ~]# ll /lianshou/               本机的内容
 总用量 0
 -rw-r--r-- 1 root root 0 3月  27 16:42 lllllll
 -rw-r--r-- 1 root root 0 3月  27 16:42 ooooooo

[root@node2 ~]# rsync -avz node1:/lianshou/ /lianshou/           从对方连拉取内容过来

receiving incremental file list
 ./
 lllllll
 ooooooo
 sdfasdfasdfasd
 tttttttsent 90 bytes  received 253 bytes  137.20 bytes/sec
 total size is 0  speedup is 0.00[root@node2 ~]# ll /lianshou/               查看本机接受的东西
 总用量 0
 -rw-r--r-- 1 root root 0 3月  27 16:42 lllllll
 -rw-r--r-- 1 root root 0 3月  27 16:42 ooooooo
 -rw-r--r-- 1 root root 0 3月  27 17:08 sdfasdfasdfasd
 -rw-r--r-- 1 root root 0 3月  27 17:08 ttttttt

 

在下面附上rsync常用参数说明

-v                                      详细输出模式
-q                                      精简输出模式
-c                                      打开校验开关,强制对文件传输进行校验
-a                                   归档模式,表示以递归方式传输文件,并且爆保持所有文件属性,等于-rlptgoD
-r                                    对子目录以递归模式处理
-R                                  使用相对路径信息
-p                                   保持文件权限
-o                                  保持文件属主信息
-g                                   保持文件属组信息
-t                                  保持文件时间信息
-n                                  指定那些文件将被传输
-W                                  复制文件,不进行增量检测
-e                                  使用rsh,ssh方式进行数据同步
-delete                           删除那些DST中SRC没有的文件
-timeout=TIMEIP              超时时间,单位为秒
-z                                   对备份的文件在传输时进行压缩处理
--exclude=PATTERN          指定排除不需要的传输的文件模式
--include=PATTERN           指定不排除而需要传输的文件模式
--exclude-from=FILE         排除FILE中指定模式的文件
--include-from=FILE         不排除FILE指定模式匹配的文件
--version                           打印版本信息
-address                            绑定到特定的地址
--config=FILE                     指定其他的配置文件,不使用默认的rsyncd.conf文件
--port=PORT                       指定其他的rsync服务端口
--progress                          在传输时实现传输过程
--log-format=format             指定日志文件格式
--password-file=FILE            从FILE中得到密码

rsync在数据同步时,需要扫描所有的文件进行对比,然后进行差量传输,但是文件很多,扫描文件是非常耗时的,使用rsync反而比较低效

 

rsync以守护模式启动

 

在node1上写配置文件,配置文件里主要写的是指定node1上哪个文件夹,远程对他推动,还是拉取这个这个文件夹,取决与别人的机器写的命令
在node1上写密码文件,密码文件写用户名和密码
然后在node1以守护模式启动就行了

编辑配置文件

[root@node1 ~]# vim /etc/rsyncd.conf 
 uid = nobody
 gid = nobody
 use chroot = no
 max connections = 10        //最大连接数,0是没有限制 
 strict modes = yes              检查口令文件的权限,要求是600 
 pid file = /var/run/rsyncd.pid
 lock file = /var/run/rsyncd.lock
 log file = /var/log/rsyncd.log
 [tui]                     //定义了一个模块,模块的名字任意,有代表性的
 path = /tui            //备份的目录 
 comment = tui       //描述
 ignore errors           //忽略一些无关紧要的错误 
 read only = no         //可以上传;yes 拒绝 
 write only = no          //可以下载;yes 拒绝 
 hosts allow = *         //允许连接的主机,* 所有的 
 hosts deny = 0.0.0.0/32     //拒绝连接的主机 
 list = false                           //禁止列表模式 
 uid = root                              //给这个模块设置一个单独的用户和组 
 gid = root
 auth users = backup             //验证连接的用户,用户名自定义,这个用户和系统用户无关,如果有多个,使用 , 分隔。 
 secrets file = /etc/server.pass  //口令文件


编辑密码口令文件
[root@node1 ~]# cat /etc/server.pass   
backup:etc123
设置密码口令文件权限
[root@node1 ~]# chmod 600 /etc/server.pass
然后以守护进程模式启动
[root@node1 ~]# /usr/local/bin/rsync --daemon

到此node1的配置就完成了

node2上的配置,只需要密码口令文件
[root@node2 ~]# echo etc123 > /etc/server.pass
[root@node2 ~]# chmod 600 /etc/server.pass
[root@node2 ~]# cat /etc/server.pass
etc123

(1)首先测试node2拉取node1上的文件
把node1中的/tui文件夹下的文件拉取到node2的/tmp文件夹中

[root@node2 ~]# ll /tmp
总用量 0
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi1
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi2
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi3
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi4

[root@node1 ~]# ll /tui
总用量 0
-rw------- 1 root root 0 3月  23 11:33 yum.log

拉取的语法  rsynv  各种选项   源  目的 密码文件

语法
rsync -avzr   [选项]   用户名@IP::模式名  目的  --password-file=本地密码文件路径

[root@node2 ~]# rsync -avzr backup@node1::tui /tmp/ --password-file=/etc/server.pass

receiving incremental file list
 ./
 yum.logsent 78 bytes  received 179 bytes  514.00 bytes/sec
 total size is 0  speedup is 0.00

查看本地/tmp文件夹
[root@node2 ~]# ll /tmp
总用量 0
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi1
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi2
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi3
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi4
-rw------- 1 root root 0 3月  23 11:33 yum.log

 

(2)然后测试node2往node1上推送内容
把node2中的/tmp文件夹下的文件推送到node1的/tui文件夹中

[root@node1 ~]# ll /tui
总用量 0
-rw------- 1 root root 0 3月  23 11:33 yum.log

[root@node2 ~]# ll /tmp/
总用量 0
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi1
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi2
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi3
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi4
-rw------- 1 root root 0 3月  23 11:33 yum.log

推送的语法    rsynv  各种选项   源  目的 密码文件

语法
rsync -avzr   [选项]   源  用户名@IP::模式名    --password-file=本地密码文件路径

[root@node2 ~]# rsync -avzr /tmp/ backup@node1::tui --password-file=/etc/server.pass

查看node1上是否推送过去

[root@node1 ~]# ll /tui
总用量 0
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi1
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi2
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi3
-rw-r--r-- 1 root root 0 3月  27 17:59 cishi4
-rw------- 1 root root 0 3月  23 11:33 yum.log

推送的命令写入计划任务:
每天凌晨2点半 30 2 * * * /usr/bin/rsync -avzr /tmp/
backup@node1::tui --password-file=/etc/server.pass

也可以写拉取的

 

 

rsync写入计划任务有两点缺陷

缺欠1:在2次触发同步数据之间如果出现数据丢失,那就找不到了。
缺欠2:rsync使用自己的内部算法,比对每个文件,备份的文件越多,比对的时间就越长  很容易卡死

解决缺欠1:rsync+inotify。

在node2上安装inotify工具,因为使用inotify,只能使用推送模式,检查推送的文件夹是否有内容变动,如果有,就推送过去

因为我电脑之前inotify用源码包装的,所以我就默认使用了源码包安装的路径,就不演示inotify yum的安装了,/usr/bin/inotifywait为YUM安装的命令存放路径,我自己的是
源码安装的所以,我把路径设置为/usr/local/inotify/bin//inotifywait
大家看我脚本的时候注意下路径

[root@node2 ~]# yum install -y inotify-tools-3.14-1.el6.x86_64

编写实时推送脚本
这是一个node2检测/tmp目录是否有变化,有变化就把/tmp下的内容推送到node1上的/test目录中

[root@node2 tmp]# cat inotify.sh
 #!/bin/bash
 ip=192.168.1.225
 src=/tmp
 dst=test
 user=backup
 rsync_passfile=/etc/server.pass
 inotify_home=/usr/local/inotify
 if [ ! -e "$src" ] || [ ! -e "${rsync_passfile}" ] || [ ! -e "${inotify_home}/bin/inotifywait" ] || [ ! -e "/usr/bin/rsync" ];
 then
 echo "Check File and Folder"
 exit 9
 fi
 ${inotify_home}/bin/inotifywait -mrq --timefmt '%d/%m/%y %H:%M' --format '%T %w%f' -e close_write,delete,create,attrib $src | while read line
 do
 rsync -azr  --delete ${src}/   $user@$ip::$dst --password-file=${rsync_passfile} >/dev/null 2>&1
 done
 exit 0

查看下node2 /tmp下内容

[root@node2 tmp]# ls
inotify.sh

查看下node1 /test中的内容
[root@node1 test]# ll
总用量 0

在node2上执行脚本,我们开启调试,查看脚本运行过程

[root@node2 tmp]# sh -x inotify.sh 
 + ip=192.168.1.225
 + src=/tmp
 + dst=test
 + user=backup
 + rsync_passfile=/etc/server.pass
 + inotify_home=/usr/local/inotify
 + '[' '!' -e /tmp ']'
 + '[' '!' -e /etc/server.pass ']'
 + '[' '!' -e /usr/local/inotify/bin/inotifywait ']'
 + '[' '!' -e /usr/bin/rsync ']'
 + read line
 + /usr/local/inotify/bin/inotifywait -mrq --timefmt '%d/%m/%y %H:%M' --format '%T %w%f' -e close_write,delete,create,attrib /tmp
 //到这开始监听/tmp [root@node2 tmp]# touch 123  //在/tmp创建123文件
 [root@node2 tmp]# ll


总用量 4
-rw-r--r-- 1 root root   0 3月  27 18:51 123
-rw-r--r-- 1 root root 547 3月  27 18:40 inotify.sh

node1上有了node2上的推送内容

[root@node1 test]# ll
总用量 4
-rw-r--r-- 1 root root   0 3月  27 18:51 123
-rw-r--r-- 1 root root 547 3月  27 18:40 inotify.sh

但是看脚本执行过程

+ rsync -azr --delete /tmp/  backup@192.168.1.225::test --password-file=/etc/server.pass
 + read line
 + rsync -azr --delete /tmp/  backup@192.168.1.225::test --password-file=/etc/server.pass
 + read line
 + rsync -azr --delete /tmp/  backup@192.168.1.225::test --password-file=/etc/server.pass
 + read line

创建一个文件居然同步了三次 

那么更改个文件内容呢

[root@node2 tmp]# vim 123
 123456
 "123" 1L, 7C 已写入+ rsync -azr --delete /tmp/  backup@192.168.1.225::test --password-file=/etc/server.pass
 + read line
 + rsync -azr --delete /tmp/  backup@192.168.1.225::test --password-file=/etc/server.pass
 + read line
 + rsync -azr --delete /tmp/  backup@192.168.1.225::test --password-file=/etc/server.pass
 + read line
 + rsync -azr --delete /tmp/  backup@192.168.1.225::test --password-file=/etc/server.pass
 + read line
 + rsync -azr --delete /tmp/  backup@192.168.1.225::test --password-file=/etc/server.pass
 + read line

居然同步了6次,显然这种写法效率不高

 

解决缺欠2:rsync+inotify+优化脚本。
 
到此大概了解了inotity+rysnc的同步过程,咱们看看网上大部分的写法

#!/bin/bash
/usr/local/inotify/bin/inotifywait -mrq --format '%w%f' -e create,close_write,delete /tmp | while read line
#把发生更改的文件列表都接收到line然后循环,但有什么鬼用呢?下面的命令都没有引用这个$line 下面做的是全量rsync
do
    cd /tmp && rsync -arz --delete /tmp/ backup@192.168.1.225::test --password-file=/etc/server.pass
done

注意看这里的rsync 每次都是全量的同步(这就坑爹了),而且line列表是循环形式触发rsync ,
等于有10个文件发生更改,就至少触发10次rsync全量同步(简直就是噩梦),而且一般创建个
文件,触发好几次同步,如果几百个文件变动,同步动作至少上千次,那还不如直接写个死
循环的rsync全量同步得了。

 

改良的写法

#!/bin/bash
src=/tmp
des=test
rsync_passwd_file=/etc/server.pass
ip1=192.168.1.225
user=backup
cd ${src}    # 此方法中,由于rsync同步的特性,这里必须要先cd到源目录,inotify再监听 ./ 才能rsync同步后目录结构一致,有兴趣的同学可以进行各种尝试观看其效果
/usr/local/inotify/bin/inotifywait -mrq --format  '%Xe %w%f' -e modify,create,delete,attrib,close_write,move ./ | while read line      # 把监控到有发生更改的文件写到line变量中
do
        INO_EVENT=$(echo $line | awk '{print $1}')              # 把inotify输出切割 把事件类型部分赋值给INO_EVENT
        INO_FILE=$(echo $line | awk '{print $2}')                   # 把inotify输出切割 把文件路径部分赋值给INO_FILE
        echo "-------------------------------$(date)------------------------------------"
        echo $line
        #增加、修改、写入完成、移动进事件
        #增、改放在同一个判断,因为他们都肯定是针对文件的操作,即使是新建目录,要同步的也只是一个空目录,不会影响速度。
        if [[ $INO_EVENT =~ 'CREATE' ]] || [[ $INO_EVENT =~ 'MODIFY' ]] || [[ $INO_EVENT =~ 'CLOSE_WRITE' ]] || [[ $INO_EVENT =~ 'MOVED_TO' ]]
        then
                echo 'CREATE or MODIFY or CLOSE_WRITE or MOVED_TO'
                rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE})${user}@${ip1}::${des}              # INO_FILE变量代表路径
        
                #仔细看 上面的rsync同步命令 源是用了$(dirname ${INO_FILE})变量 即每次只针对性的同步发生改变的文件的目录(只同步目标文件的方法在生产环境的某些极端环境下会漏文件 现在可以在不漏文件下也有不错的速度 做到平衡) 然后用-R参数把源的目录结构递归到目标后面 保证目录结构一致性
        fi

        if [[ $INO_EVENT =~ 'DELETE' ]] || [[ $INO_EVENT =~ 'MOVED_FROM' ]]
        #删除、移动出事件
        then
                echo 'DELETE or MOVED_FROM'
                rsync -avzR --delete --password-file=${rsync_passwd_file} $(dirname ${INO_FILE})${user}@${ip1}::${des}
                 #看rsync命令 如果直接同步已删除的路径${INO_FILE}会报no such or directory错误 所以这里同步的源是被删文件或目录的上一级路径,并加上--delete来删除目标上有而源中没有的文件,这里不能做到指定文件删除,如果删除的路径越靠近根,则同步的目录月多,同步删除的操作就越花时间。这里有更好方法的同学,欢迎交流。
        fi

        if [[ $INO_EVENT =~ 'ATTRIB' ]]
         #修改属性事件 指 touch chgrp chmod chown等操作
        then
                echo 'ATTRIB'
                if [ ! -d "$INO_FILE" ]             # 如果修改属性的是目录 则不同步,因为同步目录会发生递归扫描,等此目录下的文件发生同步时,rsync会顺带更新此目录。
                then
                        rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE})${user}@${ip1}::${des}
                        
                fi
        fi
done

注意虽然创建一个文件依然会同步好几次,但是这个不会是全部同步,而是同步这个文件的所在的文件夹,假如一个项目中很多个文件夹,只有一个
文件夹一个文件发生了变动,只要同步这个项目中的文件夹就可以了,而不会同步所有的文件

 

每两小时做1次全量同步

因为inotify只在启动时会监控目录,他没有启动期间的文件发生更改,他是不知道的,所以这里每2个小时做1次全量同步,防止各种意外遗漏,保证目录一致。

crontab -e
* */2 * * * rsync -avz --password-file=/etc/server.pass /tmp/
backup@node1::test

这种百万级小文件也能做到实施同步了。

 

下面附上inotify的参数说明

inotify介绍-- 是一种强大的、细颗粒的、异步的文件系统监控机制,内核从2.6.13起,
加入Inotify可以监控文件系统中添加、删除、修改移动等各种事件,利用这个内核接
口,就可以监控文件系统下文件的各种变化情况。

inotifywait                     参数说明

-m,–monitor                   始终保持事件监听状态
-r,–recursive                  递归查询目录
-q,–quiet                       只打印监控事件的信息
–excludei                       排除文件或目录时,不区分大小写
-t,–timeout                     超时时间
–timefmt                       指定时间输出格式
–format                         指定时间输出格式
-e,–event                       后面指定删、增、改等事件

inotifywait events             事件说明

access                          读取文件或目录内容
modify                          修改文件或目录内容
attrib                            文件或目录的属性改变
close_write                     修改真实文件内容
close_nowrite 
close 
open                              文件或目录被打开
moved_to                       文件或目录移动到
moved_from                   文件或目录从移动
move                            移动文件或目录移动到监视目录
create                           在监视目录下创建文件或目录
delete                           删除监视目录下的文件或目录
delete_self 
unmount                       卸载文件系统

优化 Inotify

# 在/proc/sys/fs/inotify目录下有三个文件,对inotify机制有一定的限制

[root@web ~]# ll /proc/sys/fs/inotify/
总用量0
-rw-r--r--1 root root 09月923:36 max_queued_events
-rw-r--r--1 root root 09月923:36 max_user_instances
-rw-r--r--1 root root 09月923:36 max_user_watches

max_user_watches #设置inotifywait或inotifywatch命令可以监视的文件数量(单进程)

max_user_instances #设置每个用户可以运行的inotifywait或inotifywatch命令的进程数

max_queued_events #设置inotify实例事件(event)队列可容纳的事件数量

 

[root@web ~]# echo 50000000>/proc/sys/fs/inotify/max_user_watches -- 把他加入/etc/rc.local就可以实现每次重启都生效
[root@web ~]# echo 50000000>/proc/sys/fs/inotify/max_queued_events

 

下面是把rsync做成系统服务的样子,还有设置为开机启动服务

[root@node1 init.d]# cat /etc/init.d/rsyncd 
 #!/bin/bash
 #
 # rsync Start|Stop script for the Rsync service
 #
 # chkconfig: - 13 87
 # description: The Rsyncd Server management shell script
 # processname: rsyncd
 # config: /etc/rsyncd.conf
 # pidfile: /var/run/rsyncd.pid
 # Source function library.
 . /etc/rc.d/init.d/functions
 start () {
 ls /var/run/rsyncd.pid &> /dev/null
 if [ $? -ne 0 ]
 then
 /usr/bin/rsync --daemon
 count=$(ps -ef | grep -v grep | grep -c rsync)
         if [ $? -eq 0 -a ${count} -gt 1 ]
         then
         echo -e "Starting rsyncd:\t\t\t[ \e[1;32mOK\e[0m ]"
         else
         echo -e "Starting rsyncd:\t\t\t[\e[1;31mFAILED\e[0m]"
         fi
 else
 echo -e "Starting rsyncd:\t\t\t[\e[1;31mFAILED\e[0m]"7/12
 fi
 } stop () {
 ls /var/run/rsyncd.pid &> /dev/null
 if [ $? -eq 0 ]
 then
 kill -9 `cat /var/run/rsyncd.pid` && /bin/rm -rf /var/run/rsyncd.pid
         if [ $? -eq 0 ]
         then
         echo -e "Stopping rsyncd:\t\t\t[ \e[1;32mOK\e[0m ]"
         else
         echo -e "Stopping rsyncd:\t\t\t[\e[1;31mFAILED\e[0m]"
         fi
 else
 echo -e "Stopping rsyncd:\t\t\t[\e[1;31mFAILED\e[0m]"
 fi
 }
 case $1 in
 start)
 start
 ;;
 stop)
 stop
 ;;
 restart|reload)
 stop
 start
 ;;
 *)
 echo "Usage: rsyncd {start|stop|restart|reload}"
 ;;
 esac
 #end开机自启动
 [root@node1 init.d]# chkconfig rsyncd --list
 rsyncd 服务支持 chkconfig,但它在任何级别中都没有被引用(运行“chkconfig --add rsyncd”)
 [root@node1 init.d]# chkconfig --add rsyncd
 [root@node1 init.d]# chkconfig rsyncd on
 [root@node1 init.d]# chkconfig rsyncd --list
 rsyncd          0:关闭  1:关闭  2:启用  3:启用  4:启用  5:启用  6:关闭 [root@node1 init.d]# find -L /etc -name  rsyncd   
 /etc/rc.d/init.d/rsyncd
 /etc/init.d/rsyncd