【Linux从入门到精通】第38篇:定时数据同步神器——rsync与inotify
目录一、引言rsync凭什么成为同步标配二、rsync的增量同步原理2.1 rsync如何判断“哪些部分变了”2.2 由原理决定的适用场景三、rsync核心参数与实战3.1 常用参数详解3.2 源路径末尾斜杠的重要区别3.3 用-ndry-run先测试3.4 实战网站文件同步脚本四、配合crontab定时执行五、inotifywait从定时到实时5.1 为什么还需要inotify5.2 安装inotify-tools5.3 基本使用5.4 实时同步脚本5.5 生产化改造syncthing模式六、rsync vs scp vs NFS七、本篇小结动手练习八、下篇预告一、引言rsync凭什么成为同步标配在日常运维中有一个操作几乎每天都会遇到把A服务器上的文件同步到B服务器。可以用scpbashscp -r /var/www/html/ backup-server:/backup/scp的问题很明显不管文件有没有变化每次都全量拷贝。对于几百MB的网站目录这效率太低了。rsync的独特优势在于增量同步——它只传输变化了的部分。一个100MB的日志文件如果今天只追加了10行rsync只传这几KB的数据而不是重新拷贝整个文件。这个特性让rsync成为数据同步的事实标准几乎所有备份工具Time Machine、Duplicity、rsnapshot底层都调用了它。二、rsync的增量同步原理2.1 rsync如何判断“哪些部分变了”rsync的核心算法分为三步第一步生成校验和列表rsync把目标端已存在的文件按固定大小的块切割对每一块计算两个校验和一个快速的弱校验rolling checksum滚动哈希和一个精确的强校验如MD5或SHA256。第二步匹配对于源文件rsync逐字节滑动算出每个位置的弱校验和。当发现某个位置的弱校验和与目标端某块匹配时再用强校验确认。如果两个校验和都匹配说明这个块在目标端已经存在不需要传输。第三步只传不匹配的数据不匹配的部分源端直接发送给目标端。目标端用接收到的数据块加上已有的匹配块拼接出完整的文件。一个直观的类比假设你修改了某段文字中的一句话对方手里有旧版本。你不用把整段重新打一遍只需要说“把第3句话改成xxxxx其他保持不变。”——对方的操作就是根据旧稿和你的修改指令组合出新稿。这就是rsync的智慧用少量计算换取大量传输的节省。2.2 由原理决定的适用场景理解了这个机制就能判断rsync擅长什么、不擅长什么非常适合文件很大但改动很小日志追加、数据库增量备份、大量文件中有少数变化网站代码同步不太适合大量全新文件校验和匹配率低和scp差不多、极小的文件校验和计算的开销相对传输而言不可忽略三、rsync核心参数与实战3.1 常用参数详解bashrsync -avz /source/path/ userbackup-server:/dest/path/核心三参数 -avz参数全称作用-aarchive归档模式这是一个组合参数等于-rlptgoD。保留符号链接、权限、时间戳、属主、属组等所有元信息并递归同步子目录-vverbose显示详细的同步过程哪些文件被传输了-zcompress传输时压缩数据。局域网内rsync不建议加-z压缩/解压反而耗CPU跨网络传输时开启有明显加速效果其他常用参数参数作用使用场景-P等于--partial --progress断点续传 显示进度条大文件传输必备--delete目标端删除源端没有的文件镜像同步目标端会变成源端的精确副本--exclude排除特定文件/目录--exclude*.log不同步日志--bwlimit限制传输带宽KB/s--bwlimit1000限制1MB/s避免吃满带宽-ndry-run模拟执行不实际传输测试命令无误后再正式执行-uupdate只同步更新的文件避免覆盖目标端更新的文件3.2 源路径末尾斜杠的重要区别这是rsync最容易踩的坑bash# 有斜杠复制目录的内容到目标 rsync -av /source/ /dest/ # 结果/dest/ 下直接是 file1, file2... # 无斜杠复制目录本身到目标 rsync -av /source /dest/ # 结果/dest/source/ 下是 file1, file2...记忆技巧有斜杠 打开这个目录把里面的东西倒出来无斜杠 把这个目录连包装一起搬过去。3.3 用-ndry-run先测试在生产环境中永远先模拟运行bash# 先模拟确认要同步的文件列表符合预期 rsync -avz --dry-run /source/ backup:/dest/ # 确认无误后去掉 -n 正式执行 rsync -avz /source/ backup:/dest/3.4 实战网站文件同步脚本bash#!/bin/bash # web_sync.sh - 将网站文件同步到备份服务器 SOURCE/var/www/html/ DESTbackup-server:/backup/www/ LOG/var/log/rsync_www.log echo $(date %Y-%m-%d %H:%M:%S) 开始同步 $LOG rsync -avz \ --delete \ --exclude*.log \ --exclude.git/ \ --excludenode_modules/ \ $SOURCE $DEST $LOG 21 if [ $? -eq 0 ]; then echo 同步成功 $LOG else echo 同步失败 $LOG fi参数说明--delete备份服务器上删除源端已移除的文件确保备份是源端的精确镜像--exclude不同步日志文件和依赖包目录减负增效四、配合crontab定时执行将rsync与第16篇的crontab结合实现定时备份bash# 编辑crontab crontab -etext# 每天凌晨3点同步网站文件 0 3 * * * /opt/scripts/web_sync.sh # 每小时同步一次日志归档 0 * * * * rsync -avz /var/log/app/ backup-server:/archive/logs/ --exclude*.gz五、inotifywait从定时到实时5.1 为什么还需要inotifycrontab的最小粒度是1分钟而且它不管文件变没变到点就执行。对于某些场景——比如两台Web服务器的代码同步开发更新了代码你希望立刻同步到生产服务器——分钟级延迟太慢了。inotify是Linux内核提供的事件驱动机制能实时监控文件系统的变化创建、修改、删除、移动。inotifywait是它的命令行工具。5.2 安装inotify-toolsbashsudo apt install inotify-tools -y # Ubuntu/Debian sudo dnf install inotify-tools -y # CentOS/RHEL5.3 基本使用bash# 监控一个目录的所有文件变化 inotifywait -m /path/to/watch选项说明-m持续监控不加-m的话检测到第一个事件后就退出-r递归监控子目录-e指定监控哪些事件-q安静模式不输出多余的启动信息常用事件事件含义modify文件内容被修改create文件或目录被创建delete文件或目录被删除move文件或目录被移动/重命名attrib权限、时间戳等属性变化5.4 实时同步脚本bash#!/bin/bash # realtime_sync.sh - 监控目录变化并实时同步 SOURCE/var/www/html/ DESTbackup-server:/var/www/html/ # 持续监控文件变化 inotifywait -m -r -e modify,create,delete,move --format %w%f $SOURCE | while read FILE; do echo [$(date)] 检测到变化: $FILE rsync -avz $SOURCE $DEST done工作流程inotifywait -m持续监控源目录一旦检测到文件变化修改、创建、删除、移动立刻输出变化的文件路径while read FILE循环读取每一行输出触发rsync将整个目录增量同步到目标服务器性能提醒如果文件变化极频繁如每秒几百次写入inotify会频繁触发rsync可能导致rsync实例堆积。在日志目录等高频写入场景下建议用--exclude过滤或者在循环内部加一个简单的间隔控制如两次同步至少间隔3秒。5.5 生产化改造syncthing模式上述简洁版脚本适合轻量使用。对于生产环境可以加入以下改进批处理而非逐文件触发不在一有变化就同步而是等3秒内没有新变化后再触发bash#!/bin/bash SOURCE/var/www/html/ DESTbackup-server:/var/www/html/ inotifywait -m -r -e modify,create,delete,move --format %w%f $SOURCE | while read FILE; do echo [$(date)] 检测到变化: $FILE # 等待3秒如果3秒内又有变化sleep会被后续的读取重置 timeout 3 cat /dev/null 21 || true rsync -avz --delete $SOURCE $DEST done这个脚本利用了管道阻塞的特性read会等待下一次inotify事件输出如果3秒内有新事件cat会被迫提前退出这不是完美的去抖动方案但作为Shell脚本的轻量实现已经足够实用。更完善的去抖动策略避免高频同步、错误重试、日志轮转等功能可以参考成熟的同步工具如lsyncd它正是inotify rsync的封装已经内置了这些机制。六、rsync vs scp vs NFS维度rsyncscpNFS增量同步✅ 仅传输变化部分❌ 全量拷贝✅ 文件系统级别传输加密✅ 走SSH✅ 走SSH❌ 需额外配置Kerberos或VPN实时性⚠️ 依赖触发/定时❌ 手动执行✅ 透明实时断点续传✅--partial❌ 失败后需重新开始✅ 文件系统级别适用场景备份、镜像、大文件一次性传输多服务器实时共享七、本篇小结rsync核心机制强弱校验和 块匹配 只传输变化部分-avz归档模式 显示详情 传输压缩--delete精确镜像小心使用-n--dry-run先模拟再执行万能安全网从定时到实时crontab rsync 定时备份最简单inotifywait rsync 实时同步变化即触发lsyncd 生产级封装去抖动 错误处理动手练习bash# 1. 体验rsync增量同步的基本用法 mkdir -p /tmp/source /tmp/dest echo file1 /tmp/source/file1.txt echo file2 /tmp/source/file2.txt rsync -av /tmp/source/ /tmp/dest/ ls /tmp/dest/ # 确认文件已同步 # 2. 验证增量特性修改一个文件后再同步观察传输内容 echo appended /tmp/source/file1.txt rsync -av /tmp/source/ /tmp/dest/ # 只传输变化部分 # 3. 体验inotifywait inotifywait -m /tmp/source # 在另一个终端操作 /tmp/source 目录观察输出 echo test /tmp/source/newfile.txt # 回到第一个终端看变化通知 fg # 把后台的inotifywait调回前台CtrlC结束 # 测试后自行清理rm -rf /tmp/source /tmp/dest八、下篇预告代码写完了但团队协作中如何管理代码版本、避免“最终版_v3_改2_真的不改了.py”这种混乱Git是程序员每天都要用的版本控制工具。下一篇我们将搭建私有Git服务器——使用Gitea一个轻量级的GitHub替代品让团队拥有自己的代码托管平台。你将学会Git的基本工作流、搭建Gitea服务、配置SSH方式推送代码。延伸思考rsync配合--link-dest参数可以实现增量快照备份——每次备份都创建一个完整的“镜像”但未变化的文件是通过硬链接指向上一次备份的实际只占用极少额外空间。macOS的Time Machine和Linux的rsnapshot都基于这个原理。如果你的备份需求增长到需要保留多个历史版本、但磁盘空间有限不妨研究一下这个参数。