zoukankan      html  css  js  c++  java
  • 企业集群架构-04-数据实时同步

    数据实时同步

    数据实时同步概述

    什么是实时同步

    实时同步是一种只要当前目录发生变化,则会触发一个事件,事件触发后会自动将变化的目录同步至远程服务器。


    为什么要实时同步

    • 保证数据的连续性,平滑的迁移
    • 减少人力维护成本,减少人为的干预
    • 解决nfs单点故障,备份
    • 解决大量的静态资源迁移(本地迁移云端)

    实现实时同步要利用监控服务inotify,监控同步数据服务器目录中信息的变化,发现目录中数据产生变化,就利用rsync服务推送到备份服务器上,也就是需要inotify + rsync配合使用。


    但是:

    • 随着文件数量的增大到100W+,目录下的文件列表就达20M,在网络状况不佳或者限速的情况下,变更的文件可能10来个才几M,却因此要发送的文件列表就达20M,严重减低的带宽的使用效率以及同步效率;
    • 假如inotifywait在5s内监控到10个小文件发生变化,便会触发10个rsync同步操作,结果就是真正需要传输的才2-3M的文件,比对的文件列表就达200M。
    • 使用这两个组合的好处在于,它们都是最基本的软件,可以通过不同选项做到很精确的控制,比如排除同步的目录,同步多个模块或同步到多个主机。

    因此,我们通常使用基于inotify + rsync开发的软件实现实时同步:

    1. sersyncgithub
      • 金山公司周洋在 inotify 软件基础上进行开发的,使用c++编写,采用多线程的方式进行同步,失败后还有重传机制,对临时文件过滤,自带crontab定时同步功能。
      • 采用xml配置文件,可读性较好,有些原生功能没有实现:
        • 无法实现多目录同步,只能通过多个配置文件启动多个进程
        • 文件排除功能太弱。
    2. lsyncdgithub
      • 是一个支持实时、双向、多机器的多模式文件同步工具。使用 Lua 语言封装了 inotify 和 rsync 。
      • 完美解决了 inotify+rsync海量文件同步带来的文件频繁发送文件列表的问题 —— 通过时间延迟或累计触发事件次数实现。
      • 实现简单高效的本地目录同步备份(网络存储挂载也当作本地目录),本地目录cp,本地目录rsync,远程目录rsyncssh。

    inotify基本概述

    inotify是异步的文件系统事件监控机制,利用事件驱动机制,而无须通过诸如cron等的轮询机制来获取事件,linux内核从2.6.13起支持 inotify,通过inotify可以监控文件系统中添加、删除,修改、移动等各种事件。

    查看服务器内核是否支持inotify

    Linux下支持inotify的内核最小为2.6.13

    $ ll /proc/sys/fs/inotify      # 列出下面的文件,说明服务器内核支持inotify
    -rw-r--r-- 1 root root 0 Dec 7 10:10 max_queued_events
    -rw-r--r-- 1 root root 0 Dec 7 10:10 max_user_instances
    -rw-r--r-- 1 root root 0 Dec 6 05:54 max_user_watches 
    

    inotify内核参数

    参数说明:参看man 7 inotify

    max_queued_events:    inotify事件队列最大长度,如值太小会出现 Event Queue Overflow 错误,默认值:16384
    max_user_watches:     可以监视的文件数量(单进程),默认值:8192
    max_user_instances:   每个用户创建inotify实例最大值,默认值:128  
    

    inotify参考文档

    https://github.com/rvoicilas/inotify-tools/wiki

    客户端安装inotify:基于epel源

    yum -y install inotify-tools
    

    Inotify-tools包主要文件:

    inotifywait: 在被监控的文件或目录上等待特定文件系统事件(open close delete等)发生,常用于实时同步的目录监控
    inotifywatch:收集被监控的文件系统使用的统计数据,指文件系统事件发生的次数统计
    

    inotifywait命令常见选项

    -m, --monitor        始终保持事件监听
    -d, --daemon         以守护进程方式执行,和-m相似,配合-o使用
    -r, --recursive      递归监控目录数据信息变化
    -q, --quiet          静默,仅打印时间信息
    --exclude <pattern>  指定排除文件或目录,使用扩展的正则表达式匹配的模式实现
    --excludei <pattern> 和exclude相似,不区分大小写
    -o, --outfile <file> 打印事件到文件中,相当于标准正确输出
    -s, --syslogOutput   发送错误到syslog,相当于标准错误输出
    --timefmt <fmt>      指定时间输出格式,参考 man 3 strftime
               %Y 年份信息,包含世纪信息
               %y 年份信息,不包括世纪信息
               %m 显示月份,范围 01-12
               %d 每月的第几天,范围是 01-31
               %H 小时信息,使用 24小时制,范围 00-23
               %M 分钟,范围 00-59
    
    --format <fmt>        指定事件输出格式;即实际监控输出内容
              %T  输出时间格式中定义的时间格式信息,通过 --timefmt option 语法格式指定时间信息
              %w  事件出现时,监控文件或目录的名称信息
              %f  事件出现时,将显示监控目录下触发事件的文件或目录信息,否则为空
              %e  显示发生的事件信息,不同的事件默认用逗号分隔
              %Xe 显示发生的事件信息,不同的事件指定用X进行分隔
    
    -e                    指定监控的事件,用逗号分隔,如果省略,表示所有事件都进行监听
       access 文件或目录内容被读取
       modify 文件或目录内容被写入
       create 文件或目录创建
       delete 文件或目录被删除
       attrib 文件或目录属性改变
       open 文件或目录被打开
       close 文件或目录关闭,不管读或是写模式
       close_write 文件或目录关闭,在写入模式打开之后关闭的
       close_nowrite 文件或目录关闭,在只读模式打开之后关闭的
       moved_to 文件或目录被移动到监控的目录中
       moved_from 文件或目录从监控的目录中被移动
       move 文件或目录不管移动到或是移出监控目录都触发事件
       delete_self 文件或目录被删除,目录本身被删除
       unmount 取消挂载
    

    示例:

    --timefmt "%Y-%m-%d %H:%M"
    --format "%T %w %f event: %;e"
    --format '%T %w %f'
    -e create,delete,moved_to,close_write
    

    监控一次性事件

    inotifywait /data
    

    持续监控

    inotifywait -mrq /data
    

    持续后台监控,并记录日志

    inotifywait -o /root/inotify.log -drq /data --timefmt "%Y-%m-%d %H:%M" --format "%T %w%f event: %e"
    

    持续后台监控特定事件

    inotifywait -mrq /data --timefmt "%F %H:%M" --format "%T %w%f event: %;e" -e create,delete,moved_to,close_write,attrib
    

    持续后台监控特定事件测试

    (1)安装inotify-tools包

    yum install inotify-tools  -y
    [root@centos7 ~]# 
    

    (2)监控backup目录下的文件

    inotifywait -mrq /backup --timefmt "%F %H:%M" --format "%T %w%f event: %;e" -e create,delete,moved_to,close_write,attrib  
    

    (3)新开一个窗口在data目录下进行操作 

    [root@centos7 data]# touch f1
    [root@centos7 data]# chown wang f2
    

    (4)可以看到监控窗口下实时监控此时对data目录的操作记录

    [Fri Aug 28 11:40:05 CST 2020] [root@nfs ~]
    $ inotifywait -mrq /backup --timefmt "%F %H:%M" --formate,attrib
    2020-08-31 08:51 /backup/f1 event: CREATE
    2020-08-31 08:51 /backup/f1 event: ATTRIB
    2020-08-31 08:51 /backup/f1 event: CLOSE_WRITE;CLOSE
    2020-08-31 08:52 /backup/f1 event: ATTRIB
    

    image-20200831085312984

    inotify + rsync实现实时同步

    (1)安装配置rsync服务

    参见Rsync服务使用(1)-(8)

    (2)服务端对backup目录进行监控,1秒监控一次目录

    [root@backup ~]# watch -n1 ls -l /backup
    

    (3)客户端测试rsync同步数据

    [root@nfs ~]# export RSYNC_PASSWORD=123456
    [Mon Aug 31 15:36:01 CST 2020] [root@nfs ~]
    rsync -avz /backup/ rsync_backup@172.16.1.41::backup
    sending incremental file list
    ./
    f1
    i
    
    sent 164 bytes  received 65 bytes  458.00 bytes/sec
    total size is 0  speedup is 0.00
    

    (4)服务器端此时监控到backup目录下的文件已经同步过来

    Every 1.0s: l...  Mon Aug 31 15:36:48 2020
    
    total 0
    -rwxrwxrwx 1 rsync rsync  0 Aug 31 08:51 f
    1
    -rw-r--r-- 1 rsync rsync  0 Aug 30 22:56 i
    

    (5)客户端安装inotify:基于epel源

    [root@nfs ~]# yum -y install inotify-tools
    

    (6)客户端创建脚本vi inotify_rsync.sh,实现实时同步效果

    #!/bin/bash
    SRC='/backup/'
    DEST='rsync_backup@172.16.1.41::backup'
    inotifywait -mrq --timefmt '%Y-%m-%d %H:%M' --format '%T %w %f' -e attrib,create,delete,moved_to,close_write ${SRC} | while read DATE TIME DIR FILE;do
    FILEPATH=${DIR}${FILE}
    rsync -az --delete --password-file=/etc/rsync.passwd $SRC $DEST && echo "At ${TIME} on ${DATE}, file $FILEPATH was backuped up via rsync" >> /var/log/changelist.log  # 指定日志文件
    done &
    

    (7)客户端执行脚本,并跟踪指定的日志文件

    [root@nfs ~]# bash inotify_rsync.sh
    [root@nfs ~]# tail -f /var/log/changelist.log
    At 16:16 on 2020-08-31, file /backup/1 was backuped up via rsync
    At 16:16 on 2020-08-31, file /backup/1 was backuped up via rsync
    At 16:16 on 2020-08-31, file /backup/1 was backuped up via rsync
    At 16:16 on 2020-08-31, file /backup/1 was backuped up via rsync
    At 16:17 on 2020-08-31, file /backup/1 was backuped up via rsync
    At 16:17 on 2020-08-31, file /backup/1 was backuped up via rsync
    At 16:17 on 2020-08-31, file /backup/1 was backuped up via rsync
    At 16:17 on 2020-08-31, file /backup/1 was backuped up via rsync
    

    (8)服务端跟踪此时backup目录内容

    [root@backup ~]# watch -n1 ls -l /backup
    

    (9)验证效果,在客户端backup目录下进行文件操作

    [root@nfs ~]# cd /backup
    [root@nfs /backup]# touch 1
    [root@nfs /backup]# echo 111 >> 1b
    [root@nfs /backup]# rm -rf 1
    

    观察:

    客户端日志文件变化情况

    服务端backup目录内容跟踪结果


    (10)想要注销后仍在后台运行进程,使用nohup

    nohup bash inotify_rsync.sh
    

    注意:

    ​ 输出重定向到当前目录的 nohup.out或者$HOME/nohup.out

    ​ 停止只能使用kill -9 PID

    (11)开机启动,将(10)命令加入/etc/rc.local

    lsyncd —— 多机器实时同步文件神器

    lsyncd 是一个支持实时、双向、多机器的多模式文件同步工具。

    使用 Lua 语言封装了 inotify 和 rsync 工具,采用了 Linux 内核(2.6.13 及以后)里的 inotify 触发机制,然后通过 rsync 去差异同步,达到实时的效果。

    安装

    基于epel源安装:

    yum -y install lsyncd
    

    源码编译安装:

    从源码编译安装可以使用最新版的lsyncd程序,但必须要相应的依赖库文件和编译工具:yum install lua lua-devel asciidoc cmake

    googlecode lsyncd 上下载的lsyncd-2.1.5.tar.gz,直接./configuremake && make install就可以了。

    从github上下载lsyncd-master.zip 的2.1.5版本使用的是 cmake 编译工具,无法./configure

    uzip lsyncd-master.zip
    cd lsyncd-master
    cmake -DCMAKE_INSTALL_PREFIX=/usr/local/lsyncd-2.1.5
    make && make install
    

    我这个版本编译时有个小bug,如果按照INSTALLbuild目录中make,会提示:

    [100%] Generating doc/lsyncd.1
    Updating the manpage
    a2x: failed: source file not found: doc/lsyncd.1.txt
    make[2]: *** [doc/lsyncd.1] Error 1
    make[1]: *** [CMakeFiles/manpage.dir/all] Error 2
    make: *** [all] Error 2
    

    解决办法是要么直接在解压目录下cmake,不要mkdir build,要么在CMakeList.txt中搜索doc字符串,在前面加上${PROJECT_SOURCE_DIR}

    配置

    lsyncd 主配置文件,假设放置在/etc/lsyncd.conf:

    settings {
        nodaemon = false,
        logfile = "/var/log/lsyncd.log",
        statusFile = "/var/log/lsyncd.status",
        inotifyMode = "CloseWrite",
        maxProcesses = 8
    }
    
    -- 可以有多个sync,各自的source,各自的target,各自的模式,互不影响。
    sync {
        default.rsyncssh,
        source    = "/home/wwwroot/web1/",
        host      = "111.222.333.444",
        targetdir = "/home/wwwroot/web1/",
        -- 忽略文件路径规则,可用table也可用外部配置文件
        -- excludeFrom = "/etc/lsyncd_exclude.lst",
        exclude = {
            ".svn",
            "Runtime/**",
            "Uploads/**",
        },
        -- maxDelays = 5,
        delay = 0,
        -- init = false,
        rsync = {
            binary = "/usr/bin/rsync",
            archive = true,
            compress = true,
            verbose = true,
            _extra = {"--bwlimit=2000"},
        },
    }
    

    编译安装的,简化配置

    # cd /usr/local/lsyncd-2.1.5
    # mkdir etc var
    # vi etc/lsyncd.conf
    settings {
        logfile ="/usr/local/lsyncd-2.1.5/var/lsyncd.log",
        statusFile ="/usr/local/lsyncd-2.1.5/var/lsyncd.status",
        inotifyMode = "CloseWrite",
        maxProcesses = 7,
        -- nodaemon =true,
    }
    
    sync {
        default.rsync,
        source = "/tmp/src",
        target = "/tmp/dest",
        -- excludeFrom = "/etc/rsyncd.d/rsync_exclude.lst",
        rsync = {
            binary = "/usr/bin/rsync",
            archive = true,
            compress = true,
            verbose = true
        }
    }
    

    lsyncd.conf 配置选项说明

    settings

    里面是全局设置,--开头表示注释,下面是几个常用选项说明:

    • logfile 定义日志文件
    • stausFile 定义状态文件
    • nodaemon=true 表示不启用守护模式,默认
    • statusInterval 将lsyncd的状态写入上面的statusFile的间隔,默认10秒
    • inotifyMode 指定inotify监控的事件,默认是CloseWrite,还可以是ModifyCloseWrite or Modify
    • maxProcesses 同步进程的最大个数。假如同时有20个文件需要同步,而maxProcesses = 8,则最大能看到有8个rysnc进程
    • maxDelays 累计到多少所监控的事件激活一次同步,即使后面的delay延迟时间还未到

    sync

    里面是定义同步参数,可以继续使用maxDelays来重写settings的全局变量。一般第一个参数指定lsyncd以什么模式运行:rsyncrsyncsshdirect三种模式:

    • default.rsync :本地目录间同步,使用rsync,也可以达到使用ssh形式的远程rsync效果,或daemon方式连接远程rsyncd进程;
      default.direct :本地目录间同步,使用cprm等命令完成差异文件备份;
      default.rsyncssh :同步到远程主机目录,rsync的ssh模式,需要使用key来认证

    • source 同步的源目录,使用绝对路径。

    • target 定义目的地址.对应不同的模式有几种写法:
      /tmp/dest :本地目录同步,可用于directrsync模式
      172.29.88.223:/tmp/dest :同步到远程服务器目录,可用于rsyncrsyncssh模式,拼接的命令类似于/usr/bin/rsync -ltsd --delete --include-from=- --exclude=* SOURCE TARGET,剩下的就是rsync的内容了,比如指定username,免密码同步
      172.29.88.223::module :同步到远程服务器目录,用于rsync模式
      三种模式的示例会在后面给出。

    • init 这是一个优化选项,当init = false,只同步进程启动以后发生改动事件的文件,原有的目录即使有差异也不会同步。默认是true

    • delay 累计事件,等待rsync同步延时时间,默认15秒(最大累计到1000个不可合并的事件)。也就是15s内监控目录下发生的改动,会累积到一次rsync同步,避免过于频繁的同步。(可合并的意思是,15s内两次修改了同一文件,最后只同步最新的文件)

    • excludeFrom 排除选项,后面指定排除的列表文件,如excludeFrom = "/etc/lsyncd.exclude",如果是简单的排除,可以使用exclude = LIST

      这里的排除规则写法与原生rsync有点不同,更为简单:

      • 监控路径里的任何部分匹配到一个文本,都会被排除,例如/bin/foo/bar可以匹配规则foo
      • 如果规则以斜线/开头,则从头开始要匹配全部
      • 如果规则以/结尾,则要匹配监控路径的末尾
      • ?匹配任何字符,但不包括/
      • *匹配0或多个字符,但不包括/
      • **匹配0或多个字符,可以是/
    • delete 为了保持target与souce完全同步,Lsyncd默认会delete = true来允许同步删除。它除了false,还有startuprunning值,请参考 [Lsyncd 2.1.x ‖ Layer 4 Config ‖ Default Behavior](https://github.com/axkibe/lsyncd/wiki/Lsyncd 2.1.x ‖ Layer 4 Config ‖ Default Behavior)。

    rsync

    (提示一下,deleteexclude本来都是rsync的选项,上面是配置在sync中的,我想这样做的原因是为了减少rsync的开销)

    • bwlimit 限速,单位kb/s,与rsync相同(这么重要的选项在文档里竟然没有标出)
    • compress 压缩传输默认为true。在带宽与cpu负载之间权衡,本地目录同步可以考虑把它设为false
    • perms 默认保留文件权限。
    • 其它rsync的选项

    其它还有rsyncssh模式独有的配置项,如hosttargetdirrsync_pathpassword_file,见后文示例。rsyncOps={"-avz","--delete"}这样的写法在2.1.*版本已经不支持。

    lsyncd.conf可以有多个sync,各自的source,各自的target,各自的模式,互不影响。

    lsyncd.conf其它模式示例

    settings {
        logfile = "/var/log/lsyncd/lsyncd.log",
        statusFile = "/var/log/lsyncd/lsyncd.status",
        inotifyMode = "CloseWrite",
        maxProcesses = 8,
    }
    -- I. 本地目录同步,direct:cp/rm/mv。 适用:500+万文件,变动不大
    sync {
        default.direct,
        source = "/tmp/src",
        target = "/tmp/dest",
        delay = 1
        maxProcesses = 1
    }
    -- II. 本地目录同步,rsync模式:rsync
    sync {
        default.rsync,
        source = "/tmp/src",
        target = "/tmp/dest1",
        excludeFrom = "/etc/rsyncd.d/rsync_exclude.lst",
        rsync = {
            binary = "/usr/bin/rsync",
            archive = true,
            compress = true,
            bwlimit = 2000
        }
    }
    -- III. 远程目录同步,rsync模式 + rsyncd daemon
    sync {
        default.rsync,
        source = "/tmp/src",
        target = "syncuser@172.29.88.223::module1",
        delete="running",
        exclude = { ".*", ".tmp" },
        delay = 30,
        init = false,
        rsync = {
            binary = "/usr/bin/rsync",
            archive = true,
            compress = true,
            verbose = true,
            password_file = "/etc/rsyncd.d/rsync.pwd",
            _extra = {"--bwlimit=200"}
        }
    }
    -- IV. 远程目录同步,rsync模式 + ssh shell
    sync {
        default.rsync,
        source = "/tmp/src",
        target = "172.29.88.223:/tmp/dest",
        -- target = "root@172.29.88.223:/remote/dest",
        -- 上面target,注意如果是普通用户,必须拥有写权限
        maxDelays = 5,
        delay = 30,
        -- init = true,
        rsync = {
            binary = "/usr/bin/rsync",
            archive = true,
            compress = true,
            bwlimit = 2000
            -- rsh = "/usr/bin/ssh -p 22 -o StrictHostKeyChecking=no"
            -- 如果要指定其它端口,请用上面的rsh
        }
    }
    -- V. 远程目录同步,rsync模式 + rsyncssh,效果与上面相同
    sync {
        default.rsyncssh,
        source = "/tmp/src2",
        host = "172.29.88.223",
        targetdir = "/remote/dir",
        excludeFrom = "/etc/rsyncd.d/rsync_exclude.lst",
        -- maxDelays = 5,
        delay = 0,
        -- init = false,
        rsync = {
            binary = "/usr/bin/rsync",
            archive = true,
            compress = true,
            verbose = true,
            _extra = {"--bwlimit=2000"},
        },
        ssh = {
            port = 1234
        }
    }
    

    上面的内容几乎涵盖了所有同步的模式,其中第III个要求像rsync一样配置rsyncd服务端,见本文开头。

    免密登录

    IVV配置ssh方式同步,达到的效果相同,但实际同步时你会发现每次同步都会提示输入ssh的密码,可以通过以下方法解决:

    在远端被同步的服务器上开启ssh无密码登录,请注意用户身份:

    1. user$ ssh-keygen -t rsa
    2. ...一路回车...
    3. user$ cd ~/.ssh
    4. user$ cat id_rsa.pub >> authorized_keys

    id_rsa私钥拷贝到执行lsyncd的机器上

    1. user$ chmod 600 ~/.ssh/id_rsa
    2. 测试能否无密码登录
    3. user$ ssh user@172.29.88.223

    配置lsyncd日志文件轮转,防止日志文件太大

    修改配置文件/etc/logrotate.d/lsyncd

    /var/log/lsyncd/*log { 
        missingok 
        notifempty 
        sharedscripts 
        postrotate 
            /etc/rc.d/init.d/lsyncd restart 2>&1 > /dev/null || true 
        endscript 
    }
    

    忽略规则

    需要忽略同步的文件或文件夹,excludeFrom 选项才配置该文件,exclude 类型的配置不用该配置文件。假设配置文件放在/etc/lsyncd_exclude.lst

    .svn
    Runtime/**
    Uploads/**
    

    启动

    lsyncd -log Exec /etc/lsyncd.conf
    # 启动
    # 开机启动
    

    参考

  • 相关阅读:
    HDU 6143 Killer Names【dp递推】【好题】【思维题】【阅读题】
    HDU 6143 Killer Names【dp递推】【好题】【思维题】【阅读题】
    POJ 3974 Palindrome【manacher】【模板题】【模板】
    POJ 3974 Palindrome【manacher】【模板题】【模板】
    HDU 6127 Hard challenge【计算机几何】【思维题】
    HDU 6127 Hard challenge【计算机几何】【思维题】
    HDU 6129 Just do it【杨辉三角】【思维题】【好题】
    HDU 6129 Just do it【杨辉三角】【思维题】【好题】
    HDU 3037 Saving Beans【Lucas定理】【模板题】【模板】【组合数取余】
    8.Math 对象
  • 原文地址:https://www.cnblogs.com/backups/p/14476880.html
Copyright © 2011-2022 走看看