Linux文件同步利器rsync:从原理到实战的完整指南

发布时间:2026/10/19 4:07:30
Linux文件同步利器rsync:从原理到实战的完整指南
提到 Linux 下的文件同步工具rsync 是绕不开的一个名字。工作这些年从最早的本地备份脚本到后来给服务器搭建异地容灾再到给多台机器做配置分发几乎离不开它。很多刚接触 Linux 的朋友会觉得 rsync 命令参数又多又长记不住、用不明白折腾半天数据还同步错了。其实它的核心逻辑非常朴素先对比、再传输只动有差异的部分所以效率高、可控性强。这篇文章不打算做成 man 手册的翻译稿就挑实际工作中最高频的场景从原理到实操再到排错把 rsync 怎么用透、怎么用好讲清楚。无论你是刚上手 Linux 的运维新人还是已经被业务备份需求折磨过一段时间的开发者这篇文章都能给你一套直接能落地的方案。1. 为什么说 rsync 是文件同步场景下的首选工具1.1 增量同步到底省在哪儿rsync 最核心的竞争力就是增量传输。打个比方你有一个 50GB 的源码压缩包今天改了里面一个 1MB 的配置文件如果用最普通的scp或者cp就得把整整 50GB 重新拖一遍时间、带宽、磁盘 IO 全搭进去。而 rsync 用了两段式校验算法目标端先把文件切成固定大小的数据块默认约 700 字节到 1MB 之间按文件大小自适应为每块生成强弱两个校验和源端拿到这些校验和列表对自己这边的文件逐块做比对两边一致的块直接跳过只有真正变化的块才被传输。这意味着哪怕只改了一个字节同步的数据量也只会是“这个字节所在的块”这么大。实际跑过数据迁移的朋友肯定有体会首次全量同步之后后续的增量同步速度肉眼可见地快一两分钟跑完几十 GB 的目录是常态。这个特性放在生产环境里就是实打实的效率备份窗口从几小时压缩到几分钟带宽占用也低不少。1.2 对比 scp、cp、NFS 共享的优势我把几个常见的文件传输方案放在一起对比过rsync 的优势非常清楚工具/方案增量传输断点续传元数据保留安全传输典型不足cp不支持不支持部分保留仅本机本地复制专用scp不支持不支持有限基于 SSH全量传输大文件太慢rsync支持支持--partial完整保留基于 SSH参数多需要学习成本NFS 直接挂载无传输过程无传输概念依赖客户端内网无强加密安全隔离弱不适合跨公网scp在跨机器传文件时确实简单一条命令完事但它的缺点很致命不做增量、不做校验网络断了重头再来。NFS 共享适合内网读高频场景但把目录直接挂给不可信网络安全风险大而且同步策略要自己另写脚本处理。rsync 在数据量不大时看不出差距一旦涉及几十 GB、几百 GB 甚至上 TB 的数据集差距就是天壤之别。有个容易被忽略的点rsync 同步时默认会把时间戳、权限、属主、属组、软链接、设备文件等元数据一并处理好这点对备份场景极其重要。用scp复制出来的文件往往时间戳是“复制那一刻”恢复归档时时间线直接错乱很影响排障和审计。2. 基础用法与核心参数把命令行拆开看明白2.1 命令形态与源路径结尾斜杠的坑rsync 的基本命令格式很简单rsync [选项] 源路径 目标路径源路径可以指定为本地路径也可以用userhost:/path的形式走远程。看到这里肯定会有朋友觉得这跟scp没啥区别但有一个隐藏坑是新手最容易踩的源路径末尾的斜杠有没有语义完全不一样。# 把 dir1 目录本身复制到 dir2 下面 rsync -av /data/dir1 /backup/ # 把 dir1 里面的所有内容复制到 dir2 里面 rsync -av /data/dir1/ /backup/第一条命令执行后目标端会出现/backup/dir1第二条命令执行后目标端只有/backup底下的内容不会多出一个dir1外层目录。我刚开始接触 rsync 的时候在这上面吃过亏本意是想把目录整体归档结果因为多打了一个斜杠目标目录直接“散开”了恢复时才发现层级全乱了。反向记忆一下斜杠代表内容不带斜杠代表整个目录对象。这个规则同样适用于远程路径。2.2 高频参数逐个拆解先看一条最常用的组合命令rsync -avzP --delete /data/www/ root192.168.1.10:/data/www/这一条里已经包含了绝大多数场景需要用到的核心选项。我逐个解释一下-a归档模式。相当于-rlptgoD的一连串参数集合表示递归复制、保留软链接、保留权限、保留时间戳、保留属主属组、保留设备文件。备份场景直接用-a最省心。-vverbose输出同步过程的详细信息比如哪些文件被跳过、哪些被更新了。-z传输时压缩。文本、日志、代码这类可压缩性高的文件收益明显已经压缩过的视频、图片文件开启后意义不大反而增加 CPU 开销。-P相当于--partial --progress的组合一边保留部分传输的文件断点续传的基础一边显示传输进度。传大文件时这个选项几乎是必备的。--delete让目标端保持与源端一致目标端存在但源端没有的文件会被删除。这是一个高风险参数使用前一定要想清楚绝不能用在源路径写错或挂载异常的情况下。再补充几个实践中经常用到的--exclude排除指定文件或目录支持通配符。例如--exclude*.log或--excludecache/。--exclude-from从一个文件里读取排除规则适合排除规则很多的情况。--dry-run试运行只显示会执行的动作不真正做任何修改。配合-v使用可以提前把结果列出来。-e指定远程 shell。最典型的是指定 SSH 端口rsync -av -e ssh -p 2222。--bwlimit限制传输带宽单位是 KB/s。比如--bwlimit2048表示限速 2MB/s很适合在业务高峰期做备份时使用能保护生产链路的带宽。--timeout设置 IO 超时时间避免网络异常时 rsync 进程一直挂起。--delete-excluded连排除的文件也删除这通常不是想要的别乱用。2.3 第一个完整脚本本地目录备份刚入门的话先写一个最基础的本地备份脚本把-avP玩熟再逐步叠加远程和排错逻辑。#!/bin/bash # 本地目录备份脚本 # 把 /var/www 备份到 /backup/www保留文件权限和时间戳 SRC_DIR/var/www DST_DIR/backup/www # 先做一次试运行确认即将执行的操作 rsync -av --dry-run $SRC_DIR/ $DST_DIR/ # 确认无误后正式同步 rsync -av $SRC_DIR/ $DST_DIR/这个脚本虽然简单但已经把rsync的核心思想——先检查再执行——体现出来了。实际工作中我习惯把所有 rsync 命令都先用--dry-run跑一遍等确认输出符合预期了再摘掉这个参数。3. 实战场景拆解服务器备份、网站部署与定时同步3.1 场景一远程服务器的数据备份与容灾假设你手头有一个跑着业务接口的服务器每天产生一批业务文件需要同步到另一台备份服务器。我推荐的做法是备份机主动拉取或者生产机主动推送二选一即可关键是定好策略。我这里用生产机主动推送举例rsync -avzP --delete --bwlimit5120 \ --excludecache/ \ --excludesession/ \ /data/business/ backup-userbackup-server:/data/business-backup/解释一下思路-a保留完整元数据-z压缩传输节省带宽-P显示进度也支持断点续传--delete让备份端跟随源端目录状态排除掉 cache 和 session 这类每次内容都变、但备份价值不大的目录--bwlimit5120把带宽限制在 5MB/s 左右不和线上业务抢网络。提醒一点--delete在生产机往备份机推送这种场景里好用但方向反过来就要特别小心。如果备份机挂载的备份盘出现了问题比如 I/O 错误或者文件系统变成了只读状态rsync 会认为远端文件消失然后执行删除。更稳妥的做法是周期性备份采用--link-dest做快照式增量而不是裸用--delete这个方案在下一节会详细讲。3.2 场景二代码构建后自动部署到多台服务器部署场景中rsync 的价值在于“只传变化的部分”。现在很多团队的发布流程是开发提交代码到仓库CI 构建产物到指定目录再由构建机把产物同步到生产或者测试服务器。比如我经手过的一个模拟项目构建产物是一个约 1.2GB 的打包目录里面含大量静态资源文件。每次构建其实只变几个 JS 和图片如果用scp全量推过去一次部署要几分钟用 rsync 增量推送通常十几秒就结束了。# 从构建机把打包产物同步到测试服务器 rsync -avzP --delete \ --exclude.git/ \ --excludenode_modules/ \ --exclude*.map \ ./dist/ deploy-usertest-server:/opt/www/dist/这里的关键词是“部署”部署必须保证目标环境干净所以--delete在这里是合理且必要的它能清除掉历史构建遗留的旧文件。构建好之后可以通过 SSH 远程拉动服务端进程来做服务重启比如配合 systemd 的 restart 命令。不过这一步就属于另一个话题了本文不展开。3.3 场景三用 cron 实现定时增量同步脚本写好后配一条 crontab 就能实现自动化。这里给出一套我常用的定时规则# 每天凌晨 2:30 执行一次备份 30 2 * * * /usr/bin/rsync -avzP --delete --exclude*.tmp /data/nginx/ /backup/nginx/ /var/log/rsync-backup.log 21把输出重定向到日志是很有必要的习惯。rsync 若不加-q安静模式在-v下会产生大量输出日志会持续增长建议配合logrotate做日志轮转或者在脚本里自行清理超期日志。我最开始做定时任务时习惯把 rsync 的日志输出到/dev/null省得磁盘被打满。直到有一次同步失败了整整半个月才发现那个教训相当深刻。从此之后所有 rsync 相关任务都会至少保留一个月日志。建议每周对备份做一次恢复测试。你可以临时把备份目录挂载为 web 服务的 docroot看页面能不能正常工作。备份不测试等于白备份真的到了恢复的时候才发现备份数据有问题心是拔凉拔凉的这种事隔一阵就能在网上刷到同行的血泪帖也可能落到自己头上。4. 进阶玩法快照式增量备份与断点续传4.1 用 --link-dest 做出“伪快照”效果--link-dest是 rsync 里最有价值、但很多人不知道的高级参数。它的原理很简单目标目录里如果这次同步的文件内容和上一次同步时一致那么不重新写入文件数据而是创建硬链接指向上一次备份里的同名文件。这样每次备份都像一次完整备份每个备份目录都是完整的但实际上只有变化的数据占用了额外空间。因为硬链接本身几乎不占磁盘空间所以这种方法既拥有全量备份的完整性又接近增量备份的空间效率。我搭建过一个每周全量、每日增量的备份体系周一做一次全量备份周二到周日每天用--link-dest指向上一天备份的目录周而复始。#!/bin/bash # 每日快照式增量备份脚本按日期生成备份目录 BACKUP_BASE/backup/www SNAPSHOT_DATE$(date %Y-%m-%d) PREV_SNAPSHOT$(ls -1 $BACKUP_BASE | tail -n 1) # 如果存在上一次备份目录则作为 --link-dest 参数传入 if [ -n $PREV_SNAPSHOT ] [ -d $BACKUP_BASE/$PREV_SNAPSHOT ]; then LINK_DEST--link-dest$BACKUP_BASE/$PREV_SNAPSHOT else LINK_DEST fi mkdir -p $BACKUP_BASE/$SNAPSHOT_DATE rsync -avzP --delete \ $LINK_DEST \ /data/www/ $BACKUP_BASE/$SNAPSHOT_DATE/执行完上面这段假设/data/www只有 20GB而每天变动量只有几百 MB连续备份 30 天总空间占用可能也就 20GB 出头变动部分另算而不是 30 × 20GB 的庞大容量。恢复数据时只需从任意一个备份目录取出文件即可对“要找昨天的文件”这种需求非常友好不需要拼接增量直接按日期进目录就能拿。--link-dest有一个前提条件要特别注意源目录和目标备份目录必须在同一个文件系统内因为硬链接不能跨文件系统。我的备份服务器上就用独立分区挂载到/backup所以这个限制没影响到我如果你把备份目录放在网络存储或另一块盘上就不能靠硬链接省空间了。4.2 断点续传与传输中断场景大文件传输是 rsync 的另一个看家本领。像数据库逻辑备份文件几个 GB 的.sql.gz传的时候万一网络断了用--partial可以让已传部分保留下来下一次同步时依然从断点继续不需要完全重来。rsync -avP --append-verify \ /var/backup/db.sql.gz backup-userbackup-server:/data/backup/db.sql.gz这里用--append-verify而不是只写--partial的原因是它会在续传后对文件追加的数据部分做一次校验确保断点之后的数据没丢失。注意--append系列参数只适合文件内容只增加不变化的场景比如日志追加、数据库导出文件追加不适合源端文件会被重写覆盖的场景。如果源文件在两次同步间隔中内容发生了非追加式修改直接--append会把文件搞坏。对于经常中断又改来改去的文件更稳妥的方案是源端先生成一份临时副本副本写完后再次调用同步命令由 rsync 的--checksum选项做全量校验。4.3 通过跳板机访问目标服务器有的生产环境限制了直接暴露端口目标服务器只有跳板机可以访问。rsync 同样能处理只要通过-e参数把跳板机的连接命令传给 SSH 就行了rsync -avzP -e ssh -o ProxyCommandssh -p 22 jump-user10.0.0.100 -W %h:%p \ /data/dist/ deploy-user192.168.1.50:/opt/www/这个命令的意思是本机先连到跳板机再由跳板机把转发连接到目标服务器。-W %h:%p是 OpenSSH 的 ProxyJump 参数让 SSH 替代 netcat 完成转发。这种场景下 rsync 的唯一要求就是“最终两端能用 SSH 直连通”剩下的都不用关心。5. 常见问题与排查技巧5.1 权限与属主问题导致的同步失败用 rsync 同步文件时-a会把属主和属组也带过去但只有 root 或具有相应权限的用户才能修改属主属组。最常见的报错类似rsync: chown /data/xxx failed: Operation not permitted (1)看到这类报错先不用慌这通常不致命因为文件已经传过去了只是权限设置在目标端不生效。如果是备份目标机上缺少对应账号可以在同步时用--chownuser:group强行指定所有者配合--no-o --no-g关闭原属主属组传递。比如拿www-data账号去同步备份就按下面的方式操作rsync -av --no-o --no-g --chownwww-data:www-data \ /data/www/ deploy-userbackup-server:/backup/www/如果是本机到本机的同步直接用 root 权限操作即可从根源避免属主权限问题。如果有一边用了非 root 账号就要提前检查两边对账号体系的理解是否一致否则同步一会儿就冒出一堆属主警告很烦人。5.2 排除规则失效路径写法有讲究经常有人跟我抱怨--exclude*.log写上去了但同步的时候日志还是过来了。大部分情况下是因为排除规则写的是通配符但实际路径不匹配。--exclude匹配的是 rsync 内部传输时的相对路径不是源路径的绝对路径。比如/data/www/logs/error.log这个文件在 rsync 的视角里叫logs/error.log而*.log只匹配文件名只有在相对路径下一层就匹配的才生效。想要匹配任意目录下的error.log应该写--exclude**/error.log同理排除某个子目录的正确写法是--excludelogs/ # 排除所有叫 logs 的目录 --exclude/logs/ # 只排除相对路径根上的 logs 目录排除规则一旦比较多用--include-from和--exclude-from维护规则文件可读性更高。规则文件中每行一条空的规则文件本身是合法的不会报错。5.3 传输性能突然变慢先检查硬件和 IOrsync 速度慢不一定是命令参数的问题。有一次某网站在夜间做备份同步十几 GB 的数据跑了四个小时还没结束我排查发现源端目录文件数量超过五十万个rsync 光做文件列表扫描就消耗掉了大量时间真正传输数据反而没多久。这种情况下优化思路是用--delete也好不用也好文件数量才是瓶颈建议先把小文件归档打包成一个大文件再同步或者用rsync --files-from按清单同步关键子目录。再一个常见因素是源端磁盘或目标端磁盘的 IO 被其他任务耗尽。rsync对元数据操作频繁高密度小文件场景下 CPU、磁盘随机读写都会拉满。可以用iotop或iostat先确认瓶颈再决定是调整参数还是错峰执行。5.4 如何判断同步结果是否完全一致同步完成不代表数据百分百一致特别是网络传输中偶尔会出现数据损坏。校验一致性的办法很直接用 rsync 的-c选项强制校验文件内容或者干脆再跑一遍 rsync 看输出有没有changed或new。rsync -avc --dry-run /data/www/ /backup/www/-c会跳过基于文件大小和时间戳的快速判断直接对每个文件做全量校验。代价是速度变慢一次几 TB 的同步会明显耗时所以我更常用折中方案先按默认规则同步然后从两端分别生成一份文件名大小修改时间的清单用diff对比一下发现问题再用-c细查。关于日志审计还有一个经验备份机的时区、时钟一定要和生产机保持一致。如果两个机器时钟差几分钟rsync 会小概率误判“时间戳不一致”而多做一次全量传输既浪费时间又让日志审计没法做。最后说点实在的到现在为止我已经把 rsync 的原理、基础用法、实战场景和常见排错思路都过了一遍。我从个人经验角度再补最后一句不要一上来就把-a和一堆选项机械拼接而是先把同步需求想清楚——是镜像目录还是归档备份是推送还是拉取需不需要删除多余文件然后对照参数逐个用上去。第一次跑任何 rsync 命令都强烈建议加--dry-run -v先看一遍影响范围这能帮你避免很多手动操作里的低级失误。如果这篇文章里提到的某个场景正好是你手头正在做的事建议把它当成一个起点先搭一个最小可用的同步方案跑通以后再逐步加入限速、日志、报警等外围逻辑。我自己也就是这样一步一步把 rsync 用熟的它不像某些工具学完就忘而是越往后越能挖掘出更多省力的用法。希望这些实战心得能让你少走几步弯路。