本文介绍 MySQL 的几个重要的日志文件以及两阶段提交的原理。
binlog(二进制日志)
- binlog 是MySQL Server 层的逻辑日志,可以被所有存储引擎使用;
- binlog 日志常用于数据恢复、复制以及审计;
- binlog 可以是 ROW、 STATEMENT、MIXED 三种格式:
- ROW 格式下 binlog 日志记录的是每个数据行变化前和变化后的内容,因此占用空间相对较大;
- STATEMENT格式 下,binlog 日志记录的是执行的 SQL 语句;
- MIXED 格式下,默认采用 STATEMENT 格式,某些情况下会选择性地采用 ROW 格式;
- 仅凭 binlog 日志是不能确保MySQL crash-safe的;
- binlog日志是顺序追加写到磁盘文件,文件达到一定大小后会切换到下一个,因此不会发生数据覆盖;
- 重要主库推荐配置 sync_binlog=1 ,可以使得MySQL每次提交事务都会将binlog日志同步到磁盘上,保证服务器崩溃的时候不会丢失数据;此外,如果是 Innodb 引擎,还需要配置 innodb_support_xa 为 1,才能确保二进制日志与 InnoDB 存储数据文件的同步(也就是下文的两阶段提交确保不丢失数据)。
redo log(重做日志)
redo log是InnoDB引擎特有的物理日志;
WAL 技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘数据;
redo log记录的是某个数据页做了什么修改;
凭借redo log可以确保InnoDB的crash-safe;凭借redo log和binlog实现的两阶段提交可以保障MySQL的crash-safe;
redo log日志是固定大小的循环写,超过文件大小会擦除老日志;
重做日志并不是直接写日志文件,而是先写一个重做日志缓冲(redo log buffer),然后再按照一定条件顺序写入日志文件。常见条件包括:
- 主库配置 innodb_flush_log_at_trx_commit=1 ,可以使得每次提交事务都会将 buffer 刷到日志文件,保证服务器崩溃的时候不会丢失数据;
- 主线程每秒会将重做日志缓冲写入日志文件,不论事务是否已经提交。
undo log (回滚日志)
- 回滚日志记录的是事务的行为,当事务由于某种原因执行失败或者用户手动回滚的时候,便可以通过回滚日志来恢复缓冲池数据至历史版本;
- 回滚日志默认保存在共享表空间中(也就是 ibdata 文件中);如果配置了 innodb_undo_tablespaces=N,则会保存到单独的undo001~undoN 文件中;
两阶段提交
两阶段提交过程:
- 1.新数据更新到内存;
- 2.新数据写入redo log,并处于prepare状态;
- 3.写入binlog;
- 4.提交事务,使redo log 更新为commit状态。
crash-safe保障原理:
- 如果在步骤2之前数据库宕机,因为redo log 和binlog都没写入,内存数据丢失,所以不影响一致性;
- 如果在步骤3之前数据库宕机,因为redo log存在且处于prepare状态,但检查binlog发现不存在,则回滚事务。所以不影响数据一致性;
- 如果在步骤4之前数据库宕机,因为redo log存在且处于prepare状态,而检查binlog发现存在,则执行步骤4。所以事务成功,也不影响数据一致性;
- 如果在步骤4之后数据库宕机,因为redo log存在且处于commit状态。所以不影响数据一致性。
binlog和redo log的联系:
它们有一个共同的数据字段,叫XID。崩溃恢复的时候,会按顺序扫描redo log:如果碰到commit状态的redo log,就直接提交;如果碰到只有 parepare状态的redo log,就拿着XID去binlog找对应的事务。
延伸阅读
- MySQL实战45讲: 非常适合入门的MySQL学习资料;
- 《高性能MySQL》
- 《MySQL技术内幕(InnoDB存储引擎)》
- 浅谈参数innodb_undo_tablespaces
- MySQL 5.7新特性之在线收缩undo表空间
- 分布式理论(三) - 2PC协议
- 05 | 分布式事务:如何保证多个系统间的数据是一致的?
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 duval1024@gmail.com