Linux rsync 企业级应用
简介
rsync 是 Linux 下的数据同步工具, 其支持本地同步和远程同步, 远程同步分为 daemon 和 ssh 同步方式
rsync 可以代替 cp, scp 等命令, 且具有更高的可靠性
优点:
1、同步时能够完整的保留数据目录结构、权限、时间、软硬链接等
2、能够实现增量同步, 每一次同步只会同步发生过改变的数据
3、文件传输效率高
4、支持匿名传输
5、无须特殊权限即可安装
6、支持流控制, 可以精确同步速度和使用的带宽大小
rsync 常用命令
-v, --verbose 输出详细的数据同步过程 --version 查看版本信息 -q, --quiet 静默模式 -c, --checksum 对传输的数据进行校验和检查, 默认情况下 rsync 进行快速检查, 使用基于校验和的检查意味着会大量的消耗磁盘 IO 降低传输速度 -a, --archive 归档模式, 等于 -rlptgoD -d --dirs 以不递归的方式拷贝目录本身。递归时, 如果源为 "dir1/file1", 则不会拷贝 dir1 目录, 使用该选项将拷贝 dir1 但不拷贝 file1 -P, --partial 保留那些因故没有完全传输的文件, 以加快随后的再次传输 -r, --recursive 递归复制目录 -R --relative 使用相对路径, 这意味着将命令行中指定的全路径而非路径最尾部的文件名发送给服务端 -b, --backup 创建备份, rsync 将在每个文件被传输或删除时重命名(filename~) 先前存在的目标文件 --backup-dir=DIR 使用 -b 创建备份时, 可以使用 --backup-dir 将文件备份到指定的目录中 --suffix=SUFFIX 使用 -b 创建备份时, 可以使用 --suffix 指定备份文件的后缀(默认为 filename~) -u, --update 仅在源 mtime 比目标已存在文件的mtime新时才拷贝, 注意: 该选项是接收端判断的, 不会影响删除行为 -l, --links 遇到符号链接时, 在目标上重新创建符号链接 -L, --copy-links 遇到符号链接时, 拷贝符号链接指向的原文件 --safe-links 忽略指向复制树之外的所有符号链接 -k, --copy-dirlinks 如果符号链接为一个目录, 则进行 --copy-links 操作, 如果您不希望非目录的符号链接受到影响, 这是非常有用的 -H, --hard-links 保持硬链接 -p, --perms 保持文件权限 -A, --acls 保持文件的 acl, 原系统和目标系统的 ACL 兼容才能工作 -o, --owner 保持文件的属主, 仅当接收到的 rsync 作为超级用户运行时才能工作, 默认权限为接受端用户的权限 -g, --group 保持文件的属组, 仅当接收到的 rsync 作为超级用户运行时才能工作 -D, --devices 保持设备文件信息, 仅当接收到的 rsync 作为超级用户运行时才能工作 -t, --times 保持文件修改时间 -O, --omit-dir-times 保持文件修改时间时忽略目录, 如果在接收端使用 NFS 共享目录, 则最好使用 -O 选项 -J, --omit-link-times 保持文件修改时间时忽略符号链接 --super 告诉接受方尝试以超级用户运行 rsync, 如果是超级用户可以使用 --no-super 关闭以超级用户身份运行 --fake-super 通过尝试添加特殊权限来模拟超级用户运行 -S, --sparse 对稀疏文件进行特殊处理以节省 DST 的空间 -n, --dry-run 测试运行, 查看将有哪些数据被传输 -W, --whole-file 禁用增量检测, rsync 将使用全量传输, 在网络带宽高于磁盘带宽时, 该选项比增量传输更高效 -x, --one-file-system 禁止跨越文件系统(当遇到符号链接时, 如果符号链接为一个目录, 则 rsync 将其当成一个挂载点忽略; 如果符号链接为文件则不受此选项影响) --existing 仅更新目标端已存在的文件, 跳过 DST 上不存在的文件或目录, 该选项和 --ignore-existing 一起使用时将不会更新任何的文件(在使用 --delete 时肯会有用, 这将删除 DST 上多余的文件) --ignore-non-existing 和 --existing 相同 --ignore-existing 仅更新目标端不存在的文件, 跳过 DST 上已存在的文件或目录 delete 操作: --delete 删除 DST 上 SRC 不存在的数据 # 下面 4 个选项都隐含了 delete 操作 --delete-before 在传输文件之前先执行 delete 操作(这在 DST 磁盘空间比较紧缺时是比较有效的), 如果指定了传输超时时间该选项可能会造成传输超时 该选项强制 rsync 使用旧的非增量的递归算法, 该算法要求 rsync 扫描传输中的所有文件 --delete-during, --del --delete 在大多数情况下采用的算法 ,请求在传输发生时增量地删除接收端上的文件, 每个目录的删除扫描是在每个目录检查更新之前完成的, 相对于 --delete-before 更高效 --delete-after 请求在传输完成后删除接收端上的文件, 该选项强制 rsync 使用旧的非增量的递归算法, 该算法要求 rsync 扫描传输中的所有文件 --delete-delay 请求在传输过程中计算接收端上的文件删除, 然后在传输完成后删除 这在与 --delay-updates and/or --fuzzy 使用时非常用于, 比 --delete-after 更有效 --ignore-errors 及时出现 IO 错误也进行 delete 操作 --remove-source-files 删除源端文件, 当 rsync 将源端的文件拷贝到 DST 时, rsync 将会删除源端的文件, 没有拷贝或者拷贝失败的文件不会被删除 --size-only rsync 仅检查文件大小, 默认情况下 rsync 会检查文件大小和 mtime --force 当要使用非目录替换一个非空目录时, 删除非空目录(删除目录, 即使目录不为空) --max-delete=NUM 指定删除文件或目录的最大数量 --max-size=SIZE 指定传输文件的最大大小, 单位K, M, G --min-size=SIZE 指定传输文件的最小大小, 单位K, M, G -f, --filter=RULE 使用指定规则筛选不需要传输的数据, 示例: rsync -r --filter='exclude *.log' /var/log/ /mnt/ RULE: 1、exclude 规则: 即排除规则, 只作用于发送端, 被排除的文件不会进入文件列表 2、include 规则: 即包含规则, 只作用于发送端, 被包含的文件将明确记录到文件列表中 3、hide 规则: 即隐藏规则, 只作用于发送端, 隐藏后的文件对于接收端来说是看不见的, 也就是说接收端会认为它不存在于源端 4、show 规则: 即显示规则, 只作用于发送端, 是隐藏规则的反向规则 5、protect 规则: 即保护规则, 该规则只作用于接收端, 被保护的文件不会被删除掉 6、risk 规则: 即取消保护规则, 是protect的反向规则 7、clear 规则: 删除i nclude/exclude 规则列表 --exclude=PATTERN --filter 的简写模式, 指定排除不需要传输的文件模式 --include=PATTERN --filter 的简写模式, 指定不排除而需要传输的文件模式 -z, --compress 传输数据时启用压缩, 这个操作会用到大量的cpu资源, 但是可以节约带宽 --compress-level=NUM 压缩级别 --skip-compress=LIST 不压缩的文件列表(已经压缩过的文件通常不需要再压缩), 示例: --skip-compress=gz/jpg/7z/bz2 (不压缩 gz, jpg, 7z, bz2) 等类型的文件 --bwlimit=RATE 指定传输速率, 单位秒(s), 示例: --bwlimit=10m --timeout=TIMEOUT 设置 I/O 超时时间, 如果在这段时间之内没有传输数据则 rsync 退出, 单位秒(s), 默认值为 0, 表示永不超时 --contimeout 设置与 rsync daemon 连接超时的时间 --log-file 指定日志文件 --log-file-format 设置日志格式 --stats 输出传输过程中的详细信息 --iconv=CONVERT_SPEC 指定传输编码, 默认 utf8 --no-OPTION 在选项见面加一个 --no 表示关闭这个选项(rsync 有一些默认选项, 可以使用这个参数来关闭它), 注意: 不是所有选项都可以关闭 # 作为 daemon 运行的参数 --daemon 将 rsync 作为守护进程运行 --address rsync daemon 监听的地址 --port rsync daemon 监听的端口 --sockopts 监听的 unix 套接字地址 --password-file=FILE 从指定文件获取 rsync daemon 的用户名和密码 -4, --ipv4 监听 ipv4 地址 -6, --ipv6 监听 ipv6 地址 --config 指定配置文件 --bwlimit=RATE 设置传输速率
本地文件系统之间的同步
# 将 /etc 同步到 /mnt/, 注意: 如果 etc 结尾加上 / 将同步 etc 目录下的所有文件单不会同步 etc 这个目录 rsync -a /etc /mnt/ # 将 /etc/yum.repos.d 拷贝到 /mnt, 目录结构为 /mnt/yum.repos.d/ rsync -r /etc/yum.repos.d /mnt # 将 /etc/yum.repos.d 拷贝到 /mnt, 但是在 yum.repos.d 上面生成 etc 目录, 目录结构为 /mnt/etc/yum.repos.d/ rsync -Rr /etc/yum.repos.d /mnt # 对长目录进行划分, 以 . 表示相对目录的起点, 目录结构为 /mnt/system/reboot.target.wants/ rsync -Rr /usr/lib/systemd/./system/reboot.target.wants/ /mnt/ # 将 /var/log 目录下除以 .log 结尾的文件和目录结尾的数据同步到 /mnt rsync -a --exclude='*.log' /var/log /mnt/ # 删除 /var/log/ 所有以 .log 结尾的文件 rsync -a --delete /mnt/log/ /var/log/ # 以每秒 1k 的速度同步 rsync -av --bwlimit=1k /etc/yum.repos.d/ /mnt/ # 文件大小在 10M 以下的文件不进行同步 rsync -av --min-size=10M /var /mnt/ # 复制符号链接的原始文件 rsync -avL /bin /mnt # 对旧的文件进行备份, 当文件同步时接收端会重命名已存在的文件, 在和源文件同一个目录中生成 filename~ 的备份文件 rsync -aP --backup /etc /mnt/ # 将备份的文件放入 /opt/ 中, 指定了 --backup-dir 选项之后, 在备份目录将不会对文件生成后缀 rsync -aP --backup --backup-dir=/opt/ /etc /mnt/ # 对备份文件生成自定义后缀 rsync -aP --backup --backup-dir=/opt/ --suffix=".$(date +'%Y-%m-%d_%H:%M:%S')" /etc /mnt/
远程同步环境配置
# 安装 rsync 命令(客户端和服务器端都需要安装) yum -y install rsync # 关闭 firewalld 和 selinux systemctl disbale firewalld systemctl stop firewalld setenforce 0
基于 SSH 的远程同步
# 使用 ssh 方式同步, 如果配置了秘钥登录则 rsync 直接将数据拷贝到目标主机, 如果没有设置秘钥登录, rsync 会询问用户密码 rsync /etc root@192.168.1.101:/tmp/ # 指定 ssh 的参数 rsync -aP /etc -e 'ssh -p 22' root@192.168.1.101:/tmp/ # 第一次 ssh 连接时, 直接将主机信息加入到 known_hosts 文件 rsync -aP /etc -e 'ssh -o StrictHostKeyChecking=no' root@192.168.1.101:/tmp/
基于 daemon 的远程同步
rsync daemon 能够接收客户端的推送和下载请求
客户端可以将修改过的内容推送到 rsync daemon 以供其他的客户端进行更新
使用 rsync --daemon 启动 rsync 的 daemon 模式, rsync daemon 默认会读取 /etc/rsyncd.conf 作为其配置文件
centos 7 rsync 的默认配置
cat /etc/rsyncd.conf # /etc/rsyncd: configuration file for rsync daemon mode # See rsyncd.conf man page for more options. # configuration example: # uid = nobody # gid = nobody # use chroot = yes # max connections = 4 # pid file = /var/run/rsyncd.pid # exclude = lost+found/ # transfer logging = yes # timeout = 900 # ignore nonreadable = yes # dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2 # [ftp] # path = /home/ftp # comment = ftp export area
编写 /etc/rsyncd.conf
################################## 定义全局配置 ################################## # 监听 socket 地址 port = 873 address = 0.0.0.0 # 运行 rsync daemon 的用户和用户组 uid = nobody gid = nobody # 是否限制在指定目录 use chroot = yes # 客户端是否只读 # 在 centos 6 中该参数的值为 yes 或者 no # read only = false # 拒绝和运行访问的主机 hosts deny = * hosts allow = 192.168.1.0/24 # 最大连接数 max connections = 50 # 连接超时时间 timeout = 300 # 是否列出所有模块 list = true # 认证用户 auth users = nobody # 认证文件, 格式为: username:password , 认证文件的权限必须为 600 secrets file = /etc/rsyncd/rsyncd.secrets # 客户端连接过来显示的消息 motd file = /etc/rsyncd/rsyncd.motd # 锁文件 lock file = /var/run/rsync.lock # 日志文件和 pid 文件 log file = /var/log/rsyncd.log pid file = /var/run/rsyncd.pid # 对以下文件类型不进行压缩 dont compress = *.7z *.ace *.avi *.bz2 *.deb *.gpg *.gz *.iso *.jpeg *.jpg *.lz *.lzma *.lzo *.mov *.ogg *.png *.rar *.rpm *.rzip *.tbz *.tgz *.tlz *.txz *.xz *.zip ################################## 定义模块配置, 模块配置可以存在多个, 模块配置可以覆盖全局配置(有的全局配置不能被覆盖, 比如: address 和 port) ################################## # 模块 ID, 全局唯一 [htdocs] # 模块路径, 该参数必须指定 path = /usr/local/httpd/htdocs # 忽略一些 IO 错误信息 ignore errors # 是否只读(不能上传) read only = false # 是否只写(不能下载) write only = false # 排除 test 目录 exclude = test # 描述信息, 客户端使用 --list-only 查看 comment = 'web page file'
测试和启动:
mkdir -p /usr/local/httpd/htdocs # 创建几个测试目录 mkdir /usr/local/httpd/htdocs/{html,php,jpg,test} # 创建测试文件 echo '<h1>Hello Rsync</h1>' > /usr/local/httpd/htdocs/html/index.html echo '<?php echo "Hello Rsync"?>' > /usr/local/httpd/htdocs/php/index.php echo 'test' > /usr/local/httpd/htdocs/test/test.txt # 更改 rsync 模块目录权限 chown -R nobody:nobody /usr/local/httpd/htdocs # 创建用户认证文件 mkdir /etc/rsyncd/ echo "nobody:123" >> /etc/rsyncd/rsyncd.secrets chmod 600 /etc/rsyncd/rsyncd.secrets # 设置客户端连接过来显示的消息 echo "Hello Rsync" > /etc/rsyncd/rsyncd.motd # 启动 rsync daemon (centos 7 使用 systemd 启动, centos 6 使用 rsync --daemon 启动) systemctl start rsyncd
客户端操作
# rsync daemon 和客户端之间的通信和传输使用的是 ssh 协议 # 请求列出服务器端的所有模块信息(服务器端会要求输入密码), 端口默认为 873, 所有可以省略 rsync --list-only --port 873 nobody@192.168.1.100:: # 创建客户端认证文件 echo "123" > /tmp/rsync_secrets chmod 600 /tmp/rsync_secrets # 查看 htdocs 模块的详细信息, 使用 --password-file 指定认证文件, rsync 认证是会自动读取该文件的内容作为认证密码 rsync --list-only nobody@192.168.1.100::htdocs --password-file=/tmp/rsync_secrets # 将服务器端的 htdocs 模块的内容下载到 /mnt/ 目录, test 目录不会被下载 rsync -aP nobody@192.168.1.100::htdocs --password-file=/tmp/rsync_secrets /mnt/ # 客户端推送数据到服务器端(使用方法和 scp 类似) rsync -aP /tmp/ nobody@192.168.1.100::htdocs --password-file=/tmp/rsync_secrets
rsync + sersync 实现实时同步
rsync daemon 实现了一个客户端的更新, 其他的客户端也能获取的功能, 但是其他客户端什么时候去向服务器获取最新的内容那 ?
写一个计划任务每一分钟询问一次, 在文件数量少的情况下还可行, 但是如果文件数量比较多那么 rsync 每一次去扫描都需要大量的时间和系统资源, 在文件数量大的情况下得不偿失。
这时我们可以通过监听目录的文件状态来获取那些文件发送了改变, 将这些发生了改变的文件推送到所有的客户端。在 Linux 中实现这个功能的是 Linux kernel 的一个特性叫做 Inotify
sersync:
Inotify 是 Linux kernel 2.6.13 以上提供的特性, 它监控文件系统操作, 比如读取、写入和创建
sersync 是基于 inotify 开发的, 可以记录下被监听目录中发生变化的(包括增加、删除、修改)具体某一个文件或者某一个目录的名字
使用 rsync 同步的时, 只同步发生变化的文件或者目录, 因此效率更高。类似功能的还有 inotify-tools
sersync 的优点:
1、sersync 采用多线程进行同步(默认开启 10 个线程), 能够同时处理多个 Inotify 事件
2、sersync 异常处理机制, 通过失败队列自动对之前发生异常的文件进行重新同步操作, 如果依旧失败, 每 10 个小时会对同步失败的文件再次进行同步操作, 直到文件同步为止
3、sersync 自带 crond 功能, 无需借助系统的 crond
实验环境:
实验需求: 一台机器的文件发生变化将发生变化的文件推送到所有的 rsync daemon 上 IP 地址 角色 192.168.1.99 rsync daemon 192.168.1.100 rsync daemon 192.168.1.101 rsync client, sersync 所有的 rsync daemon 配置如上
安装 sersync(192.168.1.101):
# sersync 托管在 google code 上, 在国内需要科学上网才能下载, 但是国内有人将 sersync 放在 GitHub 上了(可能不是最新的), 测试时可以从 GitHub 下载 # sersync 最新的下载地址 https://code.google.com/archive/p/sersync/downloads wget https://raw.githubusercontent.com/wsgzao/sersync/master/sersync2.5.4_64bit_binary_stable_final.tar.gz tar xvf sersync2.5.4_64bit_binary_stable_final.tar.gz cd /root/GNU-Linux-x86
编写 sersync 配置文件:
<?xml version="1.0" encoding="ISO-8859-1"?> <head version="2.5"> <!--本地socket--> <host hostip="localhost" port="8008"></host> <!--是否启用 debug 模式--> <debug start="false"/> <!--是否启用xfs文件系统--> <fileSystem xfs="false"/> <!--同步时忽略推送的文件(正则表达式), 默认关闭 --> <filter start="false"> <exclude expression="(.*).svn"></exclude> <exclude expression="(.*).gz"></exclude> <exclude expression="^info/*"></exclude> <exclude expression="^static/*"></exclude> </filter> <!--设置 Inotify 监听的事件类型--> <inotify> <delete start="true"/> <createFolder start="true"/> <createFile start="false"/> <closeWrite start="true"/> <moveFrom start="true"/> <moveTo start="true"/> <attrib start="false"/> <modify start="false"/> </inotify> <sersync> <!-- watch: Inotify 事件监听的目录 --> <localpath watch="/backup"> <!-- ip: rsync daemon 地址, name: 客户端需要同步的 rsync 模块--> <remote ip="192.168.1.99" name="htdocs"/> <remote ip="192.168.1.100" name="htdocs"/> </localpath> <rsync> <!--rsync 命令参数--> <commonParams params="-artuz"/> <!--start: true 启用密码文件认证 users: rsync 认证用户 passwordfile: 密码认证文件--> <auth start="true" users="nobody" passwordfile="/etc/rsyncd_auth.pass"/> <!--port: rsync 监听的端口--> <userDefinedPort start="false" port="874"/> <!-- 连接超时时间 --> <timeout start="false" time="300"/> <ssh start="false"/> </rsync> <!-- sersync 传输失败日志脚本路径, 每隔 60m 会重新执行该脚本, 执行完毕会自动清空 --> <failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/> <!--sersync 计划任务, 默认关闭--> <crontab start="false" schedule="600"> <crontabfilter start="false"> <exclude expression="*.php"></exclude> <exclude expression="info/*"></exclude> </crontabfilter> </crontab> <!--sersync 传输后调用 name 指定的插件脚本, 默认关闭--> <plugin start="false" name="command"/> </sersync> <!-- 插件示例 <plugin name="command"> <param prefix="/bin/sh" suffix="" ignoreError="true"/> <filter start="false"> <include expression="(.*).php"/> <include expression="(.*).sh"/> </filter> </plugin> <plugin name="socket"> <localpath watch="/opt/tongbu"> <deshost ip="192.168.138.20" port="8009"/> </localpath> </plugin> <plugin name="refreshCDN"> <localpath watch="/data0/htdocs/cms.xoyo.com/site/"> <cdninfo domainname="ccms.chinacache.com" port="80" username="xxxx" passwd="xxxx"/> <sendurl base="http://pic.xoyo.com/cms"/> <regexurl regex="false" match="cms.xoyo.com/site([/a-zA-Z0-9]*).xoyo.com/images"/> </localpath> </plugin> --> </head>
启动:
# 设置配置文件权限 chmod 644 confxml.xml # 创建认证文件 echo "123" > /etc/rsyncd_auth.pass chmod 600 /etc/rsyncd_auth.pass # 创建监听目录 mkdir /backup # 启动 ./sersync2 -r -d -o confxml.xml
测试:
192.168.1.101: echo "123" > /backup/123.txt 192.168.1.99 和 192.168.1.100 ls /usr/local/httpd/htdocs/