日志与持久性

ACID中的I是通过锁来实现,ACD是用过redo log和 undo log来实现

1、 redo log

  记了什么:物理日志,记录对一个页具体的修改。

  位置:InnoDB特有的

  与事务的关系:redo log通过Force log at commit来实现write-ahaed-logging,当事务提交的时候必须先把该事务的修改写到redo log里,从而实现了D

  和缓冲的事情:写入到磁盘的操作都会涉及到文件系统的缓冲区,只有调用fsync操作才会把缓冲里的内容刷到磁盘里,在写入缓冲区后未落盘前是不符合持久性的。

  控制刷新缓冲到磁盘的策略:innodb_flush_log_at_trx_commit

  • 默认是1,事务提交一次,调用一次fsync刷到磁盘一次
  • 0,事务提交后不刷,刷新由mater负责
  • 2,事务提交后不刷,刷的任务交给操作系统

  虽然设置成0 2 可以提高事务提交的性能但是损失了D的特性,正确是姿势是设置为1然后把多个事务一起提交,即降低commit的频率。

1.2 undo log

  比如我有一个字段id,在开始之前id为1,然后我执行了一条update语句其值变成了2,在整个事务执行的过程中不仅会在redo log里记录update id = 2这个修改,也会在undo log里记录下修改前id = 1这个记录,这样的好处是如果这个事务在执行的过程中失败了可以借助undo log逻辑的取消事务对Id的修改并回滚到之前的状态。这种粗糙是理解在非高并发下是可以的,如果有A B两个事务对id字段进行了修改,那么针对事务A的undo log只能逻辑的取消事务A的修改,取消之后id的状态并不一定是原始的状态,因为有可能事务B也对id字段修改。具体来说逻辑的取消就是对事务生成一个相反的操作,回滚insert事务就执行一个delete,回滚delete就执行一个insert,回滚update就执行一个相反的update。

  除了事务回滚外MVCC也是通过undo log来实现,即进程通过读undo log来读取字段之前的状态。

  

1.3 bin log与两阶段提交

  是什么:是一种二进制日志,是逻辑上的日志。

  记录了什么:记录了所有对数据库的修改,比如执行了Update xxx 那么Bin log上就会记录update xxx。所以称bin log是一种逻辑上的日志。

  有什么用:1、恢复。实现point-in-time的恢复,比如数据库在每天24点有一个全量的备份,想把数据库恢复到3点的状态,只需要读取数据库24点的全量备份然后让数据库执行24点到3点这一区间内bin log所有的记录2、复制 原理和恢复一样,执行bin log日志。  

  和缓冲有关的说不清的事情:在数据库中所有和文件系统写入有关的操作都会涉及到缓冲,不仅仅是Bin log,还有redo log,还有Redis下的持久化的实现。目的都是为了提高写入磁盘的效率,数据库不能再每次写bin log的时候都直接写入磁盘,而是写入一个缓冲区即缓冲写,这个缓冲区是文件系统的缓冲区而非MySQL的Server端维护的缓冲区。所以存在一定的危险性即OS挂的时候缓冲区内的内容还没有同步到磁盘上就有可能会带来数据丢失。

  bin log日志的格式(面试问过):

  • STATEMENT。最普通的格式,记录着SQL语句
  • ROW。不是简单的SQL而是记录表行的更改情况,类似于物理日志。
  • MIXED。二者的混合

  在开启了bin log后为了保证redo log和bin log存储的内容相同采取了两阶段提交。以执行update T set c=c+1 where id =1为例,首先在内存里更新c为c+1,然后更新redo log buffer,在commit之后把buffer的内容刷到redo log file里,在没有bin log的时候这样一个事务提交就完事了,如果有bin log那么此时redo log file中关于这个事务的记录是prepare状态或者说是一个未完全提交的事务状态。必须等待引擎把更新的内容写到bin log中,才能够把该事务对应记录改成commit状态。最后才是引擎在合适的时候把redo log file里的更新刷到磁盘里,这种先写日志再写磁盘的技术称为WAL(write ahand logging)。

  为什么两阶段提交能够保证redo log 和 bin log内容一致呢?理解这个问题可以从反证的角度出发,假设没有采用两阶段提交,而在写redo log 和 bin log之间mysql进程挂了。

  如果是先写redo log 再写 bin log 在之间mysql挂了。redo log里有事务更新的记录而bin log里没有,此时mysql重启根据redo log恢复数据库,相当于你执行的事务生效了,但是如果有一天根据Bin log恢复日志的时候这条事务是不存在的也就无法恢复。如果是先 binlog 然后 redo log之间Mysql挂了,那么重启的时候无法根据redo log正确的恢复数据库内容,但是有一天根据bin log恢复的时候又把这个事务恢复出来了,同样会带来不一致性。

  所以要理解这里核心的矛盾是在实习生删库之后要根据bin log来回复这个库,在mysql意外挂了之后要通过redo log来保证事务的ACID中的D,两种日志用于两个场景但有必须一致。

  如果在redo log里事务日志的状态的prepare时在写bin log之前MySQL挂会怎么样?会根据undo log回滚。

  如果在redo log里事务的状态是prepare,并且bin log里已经写入会怎么样?会自动commit。

1.4 bin log redo log undo log 区别

  bin log是在Server端的,适用于各种引擎,其记录的是逻辑处理。记录的方式是追加写,目的用于容灾恢复。

  redo log是innoDB独有的,记录的是物理信息,用于实现ACID中的D,其写方式是循环写。

  

 

  

原文地址:https://www.cnblogs.com/AshOfTime/p/10491318.html