1. redo 日志

作用:
确保事务的持久性。redo日志记录事务执行后的状态,用来恢复未写入data file的已成功事务更新的数据。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。
图片.png
内容:
物理格式的日志,记录的是物理数据页面的修改的信息,其redo log是顺序写入redo log file的物理文件中去的。
什么时候产生:
事务开始之后就产生redo log,redo log的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo log文件中。
什么时候释放:
当对应事务的脏页写入到磁盘之后,redo log的使命也就完成了,重做日志占用的空间就可以重用(被覆盖)。

REDO日志的好处、特点:

  • redo日志降低了刷盘频率(数据页刷盘是从内存刷到磁盘,是随机的I/O,速度较慢。redo log是顺序写入的,速度较快)
  • redo日志占用的空间非常小
  • redo日志是顺序写入磁盘的
  • 事务执行过程中,redo log不断记录

redo的组成:

  • 重做日志的缓冲 (redo log buffer),保存在内存中,是易失的。
  • 重做日志文件 (redo log file),保存在硬盘中,是持久的。

redo的整体流程:
image.png

  1. 1步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝
  2. 2步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
  3. 3步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加写的方式
  4. 4步:定期将内存中修改的数据刷新到磁盘中

redo log的刷盘策略:
redo log的写入并不是直接写入磁盘的,InnoDB引擎会在写redo log的时候先写redo log buffer,之后以一定的频率刷入到真正的redo log file 中。
image.png

注意,redo log buffer刷盘到redo log file的过程并不是真正的刷到磁盘中去,只是刷入到文件系统缓存(page cache)中去(这是现代操作系统为了提高文件写入效率做的一个优化),真正的写入会交给系统自己来决定(比如page cache足够大了)。那么对于InnoDB来说就存在一个问题,如果交给系统来同步,同样如果系统宕机,那么数据也丢失了(虽然整个系统宕机的概率还是比较小的)。
针对这种情况,InnoDB给出innodb_flush_log_at_trx_commit参数,该参数控制 commit提交事务时,如何将 redo log buffer 中的日志刷新到 redo log file 中。它支持三种策略:

设置为0 :表示每次事务提交时不进行刷盘操作。(系统默认master thread每隔1s进行一次重做日志的同步)
设置为1 :表示每次事务提交时都将进行同步,刷盘操作(默认值)(数据安全性得到保障)
设置为2:表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由os自己决定什么时候同步到磁盘文件。

MySQL默认策略:innodb_flush_log_at_trx_commit=1
image.png

2. undo 日志

作用:
保证数据的原子性保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。

图片.png
分析:
事务A执行update语句后,会将旧数据记录到undo buffer中,当事务B查询时取出的是旧的数据,这样子就实现了可重复读。
事务A提交时如果出现回滚,则可以从undo buffer中恢复旧数据

内容:
逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的。即它记录的是一个变化过程,例如执行一个delete时会记录一个insert;执行一个update时,会记录一个相反的update,这么做用于回滚。
什么时候产生:
事务开始之前,将当前是的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性
什么时候释放:
当事务提交之后,undo log并不能立马被删除,而是放入待清理的链表,由purge线程判断是否由其他事务在使用undo段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志空间。

undo log生成过程:
image.png
更新数据时,在事务开始之前就需要把旧数据记录到undo log中。事务开始之后再将数据放到redo log中。
undo log是逻辑格式的日志,redo log是物理格式的日志。

3. bin 日志

3.1 binlog内容

作用:

  • 用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。
  • 用于数据库的基于时间点的还原。(删除数据库之后的恢复)

内容:
逻辑格式的日志,可以简单认为就是执行过的事务中的sql语句。
记录模式:

  • ROW:日志中会记录每一行数据被修改的情况,然后对slave端对相同的数据进行修改。
    • 优点:能清楚的记录每一行的数据的修改细节,能完全实现主从数据同步和数据恢复。
    • 缺点:会产生大量日志
  • STATEMENT:每一条被修改的数据的SQL都会记录到master的binlog中,salve在复制的时候SQL进程会解析成和原来master端执行过的相同的SQL再次执行。
    • 优点:日志量小,减少磁盘IO,提升存储和恢复速度
    • 缺点:在某些情况下导致主从数据不一致,比如:now()等函数
  • MIXED:以上两种模式的混合使用,一般会使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog,MySQL会根据执行的SQL语句选择写入模式。

什么时候产生:
事务提交的时候,一次性将事务中的sql语句(一个事物可能对应多个sql语句)按照一定的格式记录到binlog中。
这里与redo log很明显的差异就是redo log并不一定是在事务提交的时候刷新到磁盘,redo log是在事务开始之后就开始逐步写入磁盘。
因此对于事务的提交,即便是较大的事务,提交(commit)都是很快的,但是在开启了bin_log的情况下,对于较大事务的提交,可能会变得比较慢一些。
这是因为binlog是在事务提交的时候一次性写入的造成的,这些可以通过测试验证。

什么时候释放:
binlog的默认是保持时间由参数expire_logs_days配置,也就是说对于非活动的日志文件,在生成时间超过expire_logs_days配置的天数之后,会被自动删除。

3.2 binlog与redolog对比

二进制日志的作用之一是还原数据库的,这与redo log很类似,很多人混淆过,但是两者有本质的不同
作用不同:redo log是保证事务的持久性的,是事务层面的(用于崩溃数据恢复),binlog用于主从复制,保证MySQL集群架构数据一致性。
内容不同:redo log是物理日志,是数据页面的修改之后的物理记录,binlog是逻辑日志,可以简单认为记录的就是sql语句
层次不同:redo log属于innoDB引擎功能,binlog属于MySQL Server自带的功能。
写入方式不同:redo log日志是循环写入,日志空间大小是固定的,binlog是追加写入,不会覆盖使用。

3.3 binlog写入机制:

binlog的写入时机也非常简单,事务执行过程中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写到binlog文件中。因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。
image.png
write和fsync的时机,可以由参数sync_binlog控制,默认是0。为0的时候,表示每次提交事务都只write,由系统自行判断什么时候执行fsync。虽然性能得到提升,但是机器宕机,page cache里面的binglog 会丢失。如下图:
image.png
为了安全起见,可以设置为1,表示每次提交事务都会执行fsync,就如同redo log 刷盘流程一样。最后还有一种折中方式,可以设置为N(N>1),表示每次提交事务都write,但累积N个事务后才fsync。
image.png
在出现IO瓶颈的场景里,将sync_binlog设置成一个比较大的值,可以提升性能。同样的,如果机器宕机,会丢失最近N个事务的binlog日志。

3.4 两阶段提交

在执行更新语句过程,会记录redo log与binlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的写入时机不一样。
如果binlog与redolog不一致,可能会导致主从数据不一致,为了解决两份日志的逻辑一致问题,innoDB存储引擎使用两阶段提交方案。
image.png
使用两阶段提交后,写入binlog时发生异常也不会有影响。如果 redo log 只是预提交但不是 commit 状态,这个时候就会去判断 binlog 是否完整,如果完整就提交 redo log, 不完整就回滚事务。
image.png
另一个场景,redo log设置commit阶段发生异常,那会不会回滚事务呢?
image.png
并不会回滚事务,它会执行上图框住的逻辑,虽然redo log是处于prepare阶段,但是能通过事务id找到对应的binlog日志,所以MySQL认为是完整的,就会提交事务恢复数据。