zoukankan      html  css  js  c++  java
  • inotify 与 rsync文件同步实现与问题

    首先分别介绍inotify 与 rsync的使用,然后用两者实现实时文件同步,最后说一下这样的系统存在什么样的问题。

    1. inotify

    这个具体使用网上很多,参考 

    inotify-tools 命令使用讲解 

     Inotify 内核版本支持

    • 从 kernel 2.6.13 开始, Inotify 正式并入内核,RHEL5 已经支持.
    • 看看是否有 /proc/sys/fs/inotify / 目录,以确定内核是否支持 
     [root@RHEL5 Rsync]# ls -l /proc/sys/fs/inotify/
      total 0
      -rw-r--r-- 1 root root 0 Oct  9 09:36 max_queued_events
      -rw-r--r-- 1 root root 0 Oct  9 09:36 max_user_instances
      -rw-r--r-- 1 root root 0 Oct  9 09:36 max_user_watches

    /proc/sys/fs/inotify/max_queued_events 默认值: 16384 该文件中的值为调用 inotify_init 时分配给 inotify instance 中可排队的 event 的数目的最大值,超出这个值得事件被丢弃,但会触发 IN_Q_OVERFLOW 事件

    /proc/sys/fs/inotify/max_user_instances 默认值: 128 指定了每一个 real user ID 可创建的 inotify instatnces 的数量上限

    /proc/sys/fs/inotify/max_user_watches 默认值: 8192 指定了每个 inotify instance 相关联的 watches 的上限

    注意: max_queued_events 是 Inotify 管理的队列的最大长度,文件系统变化越频繁,这个值就应该越大 
    如果你在日志中看到 Event Queue Overflow,说明 max_queued_events 太小需要调整参数后再次使用.

    实例:

    inotifywait -mrq --timefmt '%y%m%d %H:%M' --format '%T %e %w%f' -o log.txt -e modify,create,delete /data

    参数说明

    语法:
    inotifywait [-hcmrq] [-e ] [-t ] [--format ] [--timefmt ] [ ... ]
    参数:
    -h,–help
    输出帮助信息
    @
    排除不需要监视的文件,可以是相对路径,也可以是绝对路径。
    –fromfile 
    从文件读取需要监视的文件或排除的文件,一个文件一行,排除的文件以 @开头。
    -m, –monitor
    接收到一个事情而不退出,无限期地执行。默认的行为是接收到一个事情后立即退出。
    -d, –daemon
    跟–monitor 一样,除了是在后台运行,需要指定–outfile 把事情输出到一个文件。也意味着使用了–syslog。
    -o, –outfile 
    输出事情到一个文件而不是标准输出。
    -s, –syslog
    输出错误信息到系统日志
    -r, –recursive
    监视一个目录下的所有子目录。
    -q, –quiet
    指定一次,不会输出详细信息,指定二次,除了致命错误,不会输出任何信息。
    –exclude 
    正则匹配需要排除的文件,大小写敏感。
    –excludei 
    正则匹配需要排除的文件,忽略大小写。
    -t , –timeout 
    设置超时时间,如果为 0,则无限期地执行下去。
    -e , –event 
    指定监视的事件。
    -c, –csv
    输出 csv 格式。
    –timefmt 
    指定时间格式,用于–format 选项中的 %T 格式。
    –format 
    指定输出格式。
    %w 表示发生事件的目录
    %f 表示发生事件的文件
    %e 表示发生的事件
    %Xe 事件以 “X” 分隔
    %T 使用由–timefmt 定义的时间格式

    可监听事件

    access 文件读取
    modify 文件更改。
    attrib 文件属性更改,如权限,时间戳等。
    close_write 以可写模式打开的文件被关闭,不代表此文件一定已经写入数据。
    close_nowrite 以只读模式打开的文件被关闭。
    close 文件被关闭,不管它是如何打开的。
    open 文件打开。
    moved_to 一个文件或目录移动到监听的目录,即使是在同一目录内移动,此事件也触发。
    moved_from 一个文件或目录移出监听的目录,即使是在同一目录内移动,此事件也触发。
    move 包括 moved_to 和 moved_from
    move_self 文件或目录被移除,之后不再监听此文件或目录。
    create 文件或目录创建
    delete 文件或目录删除
    delete_self 文件或目录移除,之后不再监听此文件或目录
    unmount 文件系统取消挂载,之后不再监听此文件系统。

    2.rsync

    参考 Linux 下 rsync 的用法

    实例 

    rsync -azcvR /data /backup

    具体各参数的含义参考链接文件

    3.inotify+rsync 同步

    参考  真正的 inotify+rsync 实时同步 彻底告别同步慢

    代码

    #!/bin/bash 
    /usr/bin/inotifywait -mrq --format '%w%f'-e create,close_write,delete /backup |while read file
    #把发生更改的文件列表都接收到 file 然后循环, 下面做的是全量 rsync
    do 
        cd /backup && rsync -az --delete /backup/ rsync_backup@192.168.24.101::backup/--password-file=/etc/rsync.password 
    done

    这个程序有个问题,就是每当inotify检测到有事件发生,都进行同步一次,太麻烦

    优化:

    #!/bin/bash
    
    src=/home/dahu/Homework/daqing                           # 需要同步的源路径
    des=/home/dahu/Homework/daqing.bk                             # 目标服务器上 
    
    cd ${src}                              # 此方法中,由于 rsync 同步的特性,这里必须要先 cd 到源目录,inotify 再监听 ./ 才能 rsync 同步后目录结构一致,有兴趣的同学可以进行各种尝试观看其效果
    
    function myfunc {               #检测父文件夹是否存在
        if [ -d $(dirname $1) ]
            then
            echo "$(dirname $1)"
        else
            dir=`dirname $1`
            myfunc $dir
        fi
    }
    
    
    true && {
    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}')      # 获取事件
        INO_FILE=$(echo $file | awk '{print $2}')       # 获取文件
        
        
        echo "-------------------------------$(date)------------------------------------"
        echo $file
        #增加、写入完成、移动进事件
        if [[ $INO_EVENT =~ 'CREATE' ]] || [[ $INO_EVENT =~ 'CLOSE_WRITE' ]] || [[ $INO_EVENT =~ 'MOVED_TO' ]]         
            then
            echo 'CREATE or CLOSE_WRITE or MOVED_TO'
            rsync -avzcuR  $(dirname ${INO_FILE}) ${des}
            #仅仅更新新的东西,需要加个u,也就是跳过所有已经存在于 DST,并且文件时间晚于要备份的文件。(不覆盖更新的文件)
        fi
        
        #修改事件
        if  [[ $INO_EVENT =~ 'MODIFY' ]]
            then
            echo 'MODIFY'
            rsync -avzcR ${INO_FILE} ${des}
            #修改文件,只需要同步该文件即可
        fi
        
        #删除、移动出事件
        if [[ $INO_EVENT =~ 'DELETE' ]] || [[ $INO_EVENT =~ 'MOVED_FROM' ]] 
            then
            echo 'DELETE or MOVED_FROM'
            rsync -avzuR --delete  $(myfunc ${INO_FILE}) ${des}
            #看 rsync 命令 如果直接同步已删除的路径 ${INO_FILE} 会报 no such or directory 错误 所以这里同步的源是被删文件或目录的上一级路径,并加上 --delete 来删除目标上有而源中没有的文件,这里不能做到指定文件删除,如果删除的路径越靠近根,则同步的目录月多,同步删除的操作就越花时间。这里有更好方法的同学,欢迎交流。
        fi
        
        #修改属性事件 指 touch chgrp chmod chown 等操作
        if [[ $INO_EVENT =~ 'ATTRIB' ]]
            then
            echo 'ATTRIB'
            if [ ! -d "$INO_FILE" ]                 # 如果修改属性的是目录 则不同步,因为同步目录会发生递归扫描,等此目录下的文件发生同步时,rsync 会顺带更新此目录。
            then
            rsync -avzcuR  ${INO_FILE} ${des}
            fi
        fi
    done
    }

     优化思路就是,把每次不同类型的事件,做一个分解:

    修改文件的,只同步该文件即可;

    增加文件或文件夹的,更新文件夹目录,注意这里的更新,是指 rsync -u   仅仅进行更新,也就是跳过所有已经存在于 DST,并且文件时间晚于要备份的文件。(不覆盖更新的文件),如果你修改了原文件的内容,但不改变名字,就意味着不同步到DST,所以先把修改内容的情况考虑了

    删除文件时,这个时候你再同步,即使使用rsync --delete, 删除那些 DST 中 SRC 没有的文件,但是这个文件夹已经删除了,所以得需要访问他存在的父文件夹,不然会报错

    即使这3个优化过了,但还是会慢,为什么?

    遇到大文件的情况,或者是简单的用vim 生成文件,这个时候inotify 会监控到很多中间文件(如vim的swp),大文件的各种modify操作,都会监控到,这个时候再用刚刚那个程序,每次监控到一个事件,(即使是优化过了,只值针对该文件,不优化的话要同步所有的),都要同步一次,麻烦且耗时。

    假设你生成1G的文件,会监控到100次的modify事件,即同步100次,那就是rsync  100*1G,当然使用-u这个参数会好一点,但是如果是修改大文件又保存呢?想象一下就知道需要不停的同步,况且,必须得等到这些前面的循环都跑完了再跑后面的,这个同步的时间不能做到很及时。  刚刚又实验了一下,7.4M的文件,需要419次

    4.自己改进

    优化的思路来源于第三点的疑问,我没必要同步那么多次(代码中的-u),在这里我在单位时间(2s)内,先把所有操作去重(针对大文件),把modify和别的操作区分对待,对modify的操作同步对应文件,其余的更新父文件夹,记得加-u 和--delete即可。应该算是解决了第3点提出的疑问,重复次数不会很多,暂时测试效果还可以。

    cat tt.sh 
    #!/bin/bash
    
    src=/home/dahu/Homework/daqing                           # 需要同步的源路径
    des=/home/dahu/Homework/daqing.bk                             # 目标服务器
    cd `dirname $src`
    rm -rf log*
    inotifywait -mrq --format  '%Xe %w%f' -e modify,create,delete,attrib,close_write,move  `basename $src` > log &
    
    function testdir {   #显示存在的最深的文件夹
        #echo 'hehe'
        if [ -d $(dirname $1) ]
            then
            echo "$(dirname $1)"
        else
            dir=`dirname $1`
            testdir $dir
        fi
    }
    
    #myfunc daqing/p/q/r/s/t
    
    #2s一次循环
    cyclenum=`wc -l log |awk '{print $1+1}'`
    while true
    do
        lastnum=$cyclenum
        sleep 1
        sec=`date +%S`
        if  [ `expr $sec % 2` = "0" ]
        then
            #date
            #这种方法是失效的,why,因为> ,文件删除或者move,就不会再继续往里添加文件了,所以按指定行数来显示比较靠谱
            #cat log > log.2
            #md1=`md5sum  log|awk '{print $1}'` &&  md2=`md5sum  log.2|awk '{print $1}'`
            #if [ $md1 != $md2 ] ;then echo "md5 not equal" && continue ;fi
            #touch log.1 && mv log.1 log && cat log.2 >> log.all 
            cyclenum=`wc -l log |awk '{print $1+1}'`
            #sed -n '94,2p' 
            sed -n "${lastnum},${cyclenum}p" log > log.2        #这一轮的操作, 暂时证明这个方法是可用的
            #sed -n "${lastnum},${cyclenum}p" log >> log.all    #用来检测是否漏掉监控的操作
            sort -u log.2 > log.uniq
    
            for line in `grep "MODIFY" log.uniq|awk '{print $2}'`
            do
                #echo $line
                if [ -f $line ] ;then rsync -avzcR $line $des;fi
            done
            for line in `awk '{print $2}' log.uniq`
            do 
                dir=`testdir $line`
                rsync -avzuR --delete $dir $des
            done 
        fi     
    done
  • 相关阅读:
    Java第四十二天,会话内容(二),Cookie(一)
    Java第四十二天,Http协议,Response
    Java第四十二天,Http协议,Request
    Java第四十二天,Http协议,响应消息的数据格式
    Java第四十二天,Http协议,请求消息的数据格式
    Java第四十二天,Servlet系列(五),Servlet 体系
    Java第四十二天,Servlet系列(四),IDEA中 的 Tomcat 配置
    8 pandas实战-美国大选数据分析
    7 Pandas-替换,映射,分组,透视表
    6 pandas人口分析案例
  • 原文地址:https://www.cnblogs.com/dahu-daqing/p/8192349.html
Copyright © 2011-2022 走看看