大家好,我是十三!欢迎来到十三Tech。

前几年一次故障——主库挂了切到从库,业务侧反馈"少了几条数据"。排查了一晚才搞明白:原主库的 binlog_formatSTATEMENT,切到从库时某些带 UUID()NOW() 的语句在从库重放出来跟主库不一致。后来强制把所有库的 format 改成 ROW,问题再没出现过。

这件事让我开始认真看 redo log 跟 binlog 的差别——两者长得太像(都是"日志"、都追加写、都循环利用?错,binlog 不循环),但定位完全不同。很多人讲 binlog 只讲"归档日志"——太浅。binlog 真正的角色是 MySQL 主从复制和数据恢复的"协议层"——它定义了主库怎么把变更告诉从库、备份工具怎么拿到一致快照。

这一篇就聊聊 binlog 跟 redo log 的三大差别、三种 format 各自的坑,以及为什么 8.0 默认 ROW。

binlog 跟 redo log 长得像但职责完全不同

一、binlog vs redo log — 三大差别

很多人混 redo log 和 binlog,因为名字里都有"log"。但它们属于不同层、做不同事。

差别一:层级归属不同。redo log 是 InnoDB 引擎层的日志;binlog 是 MySQL Server 层的日志——所有引擎共用。这就是为什么 MyISAM 没 redo log(崩溃易损)但有 binlog(能复制)。

差别二:日志内容不同。redo log 是物理日志——记录"某数据页某偏移改了什么",是页级别的二进制描述。binlog 是逻辑日志——记录"这条 SQL 改了什么"或"这一行变成了什么",是语句或行级别的描述。

差别三:写入方式不同。redo log 是循环写(固定大小、覆盖使用);binlog 是追加写(写满一个文件切下一个,永不覆盖)。这个差别决定了 redo log 只能用于"近期"崩溃恢复,binlog 能用于"任意时间点"的恢复——这就是 point-in-time recovery 的基础。

SHOW BINARY LOGS;   -- 看 binlog 文件列表(一直在增长)
SHOW MASTER STATUS; -- 看当前写到哪个文件、哪个位置

这三条差别解释了为什么 MySQL 同时需要两个日志——redo log 管"快"(顺序 IO 加速),binlog 管"全"(归档所有变更)。两者协作靠"两阶段提交"——下一篇详细讲。

binlog 跟 redo log 的三大差别

二、三种 format — STATEMENT / ROW / MIXED 各自的坑

binlog 记录什么内容,由 binlog_format 决定。三种取值,每种都有坑。

STATEMENT:记 SQL 原文。优点是日志小(一条 update 影响 1 万行也只记一句),缺点是不确定性函数会出问题——UUID()NOW()RAND()USER() 在主从上执行结果不同,会导致主从不一致。开头那个故障就是 STATEMENT 模式下 UUID() 在从库重放生成了新 UUID,跟主库对不上。

ROW:记每行的变更前后镜像(before image + after image)。优点是确定——主库改成什么样,从库就改成什么样,不存在函数重算问题。缺点是日志大——一条 UPDATE t SET status = 1 影响百万行,binlog 里就是百万条 row event。生产中 binlog 大小暴涨通常是 ROW 模式 + 大事务。

MIXED:MySQL 自己判断——能安全用 STATEMENT 的就用 STATEMENT,含不确定性函数的自动切 ROW。听起来美好,但判断规则复杂、行为不可预测——线上很难调试。8.0 之后官方基本不再推荐 MIXED。

-- 8.0 默认值
SHOW VARIABLES LIKE 'binlog_format';  -- ROW

为什么 8.0 默认 ROW:因为 ROW 是唯一能保证主从严格一致的 format。早期不用 ROW 是因为日志大、性能差,但现代硬件和 binlog 压缩(binlog_transaction_compression=ON)已经让 ROW 的代价小到可接受。新项目无脑选 ROW,老项目能迁就迁。

三种 format 的差别和坑

三、binlog 在主从复制和高可用里的角色

讲完 format,再说 binlog 真正的"用武之地"——主从复制和数据恢复。

主从复制的协议层。主库把变更写进 binlog,从库的 IO 线程拉取 binlog 写到自己的 relay log,SQL 线程读 relay log 重放——整套机制完全建立在 binlog 上。binlog 的格式决定了从库能多准确:ROW 严格一致、STATEMENT 可能漂移、MIXED 看运气。

异步 / 半同步复制。MySQL 默认异步——主库写完 binlog 就返回客户端,不等从库确认。这意味着主库挂了切从库,还没拉到 binlog 的事务会丢。半同步复制(rpl_semi_sync_master_enabled)让主库等至少一个从库确认收到 binlog 才返回——大幅降低丢失风险,代价是延迟增加。

数据恢复mysqlbinlog 工具能把 binlog 解析回 SQL 执行——配合全量备份,能恢复到任意时间点。生产中"误删数据"的标准恢复流程:还原昨晚全量备份 → 重放之后的 binlog 到误操作前一刻。

mysqlbinlog --start-datetime="2026-06-16 10:00:00" \
            --stop-datetime="2026-06-16 10:30:00" \
            mysql-bin.000123 | mysql -u root -p

GTID(Global Transaction ID)。5.6+ 引入,每条事务在 binlog 里有一个全局唯一 ID(server_uuid:seq)。GTID 让从库能精确知道自己复制到了哪个事务,主从切换不再依赖"文件名 + 位置"——大幅简化高可用。新项目必开 GTID

binlog 在主从复制和数据恢复里的角色

回头看那个主从切换故障——根因是 STATEMENT 模式下 UUID() 在从库重放不一致。切到 ROW 后,主库写入时记录的就是确定的 row 镜像,从库重放只是"复制粘贴",不可能漂移。

binlog 真正教会我的,不是"归档日志",而是它定义了 MySQL 复制生态的协议——主从、读写分离、备份恢复、高可用切换全都建立在 binlog 之上。选对 format 等于选对一致性等级。

下一篇讲两阶段提交——它解决一个看起来不可能的问题:redo log 和 binlog 是两个独立日志,怎么保证两者要么都写成功要么都不写?


关于十三Tech 资深服务端研发,AI 实践者,专注分享真实可落地的技术经验。 相信 AI 是程序员的最佳搭档。

联系方式:569893882@qq.com GitHub:@TriTechAI