跳至正文

11天没发文,差点以为号要废了,服务器迁移踩了5个坑总算活过来了

事情是这样的,上个月我决定把博客从一台跑了3年的腾讯云轻量服务器,迁移到新买的阿里云ECS。原因很简单,那台轻量服务器硬盘只剩8%了,docker日志一查,光是nginx的access log就占了12G。你说一个日活不到500的小破站,日志比用户数据还大,这合理吗?

我以为迁移嘛,不就是打包、上传、解压、改个DNS,撑死半天的事。结果从周五晚上折腾到周日凌晨,中间还经历了网站502、数据库连不上、SSL证书失效、图片全裂、定时任务全挂。最离谱的是,迁移完第三天,我发现cron里一个每天早上8点跑的数据备份脚本根本没执行,整整损失了3天的用户评论数据。

先说第一个坑:数据库迁移千万别用mysqldump默认参数。

我那台旧机器是MySQL 5.7,新机器装的是MySQL 8.0。我直接一条`mysqldump -u root -p myblog > backup.sql`,然后在新机器上`source backup.sql`。结果报错:`ERROR 1419 (HY000): You do not have the SUPER privilege for binary log`。查了半天,是MySQL 8.0默认开启了binlog,而dump文件里包含了`SET @@SESSION.SQL_LOG_BIN`这种需要super权限的语句。解决办法是dump的时候加个`–set-gtid-purged=OFF`参数:

“`
mysqldump -u root -p –set-gtid-purged=OFF myblog > backup.sql
“`

但这还没完。导入之后,发现有个表里存的是用户头像的URL,旧服务器用的是`http://old-domain.com/avatar/`开头的路径。我新服务器域名不一样,得批量替换。用`UPDATE`语句改了几千条记录,结果忘了先备份那张表。后来发现有个用户的头像被替换成了空字符串,因为那条记录里URL格式本来就是错的。还好用户不多,手动修复了3个。

第二个坑:静态文件迁移,rsync比scp靠谱一万倍。

一开始我用scp把整个`/var/www/html`目录拷到新机器,结果传了40分钟还没完,因为里面有个node_modules文件夹,里面全是些乱七八糟的依赖。更坑的是,scp不会保留软链接,我有个`/var/www/html/storage -> /data/storage`的软链接,拷过去直接变成普通文件,导致laravel的日志写不进去。改用rsync之后,加个`-a`参数保留权限和链接,再配合`–exclude`跳过node_modules和vendor目录:

“`
rsync -avz –exclude=’node_modules’ –exclude=’vendor’ –exclude=’.git’ /var/www/html/ root@新IP:/var/www/html/
“`

但rsync也有坑,如果目标目录不存在,它会自动创建,但权限可能不对。我忘了先`mkdir -p /var/www/html`并设置正确的用户和组,结果文件所有者是root,nginx进程是www-data用户,读不了静态文件,页面全是403。又花了一小时`chown -R www-data:www-data /var/www/html`。

第三个坑:SSL证书迁移,别直接复制文件。

我原来用的是Let‘s Encrypt的免费证书,直接复制`/etc/letsencrypt`目录到新机器上,想着反正都是同一套证书,省得重新申请。结果nginx启动时报错:`SSL: error:02001002:system library:fopen:No such file or directory`。原因是Let’s Encrypt的证书文件里包含了绝对路径的软链接,复制过去后路径对不上。正确做法是在新服务器上重新运行certbot申请证书,或者用certbot的`–cert-name`参数指定旧证书名,配合`–dry-run`先测试。我图省事,直接重新申请了,反正就一条命令:

“`
certbot –nginx -d mydomain.com -d www.mydomain.com
“`

这里注意,如果旧服务器上已经申请过,同一域名一周内不能重复申请太多次,有速率限制。我运气好,还没触发。

第四个坑:DNS切换后,缓存让你怀疑人生。

改完DNS的A记录,TTL设的是600秒,理论上10分钟生效。结果我等了2小时,自己手机访问还是旧服务器。查了一圈,发现是我本地的DNS缓存问题。Mac上清DNS缓存命令:`sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder`。Windows是`ipconfig /flushdns`。清完之后,立刻就能访问新服务器了。但用户那边就没这么幸运了,有个朋友说他一整天都看到的是旧页面,后来发现是他家路由器的DNS缓存没清,重启路由器才解决。

第五个坑:cron任务和队列worker,最容易忘的东西。

这是最致命的。我迁移完网站能正常访问了,数据库也通了,图片也显示了,就以为万事大吉。结果第三天有用户私信我说,昨晚发的评论到现在都没显示。我登录后台一看,评论表里有数据,但状态全是`unapproved`。查代码发现,评论审核是一个异步队列任务,需要运行`php artisan queue:work`。我新机器上根本没启动这个进程。赶紧写了个systemd服务,配置里加上`Restart=always`,确保进程挂了自动重启:

“`
[Unit]
Description=Laravel Queue Worker

[Service]
User=www-data
Group=www-data
Restart=always
ExecStart=/usr/bin/php /var/www/html/artisan queue:work –sleep=3 –tries=3

[Install]
WantedBy=multi-user.target
“`

然后`systemctl enable queue-worker && systemctl start queue-worker`。再看评论,积压了3天的500多条评论瞬间被处理完了。

但还有更隐蔽的:我有个cron任务,每天凌晨3点执行一次数据备份,把数据库dump上传到OSS。旧服务器上crontab里写的路径是`/home/ubuntu/backup.sh`,新服务器上用户是root,home目录不一样,而且backup.sh脚本里写死了旧服务器的OSS配置。结果这个cron跑了3天,每次都报错`ossutil: command not found`,因为新机器上没装ossutil。我手动执行了`crontab -e`检查,发现有一条记录是`0 3 * * * /home/ubuntu/backup.sh`,但`/home/ubuntu`目录根本不存在。赶紧修改脚本路径,装了ossutil,测试跑了一遍,确认上传成功。

最后总结一下,服务器迁移这种事,看似简单,实则处处是坑。我列了个checklist,以后再也不犯:

– 数据库迁移:用`–set-gtid-purged=OFF`,导入前先替换域名和路径,导入后检查字符集和时区。
– 文件迁移:用rsync加`-a`参数,排除无用目录,检查软链接和文件权限。
– SSL证书:别复制,重新申请,或者用certbot的迁移工具。
– DNS切换:TTL设短点,清本地缓存,通知用户可能需要重启路由器。
– 后台任务:列个清单,包括cron、队列worker、定时脚本、监控agent,一个都不能少。
– 备份:迁移前先全量备份,迁移过程中每完成一步就做一次快照,万一出问题能回滚。

现在我的博客在新服务器上跑了一周,速度比原来快了30%,硬盘还剩80%。但说实话,再让我来一次,我宁愿花200块买个迁移服务,也不想再熬一个通宵了。


📎 延伸阅读

看完这篇,如果你想:

  • 直接拿工具 → 回复”13“,我把跨境获客工具包发给你
  • 系统学习 → 点击菜单”AI训练营”,从0开始跑通AI变现

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注