MySQL重做日志(redolog)

https://wenku.baidu.com/view/b626f977f31dc281e53a580216fc700aba685274.html

MySQL重做⽇志(redolog)


前⾯介绍了三种⽇志:这三种都是 Server 层的。今天的 redo log 是 InnoDB引擎专有的⽇志⽂件。


为什么要有 redo log


⽤个酒店掌柜记账的例⼦说明 redo log的作⽤。


酒店掌柜有⼀个粉板,专门⽤来记录客⼈的赊账记录。如果赊账的⼈不多,那么他可以把顾客名和账⽬写在板上。但如果赊账的⼈多了,粉板总会有记不下的时候,这个时候掌柜⼀定还有⼀个专门记录赊账的账本.


如果有⼈要赊账或者还账的话,掌柜⼀般有两种做法:
1. 直接翻开账本记录(直接写磁盘)
2. 先记在粉板(redo log)上,等空闲时再记录到账本(磁盘)上


当⽣意⽕爆时,不停有⼈来要赊账或者还账(更新操作),如果掌柜还是⽤第⼀种做法,由于记到账本上需要查找记录(随机读)那就会出现⼤量的⼈(更新操作)在等待,会影响⼯作(阻塞)。


第⼆种做法,先记在粉板上,空闲时再写回账本。因为记粉板的速度是很快的,就能⼤量处理赊账或者还账,当掌柜(MySQL)没那么忙的时候,就把粉板上的内容记到账本上。但如果粉板(redo log)写满了,那这时候掌柜(MySQL)就要停下⼯作,先去把粉板(redo log)的内容写回账本(磁盘)。


两种做法的区别是:
1. 第⼀种是要找到记录后更新,这⾥涉及随时读,⽽随时读是很费时间的
2. 第⼆种是记在⽇志上,这是顺序写的,⽽顺序写是很快的

因此MySQL采⽤第⼆种做法,当有⼀条记录需要更新的时候,InnoDB引擎就会先把记录写到redo log(粉板)⾥⾯,并更新内存,这个时候更新就算完成了。同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘⾥⾯,⽽这个更新往往是在系统⽐较空闲的时候做,这就像打烊以后掌柜做的事。


这就是WAL(Write-Ahead Logging),先写⽇志,再写磁盘。


与粉板类似,redo log 也是有固定⼤⼩的。⽐如可以配置为⼀组4个⽂件,每个⽂件的⼤⼩是1GB,那么这块“粉板”总共就可以记录4GB的操作。从头开始写,写到末尾就⼜回到开头循环写,如下⾯这个图所⽰。


两个指针:

  • write pos是当前记录的位置
  • checkpoint是当前要擦除的位置

有了 redo log,InnoDB 可以保证即使数据库发⽣异常重启,之前提交的记录都不会丢失,这个能⼒称为 crash-safe。


如何写⼊


下⾯以⼀条Update语句来介绍 binlog 是如何记录的。这⾥在⾥也有介绍过。

mysql> update T set c=c+1 where ID=2;


1. 取得 ID=2 这⼀⾏(通过内存或磁盘读取)
2. 这⾏的 c 值加1
3. 更新到内存
4. 写⼊ redo log(处于 prepare 阶段)
5. 写 binlog
6. 提交事务(处于 commit 状态)


两阶段提交


上⾯的流程采⽤了两阶段提交,那为什么要采⽤两阶段提交呢?是为了让 binlog 和 redo log 之间的逻辑⼀致。
我们假设⼀下上⾯的 update 语句在执⾏的每个时刻,MySQL 崩溃了,看⼀下两个⽇志间的逻辑是如何保持⼀致的。

  • 假设在步骤4前,MySQL崩溃重启,那么事务提交失败,不会影响数据。虽然更新了内存,但崩溃后,内存会丢失。
  • 假设在步骤4完成后崩溃,此时已经写⼊ redo log 了,重启后,发现 redo log 处于 prepare 阶段,就不恢复。
  • 假设在步骤5完成后崩溃,此时已经写⼊ binlog 了,重启后,发现 binlog 已经写⼊了,就把对应的 redo log 改为 commit 状态。

这样就能保证 redo log 和 binlog 的逻辑⼀致性。

两阶段提交是跨系统维持数据逻辑⼀致性时常⽤的⼀个⽅案。


如何使⽤


这⾥要介绍⼀下 redo log ⾥⾮常重要的⼀个参数:innodb_flush_log_at_trx_commit


innodb_flush_log_at_trx_commit=0表⽰提交事务的时候,不⽴即把 redo log buffer ⾥的数据刷⼊磁盘⽂件的,⽽是依靠 InnoDB 的主线程每秒执⾏⼀次刷新到磁盘。此时可能你提交事务了,结果 mysql 宕机了,然后此时内存⾥的数据全部丢失。


innodb_flush_log_at_trx_commit=1表⽰提交事务的时候,就必须把 redo log 从内存刷⼊到磁盘⽂件⾥去,只要事务提交成功,那么 redo log 就必然在磁盘⾥了。注意,因为操作系统的“延迟写”特性,此时的刷⼊只是写到了操作系统的缓冲区中,因此执⾏同步操作才能保证⼀定持久化到了硬盘中。


innodb_flush_log_at_trx_commit=2表⽰提交事务的时候,把 redo ⽇志写⼊磁盘⽂件对应的 os cache 缓存⾥去,⽽不是直接进⼊磁盘⽂件,可能1 秒后才会把 os cache ⾥的数据写⼊到磁盘⽂件⾥去。


如何选择


对数据丢失很敏感,设置为1,保证写到磁盘上。但性能较差。
对数据不太敏感,设置为0或2,性能较好。但可能会丢失1秒的数据。


如何查看和设置


通过以下命令查看当前的值是多少:

mysql>选择@innodb\u flush\u log\u at\u trx\u commit;
+----------------------------------+
|@@innodb_flush_log_at_trx_commit|
+----------------------------------+
| 1 |
+----------------------------------+
row(0.00秒)

在/etc/mysql/my.cnf⽂件⾥设置innodb_flush_log_at_trx_commit选项:

#/etc/mysql/my.cnf
innodb_flush_log_at_trx_commit=1


修改后,重启 MySQL 服务即可。


redo log 与 binlog 的区别

  • redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使⽤。
  • redo log 是物理⽇志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑⽇志,记录的是这个语句的原始逻辑
  • redo log 是循环写的,空间固定会⽤完;binlog 是可以追加写⼊的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值