https://chat.deepseek.com/share/qqd90q46mjuo1u83z7
https://chat.deepseek.com/share/a9kmt38uvs96rx1dkp
题目:一次insert操作,MySQL的几种log的写入顺序?
难度:medium
标签:db/mysql/log, mysql/log, difficulty/medium
评分:⭐⭐☆☆☆(2/5)
几种日志的写入顺序,首先会涉及事务,创建重试日志,也是 Redo log。Redo log 进行创建,然后进行提交,防止事务的事件出现服务器崩溃,用来做重试。然后创建 Undo log,Undo log 去确保整个事务进行,如果事务出现问题进行回滚。然后这些都完成,最终要写 binlog 用来进行数据同步。
优点:
不足:
innodb_flush_log_at_trx_commit(redo 刷盘策略,默认 1)sync_binlog(binlog 刷盘策略,默认 1)补充:
innodb_flush_log_at_trx_commit=1 + sync_binlog=1:双 1,最安全,性能最低innodb_flush_log_at_trx_commit=1 + sync_binlog=0:redo 落盘 binlog 依赖 OS,可容忍 binlog 丢失innodb_flush_log_at_trx_commit=2 + sync_binlog=1:redo 依赖 OS 缓存,可容忍 redo 丢失innodb_flush_log_at_trx_commit=0 + sync_binlog=0:靠 OS 周期刷盘,最快但风险高核心考点定位:理解 MySQL 三种日志的分工与两阶段提交协议,掌握事务提交时的完整执行链路。
知识点拆解:
innodb_flush_log_at_trx_commit:控制 redo log 刷盘策略0:事务提交只写 redo buffer,每秒由后台线程刷到磁盘(最快,可能丢 1 秒数据)1:每次事务提交都 fsync redo log 到磁盘(最安全)2:每次事务提交写 OS 文件缓存,每秒 fsync(折中,OS 崩溃可能丢)sync_binlog:控制 binlog 刷盘策略0:依赖 OS 周期刷盘(最快,可能丢)1:每次事务提交都 fsync binlog 到磁盘(最安全)srv_purge_workers,8.0 多 worker)异步清理:条件是 undo 版本没有被任何活跃事务的 ReadView 使用ibdata1 或 undo_001 无限增长,排查:information_schema.innodb_trx 找长事务innodb_max_undo_log_size(8.0.22+)超过阈值会尝试清理innodb_log_files_in_group + innodb_log_file_size(如 2 个 5GB)innodb_redo_log_capacity 统一管理,支持动态调整InnoDB: Log scan aborted)SHOW ENGINE INNODB STATUS 看 Log sequence number 和 Last checkpoint at 差值NOW()、UUID())innodb_flush_log_at_trx_commit=2 + 宕机:redo 只写 OS cache 未 fsync,OS 缓存丢失导致数据丢失sync_binlog=0 + kill -9:binlog 依赖 OS 刷盘,进程被 kill 时 OS 缓冲区可能丢考察方向:
延伸递进面试题:
innodb_flush_log_at_trx_commit=1 的性能开销有多大?information_schema.innodb_trx 找长事务;SHOW ENGINE INNODB STATUS 看 history list length;kill 长事务或提交/回滚;检查 innodb_purge_threads 是否够。面试官您好,我按"三种日志的分工 + 两阶段提交"来讲。
三种日志分工。redo log 是 InnoDB 内部的重做日志,记录修改后的状态,用于崩溃恢复;undo log 是 InnoDB 内部的回滚日志,记录修改前的状态,用于事务回滚和 MVCC;binlog 是 Server 层的日志,记录所有 DML/DDL 事件,用于主从复制和 PITR 时间点恢复。关键点:redo 和 undo 都在 InnoDB 内部,binlog 在 Server 层,跨层协调需要 2PC。
一次 insert 的完整顺序。第一步,SQL 到 Server 层解析、走执行计划。第二步,进入 InnoDB,先生成 undo log 记录修改前状态。第三步,改 Buffer Pool 里的内存页,注意此时未落盘。第四步,写 redo log buffer 记录修改后状态。第五步,事务提交时触发 2PC——先写 binlog buffer,然后 binlog write 到 binlog cache 文件,再 binlog flush 到 OS 文件缓存,此时 binlog 处于 prepare 状态。第六步,InnoDB 写 redo log 的 commit 标记并 fsync 到磁盘,这是 redo log commit。第七步,binlog 才真正 commit,fsync 到磁盘。
为什么需要 2PC。redo 和 binlog 各自独立落盘的话,会出现"redo 已 commit 但 binlog 未落盘"的中间态,崩溃后从库无法同步、PITR 也丢数据。2PC 保证两者原子——要么都成功要么都失败。崩溃恢复决策很简单:看 binlog 状态,prepare 就看 redo log 是否 commit,commit 就补写 binlog commit,未 commit 就回滚。
刷盘参数这块特别关键。innodb_flush_log_at_trx_commit 控制 redo,sync_binlog 控制 binlog,两个都设 1 就是双 1,最安全但性能最低。生产上金融、交易类坚持双 1;日志、埋点类可以放宽到 (1, 0) 或 (2, 1) 换性能。SSD 上单次 fsync 约 1ms,写入 IOPS 上限受 fsync 频率限制,所以 MySQL 用组提交(binlog group commit + redo group commit)合并 fsync,能提升 5-10 倍吞吐。
再补两个容易忽略的点。undo log 提交后不会立即清理,靠 Purge 线程异步清理,条件是没有活跃事务的 ReadView 使用它;一旦有个长事务持 ReadView,purge 就阻塞,undo tablespace 会膨胀到爆盘——这个坑我踩过,排查方法是 innodb_trx 找长事务,然后 kill 掉。redo log 是循环写的,默认两个 5GB,如果写入太快 checkpoint 跟不上,会强制 flush Buffer Pool 到磁盘,性能骤降,InnoDB: Log scan aborted 就是这个信号,需要调大 innodb_log_file_size。
当然,binlog 格式生产一律用 ROW 格式,避免 STATEMENT 里的 NOW()、UUID() 之类函数导致主从不一致。