MySQL的“家庭账本”大揭秘:Redo、Undo、Binlog,到底谁在记谁的烂账?
💸 MySQL的“家庭账本”大揭秘:Redo、Undo、Binlog,到底谁在记谁的烂账?
面试翻车现场还原 🎬:
面试官:“Redo Log和Binlog有啥区别?”
我(自信满满):“一个物理日志,一个逻辑日志呗!”
面试官(微微一笑):“那为啥非得弄俩?一个不够用吗?”
我(CPU当场烧毁):“啊这……” 🤯
别慌!今天咱们就扒开MySQL的底裤(不是),聊聊这三本“账”到底各管啥,平时是怎么暗中勾结……啊不,默契配合的!
先上张“全家福”镇镇场子 👇
| 日志 | 层级 | 记录内容 | 核心作用 |
|---|---|---|---|
| Redo Log | InnoDB引擎层 | 物理日志(页级修改) | 崩溃恢复、持久性 |
| Undo Log | InnoDB引擎层 | 逻辑日志(旧值/反向操作) | 事务回滚、MVCC |
| Binlog | Server层 | 逻辑日志(SQL/行变更) | 主从复制、时间点恢复 |
🔄 Redo Log:数据库的“防猝死保险箱”
这哥们儿干啥的?就一句话:只要事务敢提交,数据就绝对不背锅! 哪怕服务器半夜突然拔电源、原地去世,它也能把数据从ICU里抢救回来(持久性 Durability 拿捏了 ✅)。
它靠啥绝活?WAL机制(Write-Ahead Logging,预写日志)!
- 🐢 以前老实巴交的做法:改数据 → 吭哧吭哧直接写硬盘(随机IO,慢得像老牛拉车)。
- ⚡ 现在的骚操作:改数据 → 先唰唰记到Redo Log里(顺序IO,快如闪电)→ 剩下的交给后台慢慢刷盘。
核心心法:能用顺序写糊弄过去的,绝不用随机写硬刚!性能直接起飞 10~100 倍 🚀。
Redo Log 长啥样?
刷盘策略:要命还是要钱?(innodb_flush_log_at_trx_commit)
这参数就是你的“安全/性能”滑块,自己掂量着办:
| 值 | 行为 | 安全性 | 性能 |
|---|---|---|---|
| 1 (默认) | 每次提交都fsync刷盘 | 最高(最多丢1个事务) | 最低 |
| 2 | 写OS缓存,每秒刷盘 | 中(OS崩溃丢1秒) | 高 |
| 0 | 每秒写OS缓存并刷盘 | 低(MySQL崩溃丢1秒) | 最高 |
💡 老鸟掏心窝子建议:
- 💰 金融/核心交易库:乖乖填
1,安全第一,丢了数据老板能把你吃了 🦖。 - 🛒 普通业务库:填
2,性价比之王,偶尔丢1秒数据无伤大雅。 - 📊 日志/分析库:填
0,性能拉满,数据丢了就当给青春买个教训(bushi)。
崩溃恢复流程(MySQL的“复活赛”机制)
- 🕵️♂️ Analysis(案发现场勘查):先找上次Checkpoint(安全存档点)在哪。
- 🔁 Redo(时光倒流重放):从存档点开始,把已提交的事务再跑一遍。
- 🔄 Undo(后悔药时间):没提交完的?直接打回原形!
📌 划重点:Redo只保“交过钱的”,没交完的烂摊子,得靠Undo来擦屁股。
📝 Undo Log:程序员的“时光后悔药” 💊
干啥的?保原子性(Atomicity)!事务要么全部成功,要么全部当没发生过。手滑改错数据?没关系,Undo Log就是那个能大喊“回到过去!”的时光机 ⏳。
咋工作的?举个栗子 🌰:
UPDATE t SET name='李四' WHERE id=1; -- 原来叫'张三'
Undo Log会偷偷记下一笔:id=1 的旧值是 '张三'。一旦你喊“撤销”,它立马把李四踹下去,把张三请回来 👑。
不仅如此,MVCC(多版本并发控制)也得靠它撑腰!你查数据时看到的“历史版本”,其实就是Undo Log里攒的旧账本。
存储与清理:垃圾是放错位置的财富,但Undo不是 🗑️
💣 你可能踩过的“天坑”:
- 🚨 Undo表空间突然胖成猪? 十有八九是长事务赖着不走,阻塞了Purge线程,旧数据清不掉!赶紧去查
information_schema.innodb_trx,把那个摸鱼的长事务一刀砍了 🔪。 - 🌟 MySQL 8.0 的福音:支持动态Undo表空间了!还能自动瘦身(
innodb_undo_log_truncate=ON),妈妈再也不用担心我磁盘被塞爆啦~
📡 Binlog:数据库界的“行车记录仪” 🚗
这货是Server层的大总管,纯逻辑日志。你干的每一笔“修改操作”,它都拿个小本本记下来。主要干三件事:
- 📡 主从复制:主库干啥,从库跟着干,Binlog就是那个传声筒。
- ⏱ 时间点恢复(PITR):误删库了?别慌,用Binlog倒带回到删库前1分钟,还能抢救!
- 👮 审计背锅:谁在半夜乱改数据?Binlog一出,直接甩锅现场。
三种格式,选哪个好?🤔
格式选择就像挑对象,没有最好,只有最合适:
| 格式 | 记录内容 | 优点 | 缺点 | 现状 |
|---|---|---|---|---|
| STATEMENT | 原始SQL | 体积小 | 函数/存储过程可能不一致 | 已淘汰 |
| ROW (默认) | 行级变更 | 精确一致 | 体积大(批量UPDATE膨胀) | 推荐 ✅ |
| MIXED | 自动切换 | 兼顾 | 行为不可预测 | 别用 🙅♂️ |
💡 闭眼选指南:无脑选 ROW!现在都2024年了,STATEMENT早该进博物馆了。
刷盘策略(sync_binlog):8.0 默认直接给到 1,主打一个“宁可错杀一千,绝不放过一个数据”的安全感。
| 值 | 行为 | 安全性 |
|---|---|---|
| 1 (8.0默认) | 每次提交fsync | 最高 ✅ |
| 0 | OS控制刷盘 | 可能丢数据 ⚠️ |
| N | 每N次提交刷盘 | 平衡 ⚖️ |
🔗 两阶段提交(2PC):Redo和Binlog的“联姻协议” 💍
灵魂拷问:这俩要是各写各的,崩了咋整?
- 🎬 场景1:Redo写完了,Binlog没写 → 崩溃重启后,主库数据回来了,但从库一脸懵:“我咋啥也没收到?” 👉 主从不一致!
- 🎬 场景2:Binlog写完了,Redo没写 → 崩溃重启后,主库数据没了,但从库已经同步了 👉 数据直接分裂!
怎么办?上2PC(Two-Phase Commit)大法! 就像结婚,得先订婚(Prepare),再领证(Commit),缺一步都不行。
崩溃恢复时,MySQL的“断案逻辑”:
- 🔍 情况1:Redo带COMMIT,Binlog也有记录 → 没事了,散会 🍵。
- 🔍 情况2:Redo还在PREPARE,但Binlog已经有了 → 别磨叽了,赶紧补个COMMIT,人家早就生米煮成熟饭了。
- 🔍 情况3:Redo在PREPARE,Binlog查无此人 → 直接ROLLBACK!这婚没结成,赶紧分手 💔。
🛠 抄作业区:生产环境怎么配?📝
别瞎调了,直接对号入座:
💡 记住,没有银弹,只有“合适”。金融库敢用Level 3,CTO能顺着网线过来打你 👊。
🚑 急诊室:日志相关疑难杂症怎么治?
| 现象 | 根因 | 排查命令 |
|---|---|---|
| ibdata1 持续膨胀 | 长事务阻塞Undo Purge | SELECT * FROM information_schema.INNODB_TRX |
| 主从延迟突增 | Binlog大事务或 sync_binlog=1 瓶颈 | SHOW PROCESSLIST |
| 磁盘IO打满 | Redo Log太小导致频繁Checkpoint | SHOW ENGINE INNODB STATUS |
遇到这些情况别慌,按方抓药,药到病除 💉。
🎯 说人话总结(建议背诵全文 📖)
| 日志 | 本质 | 核心作用 | 调优重点 |
|---|---|---|---|
| Redo | 物理变更的 "保险箱 " | 崩溃恢复 | Checkpoint频率、fsync策略 |
| Undo | 历史状态的 "时光机 " | 回滚、MVCC | 事务时长、Purge线程 |
| Binlog | 数据流动的 "记录仪 " | 复制、恢复 | 格式选择、sync策略 |
🔑 核心就三句口诀:
- Redo和Binlog靠2PC“拜把子”,缺一不可;
- Undo不光能后悔,还是MVCC的“亲爹”;
- 日志配置别死磕“最强”,看你的业务能扛多大事儿!
🙋 唠点实在的
你在生产环境被日志坑过没?是Undo表空间胖到报警?还是主从复制因为Binlog吵架?或者Redo Log配错导致IO打满,老板在群里疯狂@你?🤯
👇 评论区吐吐槽、支支招,咱们抱团取暖~
觉得这篇“防脱发指南”有点用?点赞👍 + 收藏❤️,就是对笔者最大的投喂!
下期想盘啥?主从复制延迟?还是慢SQL优化?留言区点单,我来下厨 🍳~
📌 注:本文技术细节基于 MySQL 5.7.40 / 8.0.35 实测。生产环境千变万化,请以实际版本+压测为准,别盲目复制粘贴哦~
📚 延伸阅读:《MySQL技术内幕:InnoDB存储引擎》、MySQL官方文档、Percona Blog(大佬们常逛的后花园)
更多推荐


所有评论(0)