第八章 使用拓展
8.1 共享文件夹
8.2 本地备份
8.3 云备份
8.4 双向同步
8.5 服务器集群同步
8.6 高效替代Tftp
8.7 跨平台数据同步(已支持 windows 和 Linux 间传输)
结论
纵观这个嵌入式数据同步技术领域,时代的迅速发展也为互联网的丰富性和高效性打下了坚实的基础,而数据的大量增长和爆发而导致的数据同步问题也日益突出,在此社会形态下,人们对互联网的高效数据传输也产生了更进一步的需求,这一点更是体现在对数据的实时同步提出了更大的需求,为了迎合这种大众市场需求,本框架力求做到数据实时同步无延时,可按照需求进行个性化同步,更多功能升级可以再后面的升级维护中不断补充,使得更多的系统能够适配此框架。在技术方面,使用的rsync分别对所有数据文件进行增量同步和全量同步,使得系统间可以得到实时的数据同步信息,同时也使得信息传输的准确性得到了保证。运用了高效的数据同步算法,保证不丢包,而且信息处理高效,可以对多客户端进行实时数据同步。经过不断地编写修改配置文件,运行测试和解决 bug,终于定下了最终版本,关于rsync+inotify数据同步框架主要优势如下,整个框架中主要体现在以下三个方面:
因为做项目测试的时候时间有限,该系统在测试逻辑和容灾测试上仍存在一定的逻辑漏洞,所以有一部分的功能并未完全测试实现,还有一个问题是:rsync+inotify运行时是处于阻塞状态,因此可能要多开一个窗口来运行此脚本,解决的方法如下:
最后一个问题是,在网上搜寻了很多资料,据说网上的rsync+inotify 每次都是全量的同步,而且 file列表是循环形式触发rsync ,等于有10个文件发生更改,就触发10次rsync全量同步,等于直接写个死循环的rsync全量同步,一旦文件量达到百万级别,就会出现同步慢的问题。
有很多人会说 日志输出那里明明只有差异文件的同步记录。其实这是rsync的功能,他本来就只会输出有差异需要同步的文件信息。这种在需要同步的源目录文件量很大的情况下,简直是不堪重负。不仅耗CPU还耗时,根本不可以做到实时同步。
要做到实时,就必须要减少rsync对目录的递归扫描判断,尽可能的做到只同步inotify监控到已发生更改的文件。结合rsync的特性,所以可以根据不同事件分开判断来实现一个目录的增删改查对应的操作。
详见博客https://www.cnblogs.com/ginvip/p/6430986.html
例子如下:
#!/bin/bash
src=/data/ # 需要同步的源路径
des=data # 目标服务器上 rsync --daemon 发布的名称,rsync --daemon这里就不做介绍了,网上搜一下,比较简单。
rsync_passwd_file=/etc/rsyncd.passwd # rsync验证的密码文件
ip1=192.168.0.18 # 目标服务器1
ip2=192.168.0.19 # 目标服务器2
user=root # rsync --daemon定义的验证用户名
cd ${src}
# 此方法中,由于rsync同步的特性,这里必须要先cd到源目录,inotify再监听 ./ 才能rsync同步后目录结构一致,有兴趣的同学可以进行各种尝试观看其效果
/usr/local/bin/inotifywait -mrq --format '%Xe %w%f' -e modify,create,delete,attrib,close_write,move ./ | while read file
# 把监控到有发生更改的"文件路径列表"循环
do
INO_EVENT=$(echo $file | awk '{print $1}') # 把inotify输出切割 把事件类型部分赋值给INO_EVENT
INO_FILE=$(echo $file | awk '{print $2}') # 把inotify输出切割 把文件路径部分赋值给INO_FILE
echo "-------------------------------$(date)------------------------------------"
echo $file
#增加、修改、写入完成、移动进事件
#增、改放在同一个判断,因为他们都肯定是针对文件的操作,即使是新建目录,要同步的也只是一个空目录,不会影响速度。
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变量代表路径 -c校验文件内容
rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip2}::${des}
#仔细看 上面的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 -avzR --delete --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip2}::${des}
#看rsync命令 如果直接同步已删除的路径${INO_FILE}会报no such or directory错误 所以这里同步的源是被删文件或目录的上一级路径
#并加上--delete来删除目标上有而源中没有的文件,这里不能做到指定文件删除,如果删除的路径越靠近根,则同步的目录月多,同步删除的操作就越花时间。
if [ ! -d "$INO_FILE" ]
# 如果修改属性的是目录 则不同步,因为同步目录会发生递归扫描,等此目录下的文件发生同步时,rsync会顺带更新此目录。
then
rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip1}::${des} &&
rsync -avzcR --password-file=${rsync_passwd_file} $(dirname ${INO_FILE}) ${user}@${ip2}::${des}
fi
fi
done
据说优化后的脚本的效果可以只同步发生变化的那一个目录,减少对对文件目录的扫描,可以轻松应对百万级文件的实时同步,由于这属于系统运维的范畴,而且语法属于脚本语法,后续我将加快学习运维和脚本方面的内容,以改进此脚本的同步逻辑,以便做到大数据也能做到实时同步。
而实现的结果和理论上也存在一定的误差,后续将不断进行纠正和完善。
对于脚本的编写设计,该脚本的设计较为简洁,因此缺失了对超高文件量并发情况的考虑,对此我有在网上搜寻大量关于优化脚本以应对超高文件量并发数据同步的情况,以便在日后的工作中依旧不断改进。
致谢
感谢同事们和领导对我生活上的关心以及对我工作上的协助和耐心指导!!!
也感谢百度和博客对我的帮助!!!
附录一
###全局参数###
#address=*
#在独立运行时,用于指定的服务器运行的 IP 地址。由 xinetd 运行时将忽略此参数,使用命令行上的 –address 选项替代。 默认值本地所有IP
#port=873
# 指定 rsync 守护进程监听的端口号。 由 xinetd 运行时将忽略此参数,使用命令行上的–port 选项替代。 默认值873
#motd file=/var/run/rsyncd.motd
# 指定一个消息文件,当客户连接服务器时该文件的内容显示给客户。 默认值无
pid file=/var/run/rsyncd.pid
# rsync 的守护进程将其 PID 写入指定的文件。 默认值无
log file=/var/log/rsync.log
# 指定 rsync 守护进程的日志文件,而不将日志发送给 syslog。 默认值无
#syslog facility=
# 指定 rsync 发送日志消息给 syslog 时的消息级别。
#daemon socket options= # 指定 自定义 TCP 选项。 默认值无
##模块一##
[share]
comment = “欢迎来到169.254.0.123的share模块”
#给模块指定一个描述,该描述连同模块名在客户连接得到模块列表时显示给客户。
path=/share/
#指定当前模块在 rsync 服务器上的同步路径,该参数是必须指定的。
####模块二####
#基本模块参数
[nand]
comment = “欢迎来到169.254.0.123的nand模块”
path = /nand/app/test/
#模块控制参数
use chroot=true
# 若为 true,则 rsync 在传输文件之前首先 chroot 到 path 参数所指定的目录下。这样做的原因是实现额外的安全防护,但是缺点是需要 root 权限,并且不能备份指向 path 外部的符号连接所指向的目录文件。 默认true
uid=root
# 指定该模块以指定的 UID 传输文件。 默认nobody
gid=root
# 指定该模块以指定的 GID 传输文件。 默认nobody
max connections=200
# 指定该模块的最大并发连接数量以保护服务器,超过限制的连接请求将被告知随后再试。 默认0(没有限制)
lock file=/var/run/rsyncd.lock
# 指定支持 max connections 参数的锁文件。 默认/var/run/rsyncd.lock
list=true
# 指定当客户请求列出可以使用的模块列表时,该模块是否应该被列出。如果设置该选项为 false,可以创建隐藏的模块。 默认true
read only=false
# 指定是否允许客户上传文件。若为 true 则不允许上传;若为 false 并且服务器目录也具有读写权限则允许上传。 默认true
write only=false
# 指定是否允许客户下载文件。若为 true 则不允许下载;若为 false 并且服务器目录也具有读权限则允许下载。 默认false
ignore errors=true
# 指定 在 rsync 服务器上运行 delete 操作时是否忽略 I/O 错误。一般来说 rsync 在出现 I/O 错误时将将跳过 –delete 操作,以防止因为暂时的资源不足或其它 I/O 错误导致的严重问题。 默认true
ignore nonreadable=false
# 指定 rysnc 服务器完全忽略那些用户没有访问权限的文件。这对于在需要备份的目录中有些不应该被备份者获得的文件时是有意义的。 默认false
timeout=600
# 该选项可以覆盖客户指定的 IP 超时时间。从而确保 rsync 服务器不会永远等待一个崩溃的客户端。对于匿名 rsync 服务器来说,理想的数字是 600(单位为秒)。 默认0 (未限制)
#dont compress=
# 指定那些在传输之前不进行压缩处理的文件。该选项可以定义一些不允许客户对该模块使用的命令选项列表。必须使用选项全名,而不能是简称。当发生拒绝某个选项的情况时,服务器将报告错误信息然后退出。
# 例如,要防止使用压缩,应该是:”dont compress = *”。 默认值*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz
#模块文件筛选参数
#exclude=
#指定多个由空格隔开的多个文件或目录(相对路径),并将其添加到 exclude 列表中。这等同于在客户端命令中使用 –exclude 来指定模式。 默认空
#excludefrom=
#指定一个包含 exclude 规则定义的文件名,服务器从该文件中读取 exclude 列表定义。 默认空
#include=
#指定多个由空格隔开的多个文件或目录(相对路径),并将其添加到 include 列表中。这等同于在客户端命令中使用 –include 来指定模式 。 默认空
#include from=
#指定一个包含 include 规则定义的文件名,服务器从该文件中读取 include 列表定义。 默认空
#模块用户认证参数
auth users=root
#指定由空格或逗号分隔的用户名列表,只有这些用户才允许连接该模块。这里的用户和系统用户没有任何关系。用户名和口令以明文方式存放在参数指定的文件中。 (匿名方式)
secrets file=/etc/rsync.secrets
#secrets file 指定一个 rsync 认证口令文件。只有在 auth users 被定义时,该文件才起作用。 默认空
strict modes=false
#指定是否监测口令文件的权限。若为 true 则口令文件只能被 rsync 服务器运行身份的用户访问,其他任何用户不可以访问该文件。 默认true
#模块访问控制参数
hosts allow=*
#用一个主机列表指定哪些主机客户允许连接该模块。不匹配主机列表的主机将被拒绝。默认*
hosts deny=nobody
#用一个主机列表指定哪些主机客户不允许连接该模块。默认空
#模块日志参数
transfer logging=true
#使 rsync 服务器将传输操作记录到传输日志文件。 默认false
log format=”%o %h [%a] %m (%u) %f %l”
#指定传输日志文件的字段。 ”%o %h [%a] %m (%u) %f %l”
#* 设置了”log file”参数时,在日志每行的开始会添加”%t [%p]“。
#可以使用的日志格式定义符如下所示:
%a - 远程IP地址
%h - 远程主机名
%l - 文件长度字符数
%p - 该次 rsync 会话的 PID
%o - 操作类型:”send” 或 “recv”
%f - 文件名
%P - 模块路径
%m - 模块名
%t - 当前时间
%u - 认证的用户名(匿名时是 null)
%b - 实际传输的字节数
%c - 当发送文件时,记录该文件的校验码
附录二
参数名称 | 参数说明 |
-m,–monitor | 始终保持事件监听状态 |
-r,–recursive | 递归查询目录 |
-q,–quiet | 只打印监控事件的信息 |
–excludei | 排除文件或目录时,不区分大小写 |
-t,–timeout | 超时时间 |
–timefmt | 指定时间输出格式 |
–format | 指定时间输出格式 |
-e,–event | 后面指定删、增、改等事件 |
事件名称 | 事件说明 |
access | 读取文件或目录内容 |
modify | 修改文件或目录内容 |
attrib | 文件或目录的属性改变 |
close_write | 修改真实文件内容 |
close_nowrite | |
close | |
open | 文件或目录被打开 |
moved_to | 文件或目录移动到 |
moved_from | 文件或目录从移动 |
move | 移动文件或目录移动到监视目录 |
create | 在监视目录下创建文件或目录 |
delete | 删除监视目录下的文件或目录 |
delete_self | |
unmount | 卸载文件系统 |
优化
# 在/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