1. 为什么需要将MariaDB从系统盘迁移到数据盘
第一次在服务器上部署MariaDB时,很多运维新手会直接使用默认安装路径,结果数据库文件就被放在了系统盘上。这个看似无害的操作,实际上埋下了不少隐患。系统盘通常容量有限(特别是云服务器默认的系统盘往往只有40-100GB),随着业务增长,数据库体积膨胀会迅速挤占系统盘空间,导致系统日志无法写入、软件更新失败等问题。
更严重的是,系统盘和数据盘在IO性能上通常存在显著差异。以阿里云ECS为例,系统盘一般采用云盘,而数据盘可以配置为高效云盘甚至SSD云盘。我曾在一次性能调优中发现,将MariaDB迁移到SSD数据盘后,查询性能提升了近3倍。此外,系统盘往往与操作系统共享IO资源,当系统进行大量日志写入或包更新时,数据库性能会出现明显波动。
从运维安全角度考虑,分离系统盘和数据盘也是最佳实践。当系统崩溃需要重装时,如果数据库存放在独立的数据盘上,只需重新挂载即可恢复服务,避免了复杂的数据迁移过程。去年我们一个客户的生产环境就因系统盘损坏导致数据库丢失,最后不得不从备份恢复,造成了6小时的服务中断。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 迁移前的关键准备工作
2.1 环境检查与容量规划
执行df -h查看当前磁盘使用情况时,要特别注意/var/lib/mysql目录的占用空间。这个目录通常存放着MariaDB的所有数据文件,包括表结构、索引和实际数据。我建议使用du -sh /var/lib/mysql获取精确的数据库大小,并确保目标数据盘有至少2倍的剩余空间。
在云环境中,还需要确认数据盘已经正确挂载。通过lsblk可以查看磁盘设备列表,而mount命令能显示当前挂载点。常见的问题是管理员创建了数据盘但忘记格式化,此时需要执行:
bash复制mkfs.ext4 /dev/vdb # 假设数据盘设备为/dev/vdb
mkdir /data
mount /dev/vdb /data
2.2 服务状态管理与备份策略
迁移前必须停止MariaDB服务以保证数据一致性:
bash复制systemctl stop mariadb
但直接停止服务会导致业务中断,因此在生产环境中,我通常会:
- 先在业务低峰期进行操作
- 设置维护页面通知用户
- 使用
FLUSH TABLES WITH READ LOCK命令将数据库设为只读模式 - 通过
SHOW MASTER STATUS记录二进制日志位置(主从架构时特别重要)
完整的备份方案应该包括:
bash复制mysqldump -uroot -p --all-databases > full_backup.sql
rsync -avz /var/lib/mysql /tmp/mysql_backup
3. 数据迁移的三种实战方案
3.1 方案一:直接文件拷贝(适合中小型数据库)
这是最直观的方法,适用于数据库文件不大的场景:
bash复制cp -rp /var/lib/mysql /data/mysql
chown -R mysql:mysql /data/mysql
关键点在于-p参数保留文件属性,以及后续的权限修正。我曾遇到因权限问题导致MariaDB无法启动的情况,后来发现是SELinux上下文丢失,需要通过restorecon -Rv /data/mysql修复。
3.2 方案二:符号链接方式(适合快速回滚)
这种方法只移动数据文件而保持配置文件不变:
bash复制mv /var/lib/mysql /data/
ln -s /data/mysql /var/lib/mysql
systemctl start mariadb
优点是回滚简单,只需删除符号链接并移回原目录即可。但要注意某些安全策略(如AppArmor)可能会阻止通过符号链接访问数据文件,需要调整相应配置。
3.3 方案三:配置修改法(推荐生产环境使用)
这是最彻底的方法,通过修改MariaDB配置指向新位置:
- 编辑
/etc/my.cnf或/etc/mysql/my.cnf:ini复制[mysqld] datadir=/data/mysql socket=/data/mysql/mysql.sock - 修改systemd服务配置:
bash复制
添加:systemctl edit mariadbini复制[Service] ReadWritePaths=/data/mysql
这种方法虽然步骤较多,但能彻底解决问题。在Kubernetes环境中部署时,还需要相应调整PV/PVC的挂载路径。
4. 迁移后的验证与优化
4.1 基础功能验证
启动服务后,不能仅凭systemctl status mariadb显示active就认为迁移成功。完整的验证流程应包括:
bash复制mysql -uroot -p -e "SHOW DATABASES;"
mysqlcheck -uroot -p --all-databases
我曾经遇到过一个案例,迁移后基础查询正常,但特定存储引擎的表却无法访问,最后发现是文件权限问题。因此建议对每个数据库执行代表性查询。
4.2 性能调优建议
迁移到数据盘后,可以进一步优化配置:
ini复制[mysqld]
innodb_flush_method = O_DIRECT
innodb_io_capacity = 2000 # SSD建议值
innodb_io_capacity_max = 4000
对于使用机械硬盘的场景,则应该调整:
ini复制innodb_io_capacity = 200
innodb_io_capacity_max = 400
通过监控iostat -x 1可以观察磁盘IO利用率,确保没有出现瓶颈。
5. 常见问题与应急方案
5.1 服务启动失败排查
当遇到systemctl start mariadb失败时,按以下步骤排查:
- 查看日志:
journalctl -xe -u mariadb - 检查权限:
ls -la /data/mysql - 验证SELinux状态:
sestatus - 检查磁盘空间:
df -h /data
常见错误解决方案:
- "Can't connect to local MySQL server through socket":确认my.cnf中socket路径正确
- "Table 'mysql.user' doesn't exist":数据文件拷贝不完整,需要重新迁移
5.2 回滚操作指南
当迁移出现问题时,可以按照以下步骤回退:
- 立即停止MariaDB服务
- 恢复原数据目录:
bash复制rm -rf /var/lib/mysql # 如果是符号链接方式则删除链接 mv /data/mysql /var/lib/ - 注释掉my.cnf中的datadir修改
- 启动服务验证
在某个金融系统迁移案例中,我们预先准备了回滚脚本,结果真的在遇到文件系统权限问题时用上了,将停机时间控制在5分钟以内。
6. 高级技巧与自动化方案
对于大型数据库集群,可以考虑以下进阶方案:
6.1 使用LVM实现在线迁移
当不能停止服务时,可以结合LVM快照:
bash复制lvcreate -L10G -s -n mysql_snap /dev/vg00/mysql
mysql -e "FLUSH TABLES WITH READ LOCK; SYSTEM lvcreate --snapshot --name mysql_snap --size 1G /dev/vg00/mysql; UNLOCK TABLES;"
这种方法虽然复杂,但能实现接近零停机的迁移,特别适合7×24小时运行的关键业务系统。
6.2 自动化迁移脚本示例
以下是一个经过生产验证的迁移脚本框架:
bash复制#!/bin/bash
# 定义变量
OLD_DIR="/var/lib/mysql"
NEW_DIR="/data/mysql"
CONF_FILE="/etc/my.cnf"
# 预检查函数
check_disk_space() {
local required=$(du -s $OLD_DIR | awk '{print $1}')
local available=$(df -P $NEW_DIR | awk 'NR==2 {print $4}')
[ $available -lt $((required * 2)) ] && {
echo "Error: Not enough space on target disk"
exit 1
}
}
# 主迁移流程
migrate_mysql() {
systemctl stop mariadb
rsync -av --progress $OLD_DIR/ $NEW_DIR/
sed -i "s|datadir=.*|datadir=$NEW_DIR|" $CONF_FILE
chown -R mysql:mysql $NEW_DIR
systemctl start mariadb
}
# 执行迁移
check_disk_space
migrate_mysql
这个脚本包含了基本的错误处理,在实际使用中还可以添加日志记录、邮件通知等功能。
