知其然要知其所以然,探索每一个知识点背后的意义,你知道的越多,你不知道的越多,一起学习,一起进步,如果文章感觉对您有用的话,关注、收藏、点赞,有困惑的地方请评论,我们一起交流!
1. 核心功能与定位
Binlog(二进制日志)
- 定位 :MySQL Server层实现,所有存储引擎通用。
- 功能 :
- 主从复制:从库通过重放主库的binlog实现数据同步。
- 数据恢复:支持基于时间点(PITR)或位置的恢复。
- 逻辑日志 :记录数据库的逻辑操作(如SQL语句或行变更事件)。
- 格式 :
- Statement :MySQL 5.6 及之前版本默认使用此格式,记录原始SQL语句。
- Row : MySQL 5.7 及之后版本默认使用此格式,因为有些 statement 格式的 binlog 可能会导致主备不一致,所以要使用 row 格式,但 row 格式的缺点是,很占空间。比如你用一个 delete 语句删掉 10 万行数据,用 statement 的话就是一个 SQL 语句被记录到 binlog 中,占用几十个字节的空间。但如果用 row 格式的 binlog,就要把这 10 万条记录都写到 binlog 中。这样做,不仅会占用更大的空间,同时写 binlog 也要耗费 IO 资源,影响执行速度。
- Mixed:混合模式,MySQL 自己会判断这条 SQL 语句是否可能引起主备不一致,如果有可能,就用 row 格式,否则就用 statement 格式,mixed 格式可以利用 statment 格式的优点,同时又避免了数据不一致的风险。
Redo Log(重做日志)
- 定位 :InnoDB存储引擎特有,物理日志。
- 功能 :
- 崩溃恢复:确保事务的持久性(ACID中的D)。
- Write-Ahead Logging (WAL):事务提交时先写日志,再异步刷脏页到数据文件。
- 物理日志 :记录数据页的物理修改(如页号、偏移量、修改内容)。
- 结构 :
- 循环写入 :固定大小文件组(
ib_logfile0
、ib_logfile1
)。 - LSN(Log Sequence Number):唯一标识日志位置,用于恢复和同步。
- 循环写入 :固定大小文件组(
2. 写入时机与流程
事务提交过程(两阶段提交,2PC)
-
Prepare阶段:
- InnoDB将事务的redo log写入内存(
redo log buffer
)并刷盘(innodb_flush_log_at_trx_commit
控制)。 - 标记redo log状态为
prepare
。
- InnoDB将事务的redo log写入内存(
-
Binlog写入:
- Server层生成binlog事件并写入文件(
sync_binlog
控制刷盘策略)。
- Server层生成binlog事件并写入文件(
-
Commit阶段:
- InnoDB将redo log标记为
commit
状态。 - 事务正式提交,释放锁资源。
- InnoDB将redo log标记为
崩溃恢复流程
- 扫描redo log :找到所有
prepare
状态的日志。 - 检查binlog:若对应事务的binlog完整,则重放redo log提交事务;否则回滚。
3. 核心差异对比
维度 | Binlog | Redo Log |
---|---|---|
实现层 | MySQL Server层 | InnoDB存储引擎层 |
日志类型 | 逻辑日志(操作记录) | 物理日志(数据页修改) |
用途 | 主从复制、数据恢复 | 崩溃恢复、事务持久性 |
写入时机 | 事务提交后 | 事务进行中(WAL机制) |
生命周期 | 可配置保留策略(按时间/大小滚动) | 循环覆盖写入 |
依赖关系 | 依赖存储引擎提交事务 | 独立于binlog,但需协同保证一致性 |
4. 协作机制:两阶段提交(2PC)
目的
确保binlog和redo log的原子性,避免以下问题:
- 数据不一致:事务在binlog中存在但未提交(或反之)。
- 主从复制分歧:主库事务提交但从库未应用。
流程详解
-
Prepare阶段:
- InnoDB写redo log并刷盘,标记为
prepare
。
sql# redo log entry示例 LSN=1000 | TRX_ID=200 | STATE=PREPARE | PAGE=5 | OFFSET=120 | DATA='Alice'
- InnoDB写redo log并刷盘,标记为
-
Write Binlog阶段:
- MySQL Server写binlog并刷盘。
sql# binlog entry示例(ROW格式) UPDATE users SET name='Alice' WHERE id=1;
-
Commit阶段:
- InnoDB写redo log的
commit
标记。
sqlLSN=1000 | TRX_ID=200 | STATE=COMMIT
- InnoDB写redo log的
崩溃恢复逻辑
- Case 1:binlog存在且完整 → 提交事务(重放redo log)。
- Case 2:binlog不存在或损坏 → 回滚事务。
5. 配置与优化
Binlog优化
-
格式选择 :优先使用
Row
格式,避免主从不一致。inibinlog_format = ROW
-
刷盘策略 :平衡性能与一致性。
inisync_binlog = 1 # 每次提交刷盘(高一致) sync_binlog = 0 # 依赖OS刷盘(高性能)
-
日志保留 :
iniexpire_logs_days = 7 # 自动清理旧日志
Redo Log优化
-
文件大小 :增大日志减少切换频率。
iniinnodb_log_file_size = 4G # 单文件大小 innodb_log_files_in_group = 2 # 文件数量
-
刷盘控制 :
iniinnodb_flush_log_at_trx_commit = 1 # 每次提交刷盘(ACID) innodb_flush_log_at_trx_commit = 2 # 提交时写入OS缓存(折衷)
6. 应用场景
Binlog场景
-
主从复制 :从库通过
mysqlbinlog
解析并应用变更。 -
数据恢复 :通过
mysqlbinlog
工具按时间点恢复。bashmysqlbinlog --start-datetime="2023-10-01 00:00:00" binlog.000001 | mysql -u root -p
Redo Log场景
- 崩溃恢复:数据库重启时自动重放未落盘的修改。
- 性能优化:通过合并随机写为顺序写,提升事务提交速度。
7. 常见问题与解决方案
Q1:为何需要两个日志?
- Binlog:跨引擎、可读的逻辑日志,支持复制和恢复。
- Redo Log:引擎层物理日志,保障事务持久性和崩溃恢复效率。
Q2:如何避免日志成为性能瓶颈?
- Binlog :启用组提交(
binlog_group_commit_sync_delay
)。 - Redo Log:增大日志文件,优化刷盘策略。
Q3:误删数据如何恢复?
- 使用binlog找到误删操作的Pos或时间点。
- 导出相关binlog事件并跳过误删操作。
- 重放修正后的binlog到数据库。
总结
- Binlog 是MySQL的"操作记录仪",用于逻辑复制和恢复;Redo Log是InnoDB的"安全气囊",确保事务持久性和崩溃恢复。
- 两者通过两阶段提交协同工作,保障数据一致性。理解其机制对配置高可用架构、优化性能和处理故障至关重要。