5/25/20266 Views

阿里云 ECS 数据盘迁移实战:ext4 分区盘与 LVM 逻辑卷迁移

本文整理自一次阿里云 ECS 数据盘迁移实践,覆盖两类常见场景:普通 ext4 分区盘迁移,以及 LVM 逻辑卷自动挂载配置。重点记录迁移流程、停写一致性、fstab 写法、数据库占用排查,以及几个生产环境里很容易踩到的坑。

1. 背景说明

云服务器数据盘迁移,本质上不是简单的“复制文件”,而是一次需要兼顾 数据一致性、可回滚、可验证、可自动挂载 的生产变更。

这次迁移主要涉及两个场景:

场景原挂载新目标重点
普通 ext4 分区盘迁移/dev/vdb1 -> /G4B/dev/vdc1 -> /G4Brsync 双阶段迁移、停库、切换挂载点
LVM 逻辑卷挂载/dev/vde1 -> vgdata-lvdata -> /G4B/uploadfile开机自动挂载使用 UUID 写入 /etc/fstab

其中 /G4B 目录下存在数据库相关数据,可能涉及 MySQL、MongoDB、PostgreSQL。因此迁移过程中最关键的一点是:最终同步和切换挂载前,必须停止业务写入


2. 迁移目标

2.1 场景 A:普通 ext4 分区盘迁移

当前磁盘情况如下:

bash
df -Th

示例输出:

text
Filesystem Type Size Used Avail Use% Mounted on /dev/vda1 ext4 99G 31G 64G 33% / /dev/vdb1 ext4 985G 100G 840G 11% /G4B

块设备情况:

bash
lsblk

示例结构:

text
vda1 -> / vdb1 -> /G4B vdc -> 新数据盘

迁移目标:

  • 将旧盘 /dev/vdb1 上的数据迁移到新盘 /dev/vdc1
  • 保持业务目录仍然使用 /G4B,减少应用配置改动。
  • 迁移后通过 UUID 写入 /etc/fstab,确保 ECS 重启后自动挂载。
  • 旧盘先保留一段时间,作为回滚保障。

2.2 场景 B:LVM 逻辑卷自动挂载

当前逻辑卷结构:

text
vde └─vde1 └─vgdata-lvdata /G4B/uploadfile

目标:

  • 确认 LVM 逻辑卷文件系统类型与 UUID。
  • 将逻辑卷挂载信息写入 /etc/fstab
  • 保证系统重启后 /G4B/uploadfile 能自动挂载。

说明:云盘通常不建议走“原盘缩容”路线,尤其是生产环境。更稳妥的方式是:新盘创建、数据迁移、挂载切换、验证、保留旧盘、最后释放旧盘。XFS 文件系统不支持缩小,ext4 虽然支持离线缩小,但生产风险较高,不建议作为首选。


3. 迁移前检查清单

迁移前不要急着执行 rsync 或格式化新盘,先把以下内容确认清楚。

3.1 确认挂载点与文件系统

bash
df -Th lsblk -f mount | egrep '/G4B|uploadfile'

重点看四个信息:

  • /G4B 当前挂载在哪块盘上。
  • 新盘设备名是否确认,例如 /dev/vdc
  • 文件系统类型是 ext4、xfs 还是其他。
  • /G4B/uploadfile 是否由 LVM 逻辑卷提供。

3.2 确认数据库数据目录

数据库数据目录如果在 /G4B 下,迁移时就不能只当普通文件处理。必须确认数据库是否持续写入。

MySQL:

bash
mysql -e "SHOW VARIABLES LIKE 'datadir';" grep -R "datadir" -n /etc/my.cnf /etc/mysql/my.cnf /etc/my.cnf.d/* 2>/dev/null

MongoDB:

bash
grep -nE "dbPath|systemLog|path|port" /etc/mongo/mongo.conf 2>/dev/null

PostgreSQL:

bash
ps -ef | grep -E 'postmaster|postgres' | grep -v grep

3.3 做好云盘快照和回滚预案

生产环境建议至少做好三件事:

  1. 在阿里云控制台给旧数据盘打快照。
  2. 迁移完成后旧盘不要马上释放,先保留观察。
  3. 明确回滚方式:如果新盘启动异常,可重新挂回旧盘 UUID 或旧设备。

4. 方案一:ext4 普通分区盘迁移

推荐流程如下:

text
新盘分区格式化 临时挂载新盘 rsync 第一遍预同步 停业务写入 / 停数据库 rsync 第二遍最终同步 卸载旧盘并将新盘挂载到原目录 更新 /etc/fstab 启动服务并验证

4.1 新盘分区

注意:下面命令会清空 /dev/vdc,执行前必须确认 /dev/vdc 是新盘,不是旧数据盘。

bash
parted -s /dev/vdc mklabel gpt parted -s /dev/vdc mkpart primary 1MiB 100% partprobe lsblk /dev/vdc

4.2 格式化 ext4

bash
mkfs.ext4 -F /dev/vdc1

如果这是数据盘,可以适当降低 ext4 默认预留块比例,例如设置为 1%:

bash
tune2fs -m 1 /dev/vdc1

说明:

  • ext4 默认会预留一部分空间给 root 使用。
  • 对大容量数据盘而言,默认预留比例可能浪费较多空间。
  • 业务数据盘设置为 1% 较常见,但仍需根据实际环境评估。

4.3 临时挂载新盘

bash
mkdir -p /mnt/G4B_new mount /dev/vdc1 /mnt/G4B_new df -Th /mnt/G4B_new

确认新盘已经挂载到 /mnt/G4B_new 后,再开始同步数据。

4.4 rsync 第一遍预同步

第一遍同步可以在业务不停机的情况下执行,目的是先把大部分数据复制过去,减少最终停机窗口。

bash
rsync -aHAX --numeric-ids --info=progress2 /G4B/ /mnt/G4B_new/

参数说明:

参数作用
-a归档模式,保留权限、时间、软链接等
-H尽量保留硬链接
-A保留 ACL
-X保留扩展属性
--numeric-ids按 UID/GID 数字同步,避免用户名映射异常
--info=progress2显示整体同步进度

5. 切换窗口:停止写入并做最终同步

5.1 为什么必须停写入

如果 /G4B 下有数据库数据文件,迁移时数据库仍在写入,就可能出现以下问题:

  • 数据文件正在变化,rsync 复制到的是中间状态。
  • WAL、binlog、journal 与数据文件时间点不一致。
  • 目标盘数据库启动失败,或者更糟糕:能启动但存在隐性数据损坏。

所以正确做法是:

第一遍 rsync 可以不停业务;第二遍 rsync 前必须停止写入。

5.2 排查 /G4B 被哪些进程占用

尝试将挂载点改为只读时,可能会遇到:

bash
mount -o remount,ro /G4B

报错:

text
mount: /G4B is busy

这说明仍有进程正在访问 /G4B。使用 fuser 反查:

bash
fuser -vm /G4B

常见占用进程包括:

  • mysqld
  • mongod
  • postmaster / postgres
  • 当前 shell 的工作目录在 /G4B

建议先执行:

bash
cd / fuser -vm /G4B

避免自己的 shell 占用挂载点。

5.3 停止数据库服务

使用 systemd 停止常规服务:

bash
# MySQL systemctl stop mysqld 2>/dev/null || systemctl stop mysql 2>/dev/null || true # PostgreSQL systemctl stop postgresql 2>/dev/null || systemctl stop postgresql-* 2>/dev/null || true # MongoDB systemctl stop mongod 2>/dev/null || systemctl stop mongod* 2>/dev/null || true

再次确认:

bash
fuser -vm /G4B

如果仍然有进程占用,需要逐个处理。

5.4 MongoDB 找不到 service 名的处理方式

这次迁移中遇到一个典型问题:MongoDB 进程存在,但 systemctl stop mongod 停不掉。通过 PID 反查:

bash
systemctl status <PID>

看到类似结果:

text
CGroup: /system.slice/sshd.service ├─... sshd ├─5367 ./bin/mongod -f /etc/mongo/mongo.conf --fork

这说明 MongoDB 很可能不是由独立的 mongod.service 管理,而是通过 SSH 会话手工启动后 fork 到后台。

优先使用 MongoDB 自身命令优雅关闭:

bash
mongosh --eval 'db.adminCommand({shutdown: 1})'

如果 mongosh 不在 PATH 中,可以先找二进制路径:

bash
pgrep -a mongod PID=$(pgrep -xo mongod) readlink -f /proc/$PID/exe tr '\0' ' ' < /proc/$PID/cmdline; echo

无法优雅关闭时,再使用信号终止:

bash
kill -TERM <PID> sleep 5 kill -KILL <PID>

kill -KILL 是最后手段,生产环境不建议一上来就使用。能通过数据库自身机制关闭,就不要强杀。

5.5 rsync 第二遍最终同步

确认业务写入已经停止后,执行最终同步:

bash
rsync -aHAX --numeric-ids --delete /G4B/ /mnt/G4B_new/ sync

这里必须加 --delete,确保目标目录与源目录完全一致。


6. 切换挂载点

6.1 不推荐直接使用 mount --move

本次迁移中曾尝试:

bash
mount --move /mnt/G4B_new /G4B

但遇到错误:

text
moving a mount residing under a shared mount is unsupported

原因是当前挂载点处于 shared mount propagation 场景下,mount --move 会受到限制。

6.2 稳妥切换方式:umount + mount

更稳妥的方式是直接卸载旧挂载和临时挂载,再把新盘挂载到原目录:

bash
umount /G4B umount /mnt/G4B_new mount /dev/vdc1 /G4B df -Th /G4B

确认 /G4B 已经挂载到新盘后,再继续修改 /etc/fstab


7. 配置 /etc/fstab 自动挂载

7.1 使用 UUID,不建议使用 /dev/vdc1

云服务器磁盘设备名可能因为重启、热插拔、挂载顺序变化而发生变化。生产环境建议使用 UUID 挂载。

查看新盘 UUID:

bash
blkid /dev/vdc1

示例:

text
/dev/vdc1: UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="ext4"

编辑 /etc/fstab

bash
vi /etc/fstab

写入或替换 /G4B 对应行:

fstab
UUID=<NEW_UUID> /G4B ext4 defaults,nofail 0 2

更推荐的云服务器写法:

fstab
UUID=<NEW_UUID> /G4B ext4 defaults,nofail,x-systemd.device-timeout=10s 0 2

字段说明:

字段说明
UUID=<NEW_UUID>使用文件系统 UUID 定位磁盘
/G4B挂载点
ext4文件系统类型
defaults默认挂载参数
nofail挂载失败不阻塞系统启动
x-systemd.device-timeout=10ssystemd 等待设备出现的超时时间
0不使用 dump 备份
2非根分区 fsck 检查顺序

验证 fstab 是否正确:

bash
mount -a df -Th /G4B

注意:修改 /etc/fstab 后一定要执行 mount -a。如果这里报错,说明重启后大概率也会挂载失败。


8. 启动服务并验证

启动数据库服务:

bash
systemctl start postgresql 2>/dev/null || systemctl start postgresql-* 2>/dev/null || true systemctl start mysqld 2>/dev/null || systemctl start mysql 2>/dev/null || true systemctl start mongod 2>/dev/null || true

检查监听端口:

bash
ss -lntp | egrep '27017|3306|5432'

建议进一步验证:

bash
# 查看挂载是否正确 findmnt /G4B # 查看数据库日志 journalctl -u mysqld -n 100 --no-pager 2>/dev/null || true journalctl -u mysql -n 100 --no-pager 2>/dev/null || true journalctl -u postgresql -n 100 --no-pager 2>/dev/null || true journalctl -u mongod -n 100 --no-pager 2>/dev/null || true # 确认磁盘空间 df -h /G4B

如果业务有健康检查接口,也建议立即验证:

bash
curl -I http://127.0.0.1:<PORT>/health

9. 方案二:LVM 逻辑卷自动挂载

如果数据目录是 LVM 逻辑卷,例如:

text
vde1 -> vgdata-lvdata -> /G4B/uploadfile

可以按下面方式配置自动挂载。

9.1 查看 LVM 信息

bash
pvs vgs lvs lsblk -f /dev/vgdata/lvdata blkid /dev/vgdata/lvdata

确认逻辑卷路径、UUID、文件系统类型。

9.2 写入 /etc/fstab

推荐写法:

fstab
UUID=<UUID> /G4B/uploadfile <FSTYPE> defaults,nofail,x-systemd.device-timeout=10s 0 2

如果文件系统是 ext4:

fstab
UUID=<UUID> /G4B/uploadfile ext4 defaults,nofail,x-systemd.device-timeout=10s 0 2

验证:

bash
mkdir -p /G4B/uploadfile mount -a df -Th /G4B/uploadfile findmnt /G4B/uploadfile

9.3 LVM 自动激活检查

大多数 Linux 发行版默认会自动激活 LVM。如果担心重启后没有激活,可以检查:

bash
systemctl status lvm2-monitor 2>/dev/null || true lvmconfig --type full activation/auto_activation_volume_list 2>/dev/null || true

通常情况下,只要 pvsvgslvs 正常,fstab 写 UUID 即可。


10. 常见故障与处理

10.1 mount -o remount,ro /G4B 报 busy

原因:

  • 有进程打开了 /G4B 下的文件。
  • 有进程工作目录在 /G4B 下。
  • 数据库、日志服务、备份脚本仍在访问该目录。

处理:

bash
cd / fuser -vm /G4B

根据输出停服务。最后手段才考虑:

bash
fuser -km /G4B

10.2 MongoDB 不受 systemd 管理

现象:

bash
systemctl stop mongod

没有效果,或者找不到 unit。

排查:

bash
pgrep -a mongod systemctl status <PID>

如果看到 mongod 挂在 sshd.service 下面,说明它大概率是手工启动的。

建议后续补充 systemd unit,避免生产服务脱离进程管理。

10.3 mount --move 报 shared mount 不支持

现象:

text
moving a mount residing under a shared mount is unsupported

处理:

bash
umount /G4B umount /mnt/G4B_new mount /dev/vdc1 /G4B

不需要强行研究 mount --make-rprivate,生产变更中优先选择简单、可控、可回滚的方式。

10.4 mount -a 报错

常见原因:

  • UUID 写错。
  • 文件系统类型写错,例如实际是 xfs,却写成 ext4。
  • 挂载点目录不存在。
  • /etc/fstab 有多余空格、不可见字符或字段缺失。

排查命令:

bash
blkid lsblk -f findmnt --verify mount -av

11. 生产环境最佳实践

11.1 迁移前

  • 阿里云控制台创建旧数据盘快照。
  • 确认新盘设备名,避免误格式化旧盘。
  • 使用 df -Thlsblk -ffindmnt 盘点挂载关系。
  • 确认 MySQL、MongoDB、PostgreSQL 数据目录是否在迁移目录下。
  • 提前评估停机窗口,第一遍 rsync 尽量提前完成。

11.2 迁移中

  • 新盘分区、格式化、临时挂载。
  • 第一遍 rsync 预同步。
  • 停止业务写入,尤其是数据库。
  • 使用 fuser -vm 确认挂载点没有占用。
  • 第二遍 rsync 使用 --delete 做最终对齐。
  • 使用 umount + mount 切换挂载点。
  • 使用 UUID 更新 /etc/fstab
  • 执行 mount -a 验证配置。

11.3 迁移后

  • 使用 df -Thfindmnt 确认挂载到新盘。
  • 启动数据库并检查端口、日志、健康检查接口。
  • 验证业务读写是否正常。
  • 保留旧盘观察一段时间,不要立即释放。
  • 将手工启动的 MongoDB 等服务纳入 systemd 管理。
  • 补充变更记录,记录旧盘、新盘、UUID、迁移时间和回滚方式。

12. 常用命令速查

bash
# 查看文件系统和挂载 df -Th lsblk -f findmnt /G4B # 查看挂载点占用 cd / fuser -vm /G4B # 新盘分区 parted -s /dev/vdc mklabel gpt parted -s /dev/vdc mkpart primary 1MiB 100% partprobe # ext4 格式化 mkfs.ext4 -F /dev/vdc1 tune2fs -m 1 /dev/vdc1 # 临时挂载 mkdir -p /mnt/G4B_new mount /dev/vdc1 /mnt/G4B_new # rsync 双阶段同步 rsync -aHAX --numeric-ids --info=progress2 /G4B/ /mnt/G4B_new/ rsync -aHAX --numeric-ids --delete /G4B/ /mnt/G4B_new/ sync # 切换挂载 umount /G4B umount /mnt/G4B_new mount /dev/vdc1 /G4B # 查看 UUID blkid /dev/vdc1 # 验证 fstab mount -a findmnt --verify # 检查数据库端口 ss -lntp | egrep '27017|3306|5432'

13. 总结

这类数据盘迁移最容易出问题的点,不在于 rsync 命令本身,而在于三个细节:

  1. 是否确认了真实写入进程:数据库、日志、脚本都可能占用挂载点。
  2. 最终同步时是否真正停止写入:数据库文件迁移必须保证一致性。
  3. 自动挂载是否经过验证fstab 写完必须执行 mount -afindmnt --verify

生产环境里,迁移成功的关键不是操作有多快,而是每一步都能验证、能回滚、能解释。只要做到“快照兜底、双阶段同步、停写切换、UUID 挂载、旧盘保留”,这类 ECS 数据盘迁移就会稳很多。

讨论 0

0 / 100
Supports **Bold**, `Code`
No comments yet.