日志体系
MySQL为了满足主从复制、事务等,有复杂的日志体系。
MySQL的日志体系不是主要不是用来看的,而是运行必要的。
日志的种类有:
- Server层产生binlog,用来进行数据复制
InnoDB产生undo log、redo log,用来实现事务ACID
binlog 归档日志
Binlog是server层产生的逻辑日志
- 用来进行数据复制和数据传送
- Binlog完整记录了数据库每次的数据操作,可作为数据闪回手段
-
undo log 回滚日志
lnnoDB自身产生的逻辑日志,用于事务回滚和展示旧版本
- 对任何数据(缓存)的更新,都先写undo log
- undo log位于表空间的undo segment中
SQL: UPDATE name = ‘b’ → undo: UPDATE name = ‘a’
- 需要把表数据的name字段改为’b’, 原始表中数据name字段为 ‘a’
- undo log 就是记录与执行SQL相反的日志,如果语句执行失败,
执行这条回滚SQL数据即可恢复到事务初始状态redo log重做日志
在 MySQL 中,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。为了解决这个问题,MySQL 的设计者就采用了日志(redo log)来提升更新效率。
而日志和磁盘配合的整个过程,其实就是 MySQL 里的 WAL 技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘。
具体来说,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log(redolog buffer)里面,并更新内存(buffer pool),这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候(如系统空闲时),将这个操作记录更新到磁盘里面(刷脏页)。
Redo log日志相当于笔记本的临时记录功能,每次写数据到数据库不是直接写到数据库,因为可能来不及,先临时记录到Redo log日志中,就标记已经完成了数据的写入操作,只要写入了Redo log,数据早晚会写入到磁盘中。
InnoDB自身产生的物理日志,记录数据页的变化
- InnoDB“日志优先于数据”,记录redo log视为数据已经更新
- 内存中的数据更新后写redo log,数据被写入硬盘后删除
- redo log储存在4个1GB文件中,并且循环写入
- write pos是当前日志写入点
- check point是擦除点,数据被更新到硬盘时擦除
- 物理上4个文件不相连,逻辑上4个文件连在一起。
- 当write pos追上check point时,事务无法提交,需要等待check point推进。
- 只要redo log不丢,数据就不会丢失
数据更新流程
两阶段提交
MySQL 使用两阶段提交主要解决 binlog 和 redo log 的数据一致性的问题。
redo log 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。下图为 MySQL 二阶段提交简图:
两阶段提交原理描述:
- InnoDB redo log 写盘,InnoDB 事务进入 prepare 状态。
- 如果前面 prepare 成功,binlog 写盘,那么再继续将事务日志持久化到 binlog,如果持久化成功,那么 InnoDB 事务则进入 commit 状态(在 redo log 里面写一个 commit 记录)
备注: 每个事务 binlog 的末尾,会记录一个 XID event,标志着事务是否提交成功,也就是说,recovery 过程中,binlog 最后一个 XID event 之后的内容都应该被 purge。
redo log 刷盘参数控制
innodb_flush_log_at_trx_commit参数控制redo log刷盘,默认为1
- 0:异步每秒刷盘
- 1:每1个事务刷盘
- N:每N个事务刷盘
bin log 刷盘参数控制
sync_binlog参数控制binlog刷盘,默认为1
- 0:自动控制刷盘
- 1:每1个事务刷盘
- N:每N个事务刷盘
持久化分析
redo log刷盘前系统崩溃:
- 数据丢失,客户端事务提交不成功会进行重试
redo log刷盘后系统崩溃:
重启时会对redo log进行重放、重写内存中数据页、重写bin log
为什么redo log写在bin log之前
redo log是系统关键节点,相当于“决断点”
- binlog一旦写入无法撤回,因为可能已经被传送至备库,
如果写在redo log之前,会造成主从数据不一致