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