news 2026/5/30 18:15:41

MySQL Undo/Redo Log详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL Undo/Redo Log详解

一、核心概念对比

特性Redo LogUndo Log
主要目的保证事务的持久性保证事务的原子性和MVCC
写入时机事务进行中,数据修改前事务进行中,数据修改后
内容记录物理修改操作记录逻辑修改前的数据
存储方式顺序写入,循环覆盖随机写入,按需清理
生命周期事务提交后,数据刷盘后可清理事务提交后,但需保留至没有事务依赖
恢复方向前滚(redo)回滚(undo)
文件ib_logfile0, ib_logfile1ibdata1或独立表空间

二、Redo Log详细原理

1.物理结构

# 查看Redo Log配置 SHOW VARIABLES LIKE 'innodb_log%'; # 重要参数: # innodb_log_file_size = 每个文件大小(默认48M-2G) # innodb_log_files_in_group = 文件数量(默认2) # innodb_log_buffer_size = 缓冲区大小(默认16M)

2.写入流程(两阶段提交)

-- 示例:UPDATE users SET balance=200 WHERE id=1; 1. 内存阶段: - 修改Buffer Pool中的数据页 - 将修改记录写入Log Buffer 2. 准备阶段(Prepare): - Log Buffer中的Redo记录刷入Redo Log文件 - 此时Redo Log状态为"prepare" 3. 提交阶段(Commit): - Binlog写入完成 - Redo Log状态改为"commit" - 事务提交成功

3.Checkpoint机制

# Checkpoint过程示意 def checkpoint_process(): # 1. 找到最老的脏页LSN(Log Sequence Number) oldest_dirty_lsn = find_oldest_dirty_page() # 2. 将这个LSN写入Redo Log头 write_checkpoint_to_redo(oldest_dirty_lsn) # 3. 刷新脏页到磁盘 flush_dirty_pages_to_disk() # 4. 清理Redo Log空间 # 从checkpoint前的Redo Log可以安全覆盖

三、Undo Log详细原理

1.存储结构

-- Undo Log段管理 CREATE TABLE t ( id INT PRIMARY KEY, name VARCHAR(20), balance DECIMAL(10,2) ) ENGINE=InnoDB; -- Undo Log包含: -- 1. 回滚指针:DB_ROLL_PTR(指向旧版本) -- 2. 事务ID:DB_TRX_ID(最近修改的事务ID) -- 3. 删除标记:DELETED_BIT

2.版本链构建

# 数据行的版本链示意 当前行 (id=1, name='Alice', balance=100) ↓ roll_ptr Undo Log 1: (balance=50, trx_id=100) ← UPDATE操作前的版本 ↓ roll_ptr Undo Log 2: (name='Bob', trx_id=80) ← 更早的UPDATE ↓ roll_ptr NULL (初始版本)

3.MVCC实现

-- 读已提交(Read Committed)隔离级别下的可见性判断 SELECT * FROM users WHERE id=1; -- InnoDB判断流程: -- 1. 获取当前事务ID: current_trx_id -- 2. 获取当前活跃事务列表: active_trx_list -- 3. 从当前行开始遍历版本链: -- - 如果 trx_id < current_trx_id 且 trx_id不在活跃列表中 -- 且 trx_id <= up_limit_id(快照上限) -- - 则该版本对当前事务可见 -- 4. 否则继续查找更早版本

四、实际应用场景

场景1:银行转账事务

START TRANSACTION; -- 步骤1:A账户扣款 UPDATE accounts SET balance=balance-100 WHERE id=1; -- Undo Log记录: (balance=原始值, trx_id=当前事务) -- Redo Log记录: 页面修改信息 -- 步骤2:B账户入账 UPDATE accounts SET balance=balance+100 WHERE id=2; -- Undo Log记录: (balance=原始值, trx_id=当前事务) -- Redo Log记录: 页面修改信息 COMMIT; -- Binlog写入 → Redo Log状态改为commit

恢复场景

  • 如果在COMMIT前崩溃:

    • Redo Log处于prepare状态

    • 重启后根据Binlog决定是否提交

    • 使用Undo Log回滚未提交的修改

  • 如果在COMMIT后崩溃:

    • Redo Log为commit状态

    • 重启后重做已提交的事务

场景2:长事务问题

-- 危险的长时间查询 START TRANSACTION; SELECT * FROM large_table WHERE ... FOR UPDATE; -- 执行复杂业务逻辑(耗时10分钟) -- ... COMMIT; -- 问题: -- 1. Undo Log无法清理,导致undo表空间膨胀 -- 2. 阻塞Purge线程 -- 3. 可能触发“事务ID耗尽”问题

监控脚本

-- 监控长时间运行的事务 SELECT trx_id, trx_started, TIMEDIFF(NOW(), trx_started) AS duration, trx_state, trx_operation_state FROM information_schema.INNODB_TRX WHERE TIMEDIFF(NOW(), trx_started) > '00:05:00' ORDER BY trx_started; -- 监控Undo Log使用 SHOW ENGINE INNODB STATUS\G -- 查看"TRANSACTIONS"部分

场景3:批量数据处理优化

-- 错误的批量更新(产生大量Undo) START TRANSACTION; UPDATE large_table SET status=1 WHERE create_date < '2024-01-01'; -- 影响100万行,产生大量Undo Log COMMIT; -- 优化的批量更新 SET AUTOCOMMIT=0; SET UNIQUE_CHECKS=0; SET FOREIGN_KEY_CHECKS=0; -- 分批次处理 DECLARE done INT DEFAULT FALSE; DECLARE batch_size INT DEFAULT 1000; DECLARE last_id INT DEFAULT 0; REPEAT START TRANSACTION; UPDATE large_table SET status=1 WHERE id > last_id AND create_date < '2024-01-01' LIMIT batch_size; SET last_id = LAST_INSERT_ID(); COMMIT; -- 每个批次提交,释放Undo SELECT SLEEP(0.1); -- 避免过度消耗资源 UNTIL ROW_COUNT() = 0 END REPEAT; SET AUTOCOMMIT=1; SET UNIQUE_CHECKS=1; SET FOREIGN_KEY_CHECKS=1;

五、性能优化实战

1.Redo Log优化配置

# my.cnf配置示例 [mysqld] # Redo Log文件大小,建议设置为缓冲池的1/4到1/2 # 对于8G内存,Buffer Pool通常6G,Redo Log设为2G innodb_log_file_size = 2G innodb_log_files_in_group = 4 # 总大小=2G*4=8G # Log Buffer大小,大事务可适当调大 innodb_log_buffer_size = 64M # 刷盘策略,根据数据安全需求选择 # 1-最安全,每次提交都刷盘(默认) # 2-折中,每次提交写OS缓存,每秒刷盘 # 0-性能最好,每秒刷盘,可能丢失1秒数据 innodb_flush_log_at_trx_commit = 1

2.Undo表空间管理

-- MySQL 8.0+ 独立Undo表空间 -- 查看Undo配置 SELECT * FROM information_schema.INNODB_TABLESPACES WHERE SPACE_TYPE = 'Undo'; -- 监控Undo空间使用 SELECT tablespace_name, file_size / 1024 / 1024 AS file_size_mb, allocated_size / 1024 / 1024 AS allocated_mb FROM information_schema.FILES WHERE file_name LIKE '%undo%'; -- 设置Undo表空间自动清理 SET GLOBAL innodb_undo_log_truncate = ON; SET GLOBAL innodb_max_undo_log_size = 1 * 1024 * 1024 * 1024; -- 1GB SET GLOBAL innodb_purge_rseg_truncate_frequency = 128;

3.高并发写入优化

-- 场景:秒杀活动,大量并发写入 -- 问题:Redo Log成为瓶颈 -- 解决方案1:临时调整刷盘策略(活动期间) SET GLOBAL innodb_flush_log_at_trx_commit = 2; -- 活动结束后恢复为1 -- 解决方案2:组提交优化 -- MySQL已自动支持,确保参数合理 SHOW VARIABLES LIKE 'binlog_group%'; SHOW VARIABLES LIKE 'innodb_flush_log_at_timeout'; -- 解决方案3:拆分热点数据 -- 将热点账户分散到不同数据页 UPDATE account_001 SET ... WHERE user_id=1; -- 分表

六、故障恢复实战

场景:Redo Log损坏恢复

# 1. 检查Redo Log状态 mysql> SHOW ENGINE INNODB STATUS\G # 2. 如果有备份,优先使用备份恢复 # 使用Percona XtraBackup或mysqldump备份 # 3. 强制恢复模式(谨慎使用) # 在my.cnf中添加 [mysqld] innodb_force_recovery = 1 # 1-6,数字越大越激进 # 4. 恢复步骤 # 4.1 停止MySQL sudo systemctl stop mysql # 4.2 备份原数据文件 cp -r /var/lib/mysql /var/lib/mysql_backup # 4.3 移除损坏的Redo Log mv /var/lib/mysql/ib_logfile* /tmp/ # 4.4 启动MySQL(会自动创建新的Redo Log) sudo systemctl start mysql # 4.5 使用mysqlbinlog恢复未同步的数据 mysqlbinlog mysql-bin.000001 | mysql -u root -p

七、监控与维护脚本

-- 1. Redo Log监控 SELECT 'Redo Log' AS metric, CONCAT(ROUND(SUM(LENGTH)/1024/1024, 2), ' MB') AS current_size, CONCAT(ROUND(variable_value/1024/1024, 2), ' MB') AS configured_size, ROUND(SUM(LENGTH)*100/variable_value, 2) AS usage_percent FROM information_schema.INNODB_BUFFER_PAGE JOIN information_schema.GLOBAL_VARIABLES ON variable_name = 'innodb_log_file_size' WHERE PAGE_TYPE LIKE 'IBUF%' GROUP BY variable_value; -- 2. Undo空间监控 SELECT FORMAT_BYTES(SUM(current_size)) AS active_undo_size, FORMAT_BYTES(SUM(undo_size)) AS total_undo_size, COUNT(*) AS undo_segments, ROUND(SUM(current_size)*100/SUM(undo_size), 2) AS usage_pct FROM information_schema.INNODB_METRICS WHERE NAME LIKE '%undo%'; -- 3. 长事务和Undo关联查询 SELECT r.trx_id AS waiting_trx_id, r.trx_mysql_thread_id AS waiting_thread, TIMEDIFF(NOW(), r.trx_started) AS wait_time, b.trx_id AS blocking_trx_id, b.trx_mysql_thread_id AS blocking_thread, bl.lock_table AS locked_table FROM information_schema.INNODB_LOCK_WAITS w INNER JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id INNER JOIN information_schema.INNODB_LOCKS bl ON bl.lock_id = w.blocking_lock_id;

八、最佳实践总结

Redo Log优化:

  1. 大小配置:总大小 = Buffer Pool的25%-50%

  2. IO优化:使用SSD,单独磁盘存放Redo Log

  3. 监控告警:设置Redo Log切换频率告警(> 20次/小时需扩容)

Undo Log优化:

  1. 避免长事务:事务时间控制在5秒内

  2. 定期清理:启用innodb_undo_log_truncate

  3. 版本控制:及时提交只读事务,释放快照

通用建议:

  1. 定期备份:Redo Log不是备份,需配合Binlog和物理备份

  2. 压力测试:在高并发场景测试Redo/Undo配置

  3. 版本升级:MySQL 8.0在Undo管理上有显著改进

  4. 监控完备:使用Prometheus+Granafa监控Redo/Undo指标

故障预案:

  1. 保持Redo Log在独立磁盘

  2. 定期测试恢复流程

  3. 设置合理的innodb_force_recovery预案

  4. 重要业务开启双1配置(sync_binlog=1,innodb_flush_log_at_trx_commit=1

通过深入理解Redo和Undo Log的工作原理,可以更好地设计数据库架构、优化性能,并在故障时快速恢复,确保业务的连续性和数据的安全性。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/21 9:26:47

深度学习计算机毕设之基于python的鞋类分类

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/5/26 16:38:04

基于深度学习的杂草检测系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…

作者头像 李华
网站建设 2026/5/29 8:48:25

ABAQUS二维混凝土细观模型的数字化重建技术(二)图像映射

上篇文章介绍了基于图像进行混凝土细观模型的几何重构法&#xff0c;详细步骤可查看下面的连接。 ABAQUS二维混凝土细观模型的数字化重建技术(一)几何重构 本篇介绍二维混凝土细观模型在ABAQUS中数字化重建技术的第二种方法——基于ABAQUS背景网格的图像映射方法。混凝土图像…

作者头像 李华
网站建设 2026/5/29 17:23:13

后端开发提效10倍!别再手写CRUD接口了,试试这个API开发平台

做后端开发&#xff0c;我感觉至少有一半的时间&#xff0c;都在写那些重复、繁琐的 CRUD 接口。为每个数据模型都手写一套增删改查的逻辑&#xff0c;不仅枯燥&#xff0c;还极易出错。我一直在想&#xff0c;有没有一种方式能把开发者从这种重复劳动中解放出来&#xff1f;直…

作者头像 李华
网站建设 2026/5/15 1:59:12

计算机深度学习毕设实战-基于python深度学习的鲜花识别人工智能

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华