MySQL Redo Log 和 Undo Log 迁移实践文档

【说明】:

最近云服务器迁移,将原来的单服务器升级成主从模式,完成迁移后,发现系统盘I/O异常,执行【iostat -x 5】,磁盘%util基本上是100%,经查是由MySQL进程引起,经多方排查,最终锁定是由MySQL Redo Log 和 Undo Log导致的,将Redo Log 和 Undo Log迁移到另一块云盘后,顺利将I/O降至20%以下。现将过程记录如下。

【环境】:

MySQL 版本:8.0,采用主从复制模式

默认源目录:/var/lib/mysql

目标目录示例:/data/mysql-log

系统及版本:阿里云Ubuntu 22.04

1 Redo Log 和 Undo Log 简介

1.1 Redo Log(重做日志)

(1)作用:保证事务的持久性。当数据页修改后,先写入 Redo Log(顺序写),再异步刷入数据文件。崩溃恢复时,通过 Redo Log 重放已提交的事务修改,防止数据丢失。

(2)存储位置:MySQL 8.0 中,Redo Log 存储在 datadir/#innodb_redo/ 目录下(默认 /var/lib/mysql/#innodb_redo/),由多个 #ib_redo* 文件组成。

(3)I/O 特征:顺序写,高带宽消耗,对延迟敏感。

1.2 Undo Log(撤销日志)

(1)作用:保证事务的原子性(回滚)和 MVCC(多版本并发控制)。记录修改前的旧值,用于事务回滚或为一致性读提供历史版本。

(2)存储位置:独立表空间文件 undo_001, undo_002 等(MySQL 8.0 默认创建 2 个),位于 datadir 下(默认 /var/lib/mysql/undo_001, undo_002)。

(3)I/O 特征:随机读写,高并发写入时压力显著。

2 为什么要迁移 Redo/Undo Log

在高负载的生产环境中,Redo/Undo Log 会产生大量磁盘 I/O。默认情况下,它们与数据文件、系统表空间等共同存放在 datadir(通常为系统盘),导致以下问题:

  • 磁盘 I/O 争用:多种 I/O 类型(顺序写、随机写、读写)混合在同一磁盘,相互干扰,性能下降。
  • 系统盘压力过大:系统盘(如 vda)往往性能有限(高效云盘 IOPS 约 3000),容易达到瓶颈,影响整体稳定性。
  • 无法灵活扩展:数据文件和日志混在一起,无法单独升级日志盘的性能。
  • 迁移目标:将 Redo/Undo Log 分离到独立的、高性能的磁盘(如 ESSD),实现 I/O 隔离,降低系统盘压力,提升数据库吞吐量。

3 迁移前准备

3.1 硬件规划

准备一块或多块独立磁盘(建议 ESSD PL0 或更高),挂载到指定目录,例如 /data。

在 /data 下创建迁移目标目录:/data/mysql-log。

确保磁盘有足够空间(Redo Log 按 innodb_redo_log_capacity 设置,Undo Log 按 innodb_max_undo_log_size 设置,建议额外预留 20%)。

3.2 目录权限

bash 复制代码
mkdir -p /data/mysql-log/mysql_redo /data/mysql-log/mysql_undo
chown mysql:mysql /data/mysql-log/mysql_redo /data/mysql-log/mysql_undo
chmod 750 /data/mysql-log/mysql_redo /data/mysql-log/mysql_undo

3.3 备份

备份 MySQL 配置文件(/etc/mysql/mysql.conf.d/mysqld.cnf)。

建议对 datadir 进行全量备份(可使用 rsync 或 mysqldump)。

4 迁移步骤

4.1 停止 MySQL 服务

bash 复制代码
systemctl stop mysql

4.2 迁移 Undo Log(通过配置文件)

bash 复制代码
# 移动现有 Undo 文件(从默认目录到新目录)
mv /var/lib/mysql/undo_* /data/mysql-log/mysql_undo/

编辑 /etc/mysql/mysql.conf.d/mysqld.cnf,在 [mysqld] 段末尾添加如下内容:

bash 复制代码
innodb_undo_directory = /data/mysql-log/mysql_undo
innodb_undo_log_truncate = ON
innodb_max_undo_log_size = 1G   # 可根据需要调整

4.3 迁移 Redo Log

由于 MySQL 8.0 强制 Redo Log 位于 datadir/#innodb_redo,无法通过参数修改路径,因此这里采用符号链接。

bash 复制代码
# 移动原 Redo 目录
mv /var/lib/mysql/#innodb_redo /data/mysql-log/mysql_redo/

# 创建符号链接
ln -s /data/mysql-log/mysql_redo/#innodb_redo /var/lib/mysql/#innodb_redo
chown -h mysql:mysql /var/lib/mysql/#innodb_redo

4.4 修正目录权限

bash 复制代码
chown -R mysql:mysql /data/mysql-log
chmod 750 /data/mysql-log/mysql_redo /data/mysql-log/mysql_redo/#innodb_redo
chmod 750 /data/mysql-log/mysql_undo

# 确保父目录有执行权限(允许 mysql 用户穿透)
sudo chmod 755 /data /data/mysql-log

4.5 处理安全模块

Ubuntu 等系统默认启用 AppArmor,会阻止 MySQL 访问新路径。解决方案:

(1)临时禁用 MySQL 的 AppArmor 限制(快速测试)

bash 复制代码
aa-disable /usr/sbin/mysqld

(2)永久添加规则(推荐)

编辑 /etc/apparmor.d/usr.sbin.mysqld,在末尾(但要"}"内部)添加:

bash 复制代码
/data/mysql-log/ r,
/data/mysql-log/** rwk,

重新加载AppArmor:

bash 复制代码
apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld
systemctl restart apparmor

4.6 启动 MySQL 并验证

bash 复制代码
systemctl start mysql

# 检查无权限错误
tail -f /var/log/mysql/error.log 

5 常见故障排除

5.1 启动失败,错误日志显示 error 13 (Permission denied)

**原因:**MySQL 用户无权访问目标路径,或中间目录缺少执行权限,或 AppArmor/SELinux 阻止。

解决方案: 检查各级目录权限:ls -ld /data /data/mysql-log,确保 mysql 用户有 +x 权限。

临时禁用 AppArmor:sudo aa-disable /usr/sbin/mysqld。

5.2 启动失败,错误日志显示 Invalid Filename

**原因:**Undo 文件未成功移动到新目录,但 innodb_undo_directory 已指向新路径。

**解决方案:**将 Undo 文件移动到正确位置,或暂时注释 innodb_undo_directory 让 MySQL 使用默认路径。

5.3 迁移后磁盘 I/O 利用率依然很高

**原因:**新磁盘性能不足(例如仍为高效云盘),或 MySQL 参数未优化。

解决方案:

升级磁盘到 ESSD PL2 或更高。

调整 innodb_flush_log_at_trx_commit = 2 和 sync_binlog = 1000(主库)。具体参见6.1。

检查是否还有其他组件(如 Elasticsearch)占用同一磁盘。

5.4 符号链接在 Ubuntu 下被 AppArmor 拒绝

**原因:**AppArmor 会追踪符号链接的最终目标,即使链接本身在允许目录内,目标路径也必须在策略中允许。

**解决方案:**检查、重载并重启AppArmor 。

6 迁移后的优化建议

6.1 调整 MySQL 参数降低 I/O 压力

迁移成功后,系统盘的I/O确实显著下降了,但数据盘vdb的I/O却高达60%左右,可编辑MySQL配置文件 /etc/mysql/mysql.conf.d/mysqld.cnf,在末尾添加如下内容(注意:主/从配置略有不同)

sql 复制代码
# 主库(可容忍最多丢失 1 秒数据 + 最多 1000 个事务)
innodb_flush_log_at_trx_commit = 2
sync_binlog = 1000

# 从库(完全不产生 binlog 时可设 sync_binlog=0)
innodb_flush_log_at_trx_commit = 2
sync_binlog = 0

重启MySQL服务。经此优化后,I/O可大幅下降,甚至降至20%以下。

6.2 增大 Redo Log 容量

sql 复制代码
SET PERSIST innodb_redo_log_capacity = 16G;

6.3 定期监控磁盘利用率

sql 复制代码
iostat -x 5 | grep -E "vdb|vdc|vdd"

7 总结

通过将 Redo/Undo Log 从默认目录 /var/lib/mysql 迁移到独立的高性能磁盘 /data/mysql-log,并配合合理的 MySQL 参数优化,可以显著降低系统盘 I/O 压力,提升数据库整体吞吐量。迁移过程中遇到权限或安全模块问题时,优先使用绑定挂载方案,或临时禁用 AppArmor 进行验证。迁移后应持续监控磁盘性能,必要时升级云盘类型。

相关推荐
天若有情6738 小时前
Python精神折磨系列(完整11集·无断层版)
数据库·python·算法
ictI CABL8 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
贺小涛8 小时前
VictoriaMetrics深度解析
java·网络·数据库
lingggggaaaa8 小时前
PHP原生开发篇&SQL注入&数据库监控&正则搜索&文件定位&静态分析
数据库·sql·安全·web安全·php
小羊在睡觉8 小时前
Go与MySQL锁:索引失效陷阱
数据库·后端·mysql·golang
Arva .8 小时前
索引下推ICP
mysql
givemeacar9 小时前
MySQL数据库误删恢复_mysql 数据 误删
数据库·mysql·adb
dllxhcjla9 小时前
苍穹外卖需要注意的地方
数据库·oracle
TlYf NTLE9 小时前
PostgreSQL的备份方式
数据库·postgresql