MySQL Redo Log、Undo Log、Bin Log 三大日志与数据库事务相挂钩,之前在介绍 MySQL 事务时,提及到了它的四大特性,原子性、一致性、隔离性、持久性
Redo Log 日志是 InnoDB 存储引擎中的日志文件,用它来保证事务的持久化操作,以下是 Redo Log 几大作用
crash-safe
在操作系统中分为两种空间:用户空间、内核空间,最下面是磁盘空间
如上图,当更新完数据,一旦提交先将操作记录写入到 Redo Log 中,会保存到 Log Buffer 空间;随即 Log Buffer 会将数据写入到 OS Buffer,OS Buffer 会触发系统调用
fsync() 异步写入到磁盘中
在 MySQL 中,Redo Log 写入方式可以通过 innodb_flush_log_at_trx_commit 参数进行配置,该参数有三个可选的取值:0、1、2,分别代表不同的写入方式,默认值为 1,通过以下 SQL 查看
show VARIABLES like 'innodb_flush_log_at_trx_commit';
若提交的频率比较高,那么每次写入到磁盘都是一次磁盘 IO,这样产生的 IO 次数肯定是很多的,但相对于其他两种方式,每次都能保证写入到磁盘中
0、2 这两种方式在批量提交时效率比较快,一秒钟可能积累的事务数会很多,但是数据存在不安全,可能会丢失一秒钟的数据
总而言之,数据安全性、性能两者不能同时都保证,选择适当的配置值需要根据应用程序的需求以及对数据安全性的要求两者进行 Trade Off!
在 MySQL 中,还有一些常用参数可以支持 Redo Log 配置,如下:
这些参数可以通过修改 MySQL 配置文件(my.cnf 或 my.ini)来进行设置,在进行更改之前建议备份数据库。不正确的参数配置可能会对数据库的性能、稳定性产生影响,并测试环境中进行充分测试和评估
Undo Log 日志是 InnoDB 存储引擎中的日志文件,用它来保证事务的原子性操作
在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方成为 Undo Log)然后进行修改操作,若出现错误或者用户执行了 ROLLBACK 语句,系统可以利用 Undo Log 中的备份数据恢复到事务开始之前的状态
Undo Log 主要作用是支持数据库的事务回滚、MVCC(多版本并发控制)详细内容如下:
Undo Log 是逻辑日志,可以理解为
1、当 delete 一条记录时,Undo Log 会生成一条对应的 insert 记录
2、当 insert 一条记录时,Undo Log 会生成一条对应的 delete 记录
3、当 update 一条记录时,Undo Log 会生成相反的 update 记录
Bin Log(二进制日志)日志是 MySQL Server 层面的日志文件,主要用于作 MySQL 功能层面的事情,同时它也可以用来作数据的复制、恢复、故障恢复工作
Bin Log 几个主要的作用如下:
需要注意的是,Bin Log 是基于事务的日志,只记录对数据的修改操作,而不包括查询操作
Bin Log 以文件的形式存储在磁盘上
,通常会有多个 Bin Log 文件组成一个序列,每个文件都有一个递增的序号。Bin Log 文件是追加写入的,新的修改操作会不断追加到最新的 Bin Log 文件中
Redo Log 以循环写入的方式存储在磁盘上
,通常会有多个 Redo Log 文件组成一个循环队列。当 Redo Log 写入位置到达文件末尾时,会回到文件的起始位置再次进行循环写入
Bin Log 写入是在事务提交时进行的,即在事务完成之后将修改操作记录到 Bin Log 中。Bin Log 写入可以是同步或异步的,可以通过参数配置来调整
Redo Log 写入是在事务执行期间进行的,即在事务进行修改操作时就会将相应的 Redo Log 记录写入到 Redo Log 文件中。Redo Log 写入是顺序写入的,采用追加写的方式
Bin Log 写入方式可以通过 sync_binlog
参数进行配置,它有三种取值,如下:
首先通过 Bin Log 来恢复误删除的数据,要确认 Bin Log 是否开启,若未开启,可能你丢失的数据就很难溯源了
SHOW VARIABLES LIKE 'log_bin';
通过以下这种方式,开启 Bin Log
[mysqld]
# 服务 id,开启 bin log 要标识服务端
server-id=1
# 开启 Bin Log,二进制文件基本存储目录 > /var/lib/mysql/binlog
log_bin=/var/lib/mysql/binlog
:wq! 保存后退出,修改存储目录权限 > chomod 755 /var/lib/mysql/binlog
sudo systemctl restart mysqld
,等待数据库服务重启以后,再次执行 SHOW VARIABLES LIKE 'log_bin';
命令观察 Bin Log 是否开启成功确认好 Bin Log 已开启好以后,操作一条删除语句,比如:
DELETE from emp where empno in(7900,7902);
然后在 /var/lib/mysql 目录下就能看到 bin log 日志文件了
通过以下命令来进行观察,将二机制转为 SQL 语句导出在本地文件 > output.sql,如下:
# --start-datetime="2023-06-13 18:28:00" --stop-datetime="2023-06-13 18:34:00"
# 通过时间点范围导出部分数据,而不是全量数据,便于快速定位到需要的数据部分
mysqlbinlog --no-defaults --base64-output=decode-rows -v binlog.000001 > output.sql
最终,通过观察文件内容找出了原始的数据,可以对它进行恢复操作
如上图,数据更新执行过程分为以下几点
为什么 Redo Log 要采用两阶段提交,假设不使用两阶段,举例场景如下:
1、先写完 Redo Log 后再写 Bin Log
属性:name,由 choshim -> vnjohn
假设在 Redo Log 写完,Bin Log 还未写完时,MySQL 进程异常重启;由于前面所提及到的,Redo Log 写完之后,即使系统崩溃了,仍然能够把数据恢复回来,所以恢复后 name 值变为 choshim,但是由于 Bin Log 没写完就 crash 了,这时候 Bin Log 里面讲究没有这条语句;因此,在之后备份日志的时候,Bin Log 存起来的数据里面就没有这条语句;最后,你会发现,若使用这个 Bin Log 来恢复临时库的话,由于这条语句的 Bin Log 丢失,临时库就会少了这一次数据更新,恢复出来的这一条数据 name 值为 choshim,与原有库中的值不同
2、先写 Bin Log 后再写 Redo Log
属性:name,由 choshim -> vnjohn
假设在 Bin Log 写完之后 crash 了,由于 Redo Log 还没写,崩溃恢复这个事务无效,所以这一条数据 name 属性值为 choshim;但 Bin Log 里面已经记录了 “把 name 从 choshim 改为 vnjohn” 日志;所以,之后用 Bin Log 来进行恢复时就会多出了一条更新操作的事务出来,恢复出来的这一条数据 name 属性值为 vnjohn,与原有库值不同
因为以上这两种问题,谁先写谁后写都会发生问题,所以要解决这种一致性问题,就不得已要采取分阶段的方式来保证事务的完整性
如上图在时刻 A 的地方,也就是写入 Redo Log 处于 prepare 阶段之后、写 Bin Log 之前,发生了系统崩溃 crash,由于此时 Bin Log 还没写入,Redo Log 也还没进行提交;所以崩溃恢复时,这个事务会进行回滚,同时,Bin Log 还没写入,所以也不会传给备用库
若在 Redo Log 里面的事务是完整的,也就是有了 commit 标识,则直接提交;若 Redo Log 里面的事务只有完整的 prepare 阶段,则判断对应事务的 Bin Log 是否存在并完整
1、若事务的 Bin Log 完整,则提交事务
2、若事务的 Bin Log 不完整,则回滚事务
若是在时刻 B 发生 crash,在崩溃恢复过程中事务是会被提交的
PS:两阶段提交的最后一阶段操作本身是不会失败的,除非是系统或硬件发生了错误,所以也就不再需要回滚
该篇博文从浅入深的讲解了 MySQL 中三大日志 > Redo Log、Undo Log、Bin Log 三大日志体系,Redo Log、Undo Log 是 InnoDB 存储引擎内的日志,Bin Log 是 MySQL Server 层面的日志,接着仔细说明了它们各自的作用,包括了写入的执行过程、写入的方式,实战方面,演示了如何使用 Bin Log 恢复误删的数据,最后,分析了为什么要采用两阶段提交方式来完成 Redo Log、Bin Log 记录以及数据更新!
MySQL 专栏高质量博文如下:
MySQL 内置的监控工具介绍及使用篇
构建优化之城:MySQL 数据建模、数据类型优化与索引常识全面解析
MySQL 数据结构优化与索引细节解析:打造高效数据库的优化秘笈
MySQL 数据访问与查询优化:提升性能的实战策略和解耦优化技巧
深度解析 MySQL 事务、隔离级别和 MVCC 机制:构建高效并发的数据交响乐
如果觉得博文不错,关注我 vnjohn,后续会有更多实战、源码、架构干货分享!
推荐专栏:Spring、MySQL,订阅一波不再迷路
大家的「关注❤️ + 点赞 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!