前段时间我打算把主站迁到一台新的 VPS 上。旧机器用了两年多,配置有点跟不上了,而且同价位的新机器性能更好一些。迁移前最头疼的就是数据怎么搬:网站文件、用户上传的图片、数据库备份,零零散散加起来有 100G 左右,而且文件数量特别多,小文件占了大头。
如果用 scp 或者 sftp 慢慢拖,按照我这破线路的速度,估计得传好几天,中间断一次还得从头来。所以这次迁移我用的工具是 rsync,整个过程比预想中顺利很多。
为什么选 rsync
rsync 有几个特点特别符合这次迁移的需求:
- 增量同步:只传输发生变化的部分,已经传过的文件不会再传。
- 断点续传:大文件传到一半断了,下次会从断点继续,不用重来。
- 保留权限:可以保留文件的权限、时间戳、所有者这些信息,对 Web 目录特别重要。
- 压缩传输:
-z参数可以在传输过程中压缩,适合小文件多的场景。
迁移前的准备
迁移之前我先列了一个清单:
- 在新服务器上装好同样的环境:Nginx、PHP、MySQL、Node.js 这些。
- 确认新服务器的磁盘空间足够,留有一定余量。
- 把旧服务器的 SSH 密钥加到新服务器,方便 rsync 直连。
- 通知用户或者设置维护页面(如果有的话)。
数据迁移我分了两步走:先迁静态文件,再迁数据库。因为数据库在迁移过程中可能还在变化,所以放在最后一步。
第一次全量同步
第一次同步把旧服务器上的所有数据拉到新服务器。我直接在新服务器上执行拉取命令:
1rsync -avz --progress \
2 -e "ssh -p 22" \
3 root@旧服务器IP:/var/www/myblog/ /var/www/myblog/
参数解释:
-a:归档模式,保留权限、符号链接、时间戳等,相当于-rlptgoD。-v:显示详细进度,方便看传输了什么。-z:传输时压缩,适合文本和小文件。--progress:显示每个文件的进度。-e "ssh -p 22":指定 SSH 端口,如果改了端口这里要对应修改。
第一次全量同步花了我大概三四个小时。主要是小文件太多,rsync 要逐个比对,带宽反而没用满。
遇到的第一个坑:大量小文件导致内存不足
同步到一半的时候,连接突然断开,报错 connection unexpectedly closed。
排查了一下,发现是因为我有一个目录里存了几百万张缩略图,每张只有几 KB。rsync 在构建文件列表时要把所有文件信息加载到内存,而那台旧机器只有 512M 内存,直接被 OOM 杀了。
解决办法是分目录同步。我写了一个简单的脚本,把大目录拆成多个小批次:
1#!/bin/bash
2
3SRC="root@旧服务器IP:/var/www/myblog/uploads/"
4DST="/var/www/myblog/uploads/"
5
6# 按年份子目录分别同步
7for dir in 2022 2023 2024; do
8 echo "正在同步 $dir ..."
9 rsync -avz --delete -e "ssh -p 22" "$SRC$dir/" "$DST$dir/"
10done
这样每次同步的文件列表就小多了,不会再把内存吃光。
第二次增量同步
全量同步完成后,旧服务器上的数据可能又有更新了。在切换域名解析之前,我再跑一次增量同步:
1rsync -avz --delete \
2 -e "ssh -p 22" \
3 root@旧服务器IP:/var/www/myblog/ /var/www/myblog/
这次加上 --delete 参数,保证两边完全一致。如果新服务器上多出了旧服务器没有的文件,会被删除。
因为大部分文件已经在第一次同步过了,第二次只花了十几分钟。
数据库迁移
静态文件同步完之后,开始迁数据库。我先在旧服务器上做一个完整的 dump:
1mysqldump -u root -p --all-databases --single-transaction > /tmp/all_databases.sql
--single-transaction 参数可以在不锁表的情况下导出 InnoDB 表,对线上服务影响比较小。
然后把 dump 文件传到新服务器:
1rsync -avz --progress -e "ssh -p 22" root@旧服务器IP:/tmp/all_databases.sql /tmp/
在新服务器上导入:
1mysql -u root -p < /tmp/all_databases.sql
导入完成后,我检查了几个关键表的数据量和最近更新时间,确认没有遗漏。
切换前的最终同步
真正切换流量之前,我还做了一次最终同步。这次要尽量减少停机时间。
步骤大概是这样的:
- 在旧服务器上暂停写入操作,比如暂时关闭用户上传功能,或者把应用设为只读模式。
- 跑最后一次 rsync 增量同步。
- 跑最后一次数据库 dump 和导入。
- 更新域名解析到新服务器 IP。
- 等新服务器开始承接流量后,再打开写入功能。
整个切换过程实际停机时间大概 10 分钟左右,主要花在数据库导入上。
验证和收尾
切换之后,我重点检查了这些东西:
- 网站首页、文章页、搜索功能是否正常。
- 图片、CSS、JS 等静态资源是否能正常加载。
- 数据库读写是否正常。
- Nginx 日志有没有报错。
- SSL 证书是否生效。
全部确认没问题后,我在旧服务器上保留了一个星期的数据作为保险,然后才清理掉。
总结
这次迁移让我对 rsync 的理解更深了一层。几个关键点:
- 全量 + 增量 + 最终同步 是减少停机时间的标准做法。
- 大量小文件要分目录同步,避免内存问题。
--delete要谨慎使用,确保目标目录是对的。- 数据库和静态文件分开迁移,数据库放在最后。
- 迁移前备份,迁移后验证,不要嫌麻烦。
rsync 真的算得上运维人员的神器之一。只要网络通,它就能把数据稳稳当当地搬过去。下次如果你也要迁移服务器,不妨试试这个方案。