MySQL之日志


MySQL日志有3种:

redo

官方文档:https://dev.mysql.com/doc/refman/8.0/en/innodb-redo-log.html

redo log是重做日志,提供前滚操作。
redo log是物理日志,记录的是数据行的物理修改,当数据需要恢复时,可以从redo log中恢复到数据最后一次的修改状态。
redo log包含两块内容,一部分是日志缓冲(log buffer),在内存中;另一部分是日志重做文件(log file),在磁盘上。

InnoDB通过force log at commit实现事务的持久性,在事务提交的时候,必须先将该事务的所有事务日志写入redo log file和undo log file中。

流程:
我们来看下日志的写入过程:
在这里插入图片描述
如上图所示,我们来梳理下redo log的处理流程:

  1. 当数据发生了修改,InnoDB引擎先将该记录写入redo log buffer中,更新内存中的数据,此时更新就算是完成了。
  2. 在适当的时机,InnoDB引擎调用os方法,将buffer中的数据写入磁盘。

另外redo log是固定大小的,是循环写,当空间用完之后,后续记录会将最老的记录替换掉。

flush data
那MySQL是在什么时候将buffer中的数据写入log file呢?
通过配置:innodb_flush_log_at_trx_commit来决定,有0,1,2三种值,默认为1:
在这里插入图片描述

  • 为0的时候,事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file on disk中。当系统崩溃,尚在os buffer中还没来记得刷入磁盘的数据都将丢失。
  • 为1的时候,事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file on disk中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。
  • 为2的时候,每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。

数据恢复:
在这里插入图片描述
log file以log block为单位进行存储,一个block大小为512字节,
write point:数据已经刷新到磁盘上的位置点
check point:数据已经完整刷新到磁盘上的位置点

当启动InnoDB时,无论上一次是正常关闭还是异常关闭,重启InnoDB时,都会从check point开始到write point为止进行恢复数据。

undo

官方文档:https://dev.mysql.com/doc/refman/8.0/en/innodb-undo-logs.html

undo log是回滚日志,提供回滚操作。
在InnoDB中,使用undo log来实现多版本并发控制。

在操作任何数据之前,首先先将数据备份到一个地方(这个数据备份的地方就是undo log),任何进行数据修改。如果出现错误或者用户执行rollback,MySQL可以用 undo log的备份数据,将数据恢复到数据开始之前。

与redo log不同,redo log是物理日志,undo log是逻辑日志:

  • 当delete一条记录,undo log中会新增一条对应的insert记录
  • 当insert一条记录,undo log中会新增一条对应的delete记录
  • 当update,undo log中会新增一条相反的update记录

当事务提交后,InnoDB不会立即删除undo log中的记录,会将该事务对应的undo log放入到删除列表中,未来通过purge来删除。

binlog

binlog是MySQL server的日志文件,在server层,主要负责MySQL功能层面的事情。

与redo log的区别:

  1. redo,undo是InnoDB独有的,binlog是所有引擎都可以使用的
  2. redo是物理日志,记录的是对某个数据页做了哪些具体的修改,undo,binlog是逻辑日志,记录原始逻辑
  3. redo是循环写,空间会用完,binlog是文件追加,不会覆盖之前的信息

数据恢复:
找一个备份的时间点,把备份的binlog取出来,重放到要恢复的那个时刻

事务

我们来简单回顾下数据库事务的几大特性:

  • Atomicity:原子性,通过undo日志实现
  • Consistency:一致性,通过A+I+D三个特性组合保证
  • Isolation:隔离性,通过锁
  • Durability:持久性,通过redo日志实现

简单梳理下数据库事务的处理过程:
在这里插入图片描述
以update事务为例,流程大体如下:

  1. 执行器先从引擎中找到数据,如果数据不在内存,则从磁盘中加载数据进入内存
  2. InnoDB数据引擎拿到数据之后,将数据在内存中进行更新,同时将数据记录写入redo,undo,此时数据处于prepare阶段,InnoDB引擎通知执行器操作完成
  3. 执行器写入本次操作的binlog
  4. 执行器调用引擎的事务提交接口,引擎把刚写入的redo,undo状态改成commit,同时将binlog写入磁盘,事务完成

两阶段:
我们可以看到上述流程,先是经历了prepare阶段,再是commit阶段,为什么要设计经历两个阶段呢,直接写入redo,binlog会有什么问题呢?

现有一条记录数据列:a=1,执行update指令:a=2,

  1. 如果一次性先写入redo,再写入binlog:
    假设redo log已经写入完成,binlog还没有写入完成,此时进程异常,MySQL退出。后面再重启数据库,通过redo log是可以将数据恢复到a=2的,因为redo log里面是有记录这个操作的。但是binlog里面是没有这个操作的记录,后续通过备份日志进行数据恢复,因binlog中这个记录丢失,恢复后的数据是a=1,而实际应该是a=2,恢复后的数据是不准确的。
  2. 如果一次性先写入binlog,再写入redo:
    情形是类似的,binlog写入完成,而redo没有完成写入,那么InnoDB重启之后,数据是无法恢复到a=2,最终的数据还是a=1,而用binlog恢复之后得到的数据确实a=2。

通过两段式提交,确保redo,binlog里面记录的数据,最终是一致的。

PS:binlog默认是关闭的,需要手动开启。在binlog关闭状态下,事务是不需要两阶段提交的,参与者就只有redo和undo,中间需要通过互斥锁来防止资源竞争。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值