上周帮一个做跨境电商的同行从阿里云迁移到腾讯云,网站目录大概80GB、MySQL数据库12GB。用rsync拖了三个小时快跑完的时候SSH断连,自动重连后rsync重新扫了80GB文件但什么也没同步——因为所有文件mtime和size都匹配,rsync判断"没变化"就跳过了。问题在于SSH断连前最后的800MB文件只传了一半,文件大小看起来对但内容是残缺的,rsync不校验内容只对比大小和时间,这800MB残缺文件就被当成了"已同步"
网站数据同步的本质不是"把文件从A搬到B",而是"搬完之后两边数据一模一样且能用"。rsync默认不校验文件内容只对比大小和修改时间,rclone默认走哈希校验但速度慢三到五倍,MySQL主从复制能实时同步但一旦中断想修复差异比重新搭一遍还麻烦。工具选对方向不搞反,比工具本身是什么重要一百倍。
网站数据同步要拆成两块看:文件同步(网站代码、图片、附件、静态资源)和数据库同步(文章、用户、订单、配置)。两块用的工具、逻辑、翻车点完全不同,混在一起用同一个方案是90%翻车的根源。
一、文件同步:rsync和rclone的边界在哪
两台Linux服务器之间同步网站文件,rsync是首选。它的增量算法只传文件变化的部分——一个100MB的日志文件新增了2KB内容,rsync只传这2KB。但rsync的"增量检测"有个前提:默认对比的是文件大小(size)和修改时间(mtime),不对比文件内容。这就是开头那800MB残缺文件被跳过的原因。
| 对比维度 | rsync | rclone |
|---|---|---|
| 核心用途 | 两台Linux服务器之间同步文件 | 本地↔云存储/云↔云之间同步文件 |
| 增量检测方式 | 默认:mtime + size(快但不可靠) 加 -c 参数:内容校验(慢但准确) | 默认:哈希校验(准确但慢) 可切换为mtime+size(快但不可靠) |
| 支持的后端 | 本地文件系统 + SSH远程 | 40+种:S3/OSS/COS/OneDrive/Google Drive/WebDAV/SFTP等 |
| 传输速度 | 单线程但增量极高效,局域网内跑满带宽 | 支持多线程(--transfers),大文件传云存储比rsync快 |
| SSH断连恢复 | 默认每次新建SSH连接,断连后重新扫全量文件 | 支持断点续传,大文件传输中断后从断点继续 |
| 适合网站同步吗 | ✅ 最佳选择,配合SSH复用+定时cron | ⚠️ 适合备份到云存储,不适合服务器间日常同步 |
二、rsync五个致命翻车点
翻车1:--delete方向搞反,新数据被旧数据覆盖
rsync -avz --delete /旧服务器/ /新服务器/ ——如果源目录是空的或者你搞反了方向,--delete会把目标端所有文件删光。这个参数的字面意思是"让目标目录和源目录完全一致",不是"删除目标端多余的文件"这么温柔。
解法:每次带--delete执行前,先用--dry-run跑一遍看rsync打算删什么,确认无误再去掉--dry-run。
翻车2:SSH断连后半截文件被当完整文件
就是开头说的那个场景。rsync默认不校验文件内容,传输中断后文件大小看起来正确但内容是残缺的,rsync跳过它。
解法:大文件传输加 -c 参数强制内容校验(速度会慢但不会漏);或者传输完成后用md5sum对关键文件做二次校验;最稳的方案是启用SSH连接复用(ControlMaster),大幅降低断连概率。
翻车3:文件权限和属主丢失
默认rsync不保留文件权限、属主和属组。网站同步后WordPress上传目录变成root:root 644,PHP没有写入权限,所有图片上传全部失败。
解法:加 -p(权限)-o(属主)-g(属组)参数。如果是跨服务器同步且两边用户名不同,用 --chown=USER:GROUP 强制修改。
翻车4:排除规则漏了不该排除的东西
用 --exclude='cache/' 排除了缓存目录,但 --exclude 是从源路径的相对路径开始匹配的。如果源路径是 /var/www/,排除规则写 --exclude='var/www/cache/' 匹配不到——因为rsync把 /var/www/ 当作根路径。
解法:--exclude的路径永远以源路径为基准。搞不清就用 --exclude-from=FILE 写到一个文件里,用绝对路径测试通过后再填进去。

翻车5:路径末尾斜杠的"暗语法"
rsync -avz /source/ /dest/ ——末尾有斜杠:同步目录里的内容。
rsync -avz /source /dest/ ——末尾无斜杠:在dest下创建一个source子目录再同步内容。
差一个斜杠,目录结构完全不同。多少人的网站迁移后访问404,最终发现是wwwroot下面多嵌套了一层目录。
解法:统一加斜杠,或者用rsync -avz /source/ user@host:/dest/ 这种明确写法。永远不省略末尾斜杠。
三、数据库同步:不是拿mysqldump导出再导入就完了
数据库同步分两种情况:一次性迁移(搬家、换服务器)和持续同步(主从复制、读写分离)。两种场景用的工具和策略完全不同。
| 场景 | 推荐工具/方案 | 核心操作 | 翻车点 |
|---|---|---|---|
| 一次性迁移 数据库<5GB | mysqldump + mysql | 导出SQL→传输→导入,简单直接 | 导出期间数据库被写入导致数据不一致。加 --single-transaction(InnoDB)或 --lock-tables(MyISAM) |
| 一次性迁移 数据库>5GB | xtrabackup / mydumper | 物理热备份或并行导出,比mysqldump快3-5倍 | xtrabackup要求MySQL版本一致,mydumper导入时注意字符集 |
| 持续实时同步 | MySQL主从复制 | 主库binlog→从库relay log→回放,秒级延迟 | 主从延迟、数据不一致后修复困难、从库宕机恢复需重搭 |
| 持续近实时同步 | Canal + 自定义消费端 | 伪装成MySQL从库解析binlog,推送到MQ或直接写入目标 | 维护成本高,需要专职DBA,小站别碰 |
| 跨数据库异构同步 | DBSyncer / DataX | MySQL→ES/PostgreSQL/MongoDB等异构数据源同步 | 字段类型映射不一致、增量同步断点恢复 |
| 桌面可视化同步 | Navicat / DBeaver 数据同步 | GUI操作,可视化对比+同步,支持结构和数据 | Navicat付费(¥1,500+/年)、大表同步慢、不适合自动化 |
四、四种建站场景的同步方案速查
| 你的场景 | 文件同步方案 | 数据库同步方案 | 月成本 |
|---|---|---|---|
| 网站搬家(一次性) | rsync -avzP /旧/ /新/ 先--dry-run再执行 | mysqldump --single-transaction → 传输 → mysql导入 | $0 |
| 定时备份到异地 | rsync + cron 每天凌晨执行 或rclone备份到对象存储 | mysqldump定时导出 + rsync传输 | $0 (云存储按量付费) |
| 多服务器负载均衡 | rsync + inotifywait (事件驱动,文件变化即时同步) | MySQL主从复制 (主库读写,从库只读) | $0工具 + 服务器成本 |
| 静态站点部署更新 | rsync --delete (保持服务器和本地构建目录一致) | 不涉及 | $0 |
| 站群多站点统一备份 | rclone 批量同步到COS/OSS 写脚本遍历所有站点目录 | 脚本批量mysqldump → rclone上传 | $0 + 对象存储按量 |
五、三个同步工具之外的翻车点
六、一个安全的生产级网站迁移同步流程
把这个流程存成checklist,每次网站迁移照着走一遍,不用靠脑子记:
第1步:源站切维护模式,停止一切写入操作。

第2步:mysqldump --single-transaction --routines --triggers --events 导出数据库,检查导出文件大小和末尾是否有 "Dump completed" 字样。
第3步:rsync -avzP --dry-run 先跑一次看差异清单,确认无误后去掉 --dry-run 正式执行。重点检查exclude规则是否排除对了缓存、日志、临时文件。
第4步:目标服务器导入数据库前先检查字符集一致,导入后跑 SELECT COUNT(*) 对比源库和目标库的关键表行数。
第5步:修改目标站配置文件(数据库连接、站点URL、缓存配置、CDN回源地址),确认没有任何地方还指向旧服务器。
第6步:按测试清单逐项验证:首页→内页→图片→上传→搜索→登录→后台→API接口。
第7步:切DNS到新服务器IP,TTL提前改短(建议600秒),保留旧服务器运行24-48小时做回滚备份。
第8步:48小时内持续监控新站访问日志和错误日志,确认没有异常后关停旧服务器。
网站数据同步的坑不在于工具难用,而在于每个工具都有自己的"默认假设"——rsync默认假设mtime+size能判断文件是否一致(大部分时候可以,断连场景不可以),MySQL主从复制默认假设网络稳定binlog不会丢(大部分时候可以,抖动场景不可以),mysqldump默认假设导出过程中没人写数据(你忘了加--single-transaction它也不会提醒你)。知道每个工具在什么场景下默认假设会失效,比知道工具怎么用重要得多。最后说一句:每次同步前先跑--dry-run,每次导出数据库都加--single-transaction,迁移后旧服务器至少保留48小时不删。这三条做到了,90%的翻车都能避免。

