接手两台 Linux 服务器之间的文件同步时,我一般不会直接敲 rsync 命令,而是先想清楚两个问题:这两台机器是单向备份,还是两边都会改文件?如果是前者,rsync 是最顺手的工具;如果是后者,直接用 rsync 往外推就容易出事。先确认同步方向和数据特点,能省掉后面很多麻烦。
最常见的一种误判,是以为 rsync 会把两台服务器的文件“合并”成一样。实际上 rsync 是单向同步,它只会让目标端变成源端的镜像。如果两台服务器都需要修改同一批文件,直接使用 rsync 单向推送会造成数据互相覆盖。稳妥的做法是先确定一台作为权威节点,只允许单向同步;若必须双向,要引入 inotify 或 lsyncd 等实时触发机制,并在同步前用 --dry-run 对比双方文件列表,确认没有大规模双向差异后再启用自动同步。
先确认现象和数据分布
我会先问自己:当前是首次同步,还是已经在跑但出了异常?如果是首次同步,先看源目录有多大、文件数量有多少、有没有大量小文件。如果是已有同步任务,先看上次同步日志,确认是权限问题、网络中断还是误删。再看两台服务器的文件布局是否一致,比如源端是 /data/www,目标端是否也有同名目录,还是需要映射到别的路径。
这些确认不需要一次做完,但至少要判断出同步粒度。文件数量少,可以整目录直接推;文件数量多,建议分批或者用 --delete 前先做试跑。
容易误判的地方
rsync 的坑大多不在软件本身,而在参数理解上。执行 rsync 时,最基本的命令是 rsync -avz --delete /源目录/ user@目标IP:/目标目录/。注意源目录末尾的斜杠很重要,带斜杠表示同步目录内的内容,不带斜杠则会把目录本身也复制过去。--delete 选项会让目标端删除源端已不存在的文件,如果不想删除目标端多余文件,就不要加这个参数,以免误删。
另一个容易误判的地方是软链接。默认情况下 rsync 不会复制软链接指向的真实文件内容,而是将软链接本身复制过去。如果需要保持链接的原始指向,必须使用 -l 或 --links 参数;若希望把软链接指向的目标文件内容也同步,则需要 -L 参数。同步前先在源端执行 ls -l 检查软链接情况,再决定参数。另外,使用 -a 归档模式会保留权限、时间戳和属主,但跨用户同步时可能因属主不一致导致目标端文件不可访问,此时考虑用 --no-owner 或 --no-group 调整。
建议的处理顺序
我的习惯是:先做一次仅列出变化的试跑,再正式同步;正式同步时保留日志;同步完成后做一次目标端抽查。具体顺序可以这样安排。
- 先确认源端要同步的绝对路径和用户身份,避免用 root 同步出一个权限不一致的目录。
- 先在源端执行 rsync -avz --dry-run --itemize-changes 源目录/ user@目标IP:/目标目录/,看输出是否符合预期。
- 确认没有意外删除或覆盖后,再进入正式同步。若网络不稳定,加上 --partial --bwlimit 参数。
- 同步结束后,到目标端检查几个关键文件的时间戳和大小,再看目标端日志有没有报错。
命令与参数示例
对于一次完整的手动同步,我通常这样写:
rsync -avz --delete --partial --bwlimit=2000 --log-file=/var/log/rsync-sync.log /data/www/ backup@服务器IP:/backup/www/
在跨机房或公网同步大文件时,建议加上 --bwlimit=2000 限制带宽为 2MB/s,避免占满出口带宽影响线上业务。同时配合 --partial 保留部分传输的文件,这样断网重连后再次执行相同命令,rsync 会基于已传输的部分继续同步,而不是从头开始。若文件数量极多,可先压缩再传,但要注意 --compress 在局域网内反而增加 CPU 开销。
当同步目录中包含日志、临时文件或缓存时,应使用 --exclude 排除,例如 --exclude='*.log' --exclude='cache/'。注意 exclude 模式的匹配路径是相对源目录的,如果写成 --exclude='/logs' 可能无法匹配。建议先在源端用 rsync --list-only --exclude 看看实际会同步哪些文件,确认排除规则生效后再正式执行。对于需要同时排除多个模式的场景,可以把模式写入单独文件,用 --exclude-from=规则文件 引用。
验证方法
在生产环境执行 rsync 之前,强烈建议先运行 rsync -avz --dry-run --itemize-changes 源目录/ 目标目录/ 来预览将要发生的操作。输出中会逐项列出新增、删除、更新,以及属性变化。例如 '>f+++++++++' 表示新增文件,'cL+++++++++' 表示软链接变化。确认输出里没有意外的删除或覆盖后,再去除 --dry-run 正式执行。若机器上已有历史同步记录,先用 --stats 查看统计信息,便于对比每次同步的传输量。
正式同步完成后,我还会在目标端跑一次 find 检查文件数量,或者用 du 对比目录总大小。如果差异在可接受范围内,说明同步是完整的。若发现数量对不上,优先看日志里有没有 skipped 或 permission denied。
回滚和风险
rsync 没有内置回滚机制,所以要在同步前把风险边界想清楚。如果目标端已经有数据,第一次同步时不要加 --delete,先跑一次纯推送,确认目标端数据没有覆盖到错误位置。如果目标端需要回滚,只能靠文件系统快照或备份,否则无法恢复到同步前状态。建议在正式任务前对目标目录做一次 tar 或快照,尤其是第一次接管同步任务的时候。
后续维护上,如果同步频率高,可以写成 shell 脚本配合 crontab 执行,但脚本里要保留日志轮转和失败重试;如果同步的数据变化频繁且双向都有修改,还是要回到开头那个判断,先解决权威节点问题,再谈自动化。
最后补一句:rsync 适合稳定路径、稳定网络环境的定时或手动同步。如果服务器数量超过三台,或者同步路径经常变化,建议用专门的文件分发工具,而不是把 rsync 脚本越写越复杂。