一、MySQL日志文件类型
- 重做日志(redo log)
- 回滚日志(undo log)
- 二进制日志(binlog)
- 错误日志(errorlog)
- 慢查询日志(slow query log)
- 一般查询日志(general log)
- 中继日志(relay log)
其中,比较重要的包括 redo log 、 undo log 和 binlog。
redo log 是重做日志,提供前滚操作;undo log 是回滚日志,提供回滚操作。
二、几种日志的对比
2-1、用途
redo log
确保事务的持久性。
如果在发生故障的时间点(比如系统宕机),尚有数据未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达保证事务的持久性。
undo log
首先明确undo log绝对不是redo log的逆过程。它可以保存事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制(MVCC)下的读。
binlog
1. 用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。
2. 用于数据库的基于时间点的还原。
2-2、存储内容、格式
redo log
物理格式的日志,记录的是物理数据页面的修改的信息(数据库中每个页的修改),面向的是表空间、数据文件、数据页、偏移量等。
undo log
逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,与redo log不同。
binlog
逻辑格式的日志,可以简单认为就是执行过的事务中的sql语句。
但又不完全是sql语句这么简单,而是包括了执行的sql语句(增删改)反向的信息。比如delete操作的话,就对应着delete本身和其反向的insert;update操作的话,就对应着update执行前后的版本的信息;insert操作则对应着delete和insert本身的信息。
因此可以基于binlog做到闪回功能。
2-3、日志生成
redo log
事务开始之后就产生redo log,redo log的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中就开始写入。在发出事务提交指令时,先保证缓存中的redo log写入完毕,才执行提交动作。
undo log
事务开始之前,根据当前版本的数据生成undo log;产生undo日志的时候,同样会伴随类似于保护事务持久化机制的redo log的产生。
binlog
事务提交的时候,一次性将事务中的所有sql语句按照一定的格式记录到binlog中。
这里与 redo log 相比最明显的差异就是redo log 在事务开始之后就开始逐步写入磁盘。
2-4、删除策略
redo log
当对应事务的数据写入完成(持久化完成)之后,redo log的使命也就完成了,日志占用的空间就可以重用(redo log的日志文件是循环写入的)。
undo log
事务提交之后,undo log并不会马上被被删除,而是放入待清理的链表。由purge线程判断是否由其他事务在使用undo段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志空间。
binlog
binlog的日志文件是追加写入,也就是文件写到一定大小以后会切换到下一个,不覆盖原有记录。不过同时binlog的默认行为是,对于非活动的日志文件,在生成时间超过expire_logs_days配置的天数之后,会被自动删除。
2-5、redo log 与 binlog 的区别
- 作用不同:redo log是保证事务的持久性的,是事务层面的——是innodb层产生的;binlog作为还原的功能,是数据库层面的。保护数据的层次是不一样的。
- 内容不同:redo log是物理日志,是数据页面的修改之后的物理记录;binlog是逻辑日志,可以简单认为记录的是sql语句。
- 关于恢复数据的效率:基于物理日志的redo log恢复效率要高于语句逻辑日志的binlog。
三、两阶段提交
redo log 保证的是数据库的 crash-safe 能力。采用的策略就是常说的“两阶段提交”。
一条update的SQL语句是按照这样的流程来执行的:
将数据页加载到内存 → 修改数据 → 更新数据 → 写redo log(状态为prepare) → 写binlog → 提交事务(数据写入成功后将redo log状态改为commit)
只有当两个日志都提交成功(刷入磁盘),事务才算真正的完成。
一旦发生系统故障(不管是宕机、断电、重启等等),都可以配套使用 redo log 与 binlog 做数据修复。
binlog状态 | redo log 状态 | 对策 |
---|---|---|
有记录 | commit | 事务已经正常完成 |
有记录 | prepare | 在binlog写完、提交事务之前发生故障。此时数据完整。恢复策略:提交事务 |
无记录 | prepare | 在binglog写完之前发生故障。恢复策略:回滚 |
无记录 | 无记录 | 在写redo log之前发生故障。恢复策略:回滚 |
补充:
1. 3种日志对比
二进制日志bin log仅在事务提交时记录,一对一,每一个事务仅包含对应事务的一个日志。
重做日志redo log记录的是物理操作日志,一对多,每个事务对应多个日志条目,并且事务的重做日志写入是并发的,并非在事务提交时写入,故其在文件中记录的顺序并非是事务开始的顺序。*T1、*T2、*T3表示的是事务提交时的日志。
2. binlog二进制 逻辑
2.1 what
逻辑日志,是由mysql上层产生,无论采用什么存储引擎都会有。
由两种格式,Statment格式、ROW格式和Mixed格式
格式 样例
Statment
存储sql
update table set a='aa' where id=52;
ROW格式
每行数据地 修改前后地每个字段地值mysqlbinlog解析如下
如图,包含一行数据的修改前后的值,达到误操作后进行恢复的目的
Mixed格式
2.2 how文件写入
binlog是追加写,不会覆盖;当文件满了,就创建新的binlog文件,index递增,循环写入
3. redo log 重做日志 物理
重做日志主要用于宕机恢复,在事务提交前一定会写入到重做日志,但数据不一定持久化到了数据页。
Write-Ahead Logging:先写日志,再写磁盘,更新数据时数据行可能是没有及时修改的;这么做是为了提高性能,因为数据行比较分散,写入文件可能要重新磁盘寻址影响性能;
而重做日志是顺序读写,没有了最耗时地磁盘寻址;当事务提交后如果发生宕机,此时数据是未持久化地,重启后可以根据重做日志进行恢复,保障了事务的持久性。
what:
记录页的修改
日志类型有插入、删除等51种,以插入、删除为例,他们的格式如下,
插入语句记录了哪个表空间、哪一页、哪个偏移下需要存放rec body这一行。
删除语句记录表空间、哪一页、哪个偏移的行是需要删除的。
文件写入
多个重做日志文件循环写,会覆盖!因为数据也会刷磁盘,当刷完磁盘,redo 日志已经没有用了!
4. undo log 逻辑
主要用于事务回滚 和MVCC 多版本并发控制
undo log分为 insert和update,划分是根据插入语句的undo log提交后可以直接删除;而update类型的根据MVCC的需求不能删除,需要purge线程判断能否删除。
insert类型的undo log格式如下,记录了next下一跳日志、类型、undo no、表id和主键kv,如需回滚直接根据主键定位到数据行进行删除。
update类型是针对update语句和delete语句,除了以上 还记录了修改数据的事务id、数据的回滚指针、update vector 修改的列的原始和修改值,可以根据这个写出相反的update语句和insert语句。
5. update流程(记录日志时机)
两阶段提交
将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。
why:
由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是先写完redo log 再写 binlog,或者采用反过来的顺序。我们看看这两种方式都会存在当两者中间数据库崩溃的话,两者数据不一致。