这是一个非常经典且务实的问题。很多刚接触阿里云 ECS 的新手,为了省钱或者图省事,只买了一块系统盘(通常 40G-100G),没挂载数据盘,结果 MySQL 一跑起来,日志稍微大点,或者数据稍微多一点,系统盘就满了,导致服务器直接卡死甚至无法 SSH 登录。
在没有独立数据盘的情况下,安全、稳定地安装和使用 MySQL,核心思路只有两个:一是把数据目录迁移到系统盘的剩余空间或指定分区;二是通过配置严格限制磁盘使用上限。
以下是基于生产环境经验的实操方案,按推荐程度排序:
方案一:逻辑卷管理(LVM)——最稳健的“伪”扩展方案
如果你在安装系统时选择了 LVM(大多数云厂商默认镜像都支持),这是在不增加物理磁盘的情况下,未来最容易扩容的方法。即使现在不扩容,先建立好结构也是好习惯。
-
确认当前状态
df -h lsblk pvs # 查看物理卷 vgs # 查看卷组 lvs # 查看逻辑卷 -
创建 MySQL 专用逻辑卷(如果尚未创建)
假设你的系统盘是/dev/vda,根分区是/dev/vda2。你可以从根分区划出一部分空间给 MySQL。
注意:直接从已使用的 LV 中缩小风险极大,建议先在vgdisplay中看到有足够的 Free PE(空闲物理扩展块)。如果没有,此路不通,请看方案二。 -
修改 MySQL 数据目录指向
这是关键一步。默认 MySQL 数据在/var/lib/mysql。你需要将其移动到新的逻辑卷上。- 停止 MySQL:
systemctl stop mysqld - 移动数据:
mv /var/lib/mysql /mnt/mysql_data(临时存放) - 挂载新逻辑卷到
/var/lib/mysql - 修改权限:
chown -R mysql:mysql /var/lib/mysql - 启动 MySQL:
systemctl start mysqld
- 停止 MySQL:
优点:未来如果想加数据盘,只需将新盘加入 VG 并扩展 LV,无需停机迁移数据。
缺点:对初始磁盘规划有要求,如果系统盘已满,无法操作。
方案二:挂载至系统盘非根分区(/data 或 /opt)——最通用的做法
如果你的系统盘只有一个根分区 /,且已经占用了大部分空间,我们需要找一个“角落”安顿 MySQL。
步骤 1:评估空间
df -h /
确保 / 分区还有至少 10-20GB 的可用空间。MySQL 本身很小,但数据和 Binlog 会迅速膨胀。
步骤 2:创建专用目录并设置权限
不要直接把数据放在 /root 或其他用户目录下。
# 创建目录
mkdir -p /data/mysql
# 赋予 mysql 用户权限
chown -R mysql:mysql /data/mysql
chmod 750 /data/mysql
步骤 3:修改 MySQL 配置文件
编辑 /etc/my.cnf 或 /etc/mysql/my.cnf(取决于发行版,CentOS 通常是 my.cnf,Ubuntu 可能是 mysql.conf.d/mysqld.cnf)。
找到 [mysqld] 段,修改 datadir:
[mysqld]
datadir=/data/mysql
socket=/var/lib/mysql/mysql.sock
注意:如果是 Ubuntu/Debian,可能还需要修改 pid-file 和 tmpdir 的位置,避免写入冲突。
步骤 4:处理 SELinux(仅限 CentOS/RHEL)
如果开启了 SELinux,直接改路径会导致 MySQL 启动失败。
# 查看上下文
ls -Zd /data/mysql
# 如果报错,需要重新标记上下文
semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?"
restorecon -Rv /data/mysql
步骤 5:重启并验证
systemctl restart mysqld
systemctl status mysqld
mysql -u root -p -e "SHOW VARIABLES LIKE 'datadir';"
方案三:关键的安全与稳定性配置(无数据盘场景的核心)
既然没有独立数据盘,防止系统盘被写满导致服务器宕机就是最高优先级。必须做好以下配置:
1. 严格控制 Binlog 过期时间
Binlog 是 MySQL 增长的元凶。默认情况下,Binlog 不清理,直到磁盘爆满。
在 my.cnf 中添加或修改:
# 保留 7 天的 binlog,超过自动删除
expire_logs_days = 7
# 或者更激进一点,保留 3 天
# expire_logs_days = 3
注意:新版 MySQL (8.0+) 推荐使用 binlog_expire_logs_seconds,单位是秒。
2. 限制 InnoDB 缓冲池大小
如果你的服务器内存有限(比如 2G 或 4G),不要把 innodb_buffer_pool_size 设得太大,否则 Swap 交换频繁,IO 性能骤降。
# 设置为物理内存的 50%-70%
innodb_buffer_pool_size = 1G
3. 开启自动清理旧数据策略
对于非核心业务表,设置 max_binlog_size 和合理的 purge 策略。
# 单个 binlog 文件最大 1G,避免单个文件过大
max_binlog_size = 100M
4. 监控告警(必做!)
没有数据盘意味着系统盘和数据盘共用 IO 和空间。一旦磁盘使用率达到 80%,MySQL 可能还能写,但 90% 以上就会开始报错,95% 以上服务中断。
- 安装
zabbix-agent或阿里云自带的云监控插件。 - 设置磁盘使用率 > 80% 时发送短信/邮件告警。
5. 定期备份而非依赖磁盘空间
既然磁盘紧张,就不要指望靠磁盘空间来维持长期运行。
- 使用
mysqldump或XtraBackup每天凌晨全量/增量备份。 - 备份文件上传到 OSS(对象存储),而不是留在本地磁盘。
- 命令示例:
# 每天凌晨 2 点备份,压缩后传到 OSS(需配置 ossutil) 0 2 * * * /usr/local/bin/backup.sh >> /var/log/mysql_backup.log 2>&1
常见坑点与避坑指南
-
不要使用 tmpfs 作为数据目录
有人提议把/var/lib/mysql挂载到内存文件系统(tmpfs)以提速。这在测试环境可行,但生产环境绝对禁止。重启服务器后数据全部丢失,且内存不足时会导致 OOM Killer 杀死 MySQL 进程。 -
不要手动解压安装包覆盖原有目录
如果之前用过 yum/apt 安装的 MySQL,直接解压二进制包替换会导致库文件版本不一致、权限混乱。务必卸载旧版,再安装新版。 -
系统盘 IOPS 瓶颈
阿里云 ESSD 云盘性能较好,但如果只是基础型云盘,高并发下 IO 延迟会很高。观察iostat -x 1,如果%util持续接近 100%,说明磁盘已达瓶颈。此时除了优化 SQL,唯一解决办法是升级云盘类型或加装数据盘。 -
字符集问题
在新建数据库实例时,务必指定utf8mb4字符集,避免后续出现 emoji 表情或特殊符号插入失败的问题。
总结
在无数据盘环境下,“空间隔离 + 自动清理 + 外部备份” 是三大支柱。
- 空间隔离:将
datadir移到/data/mysql等非系统核心目录,便于管理和监控。 - 自动清理:强制设置
expire_logs_days,防止 Binlog 撑爆磁盘。 - 外部备份:数据存在本地都是耍流氓,必须定时备份到 OSS。
如果业务数据量预计会超过 50GB,强烈建议还是花几十块钱买一块最低配的数据盘(如 40G SSD),挂载到 /data,这样运维压力会小得多。毕竟,磁盘成本远低于故障恢复成本。
云技术博客