概述 undo log(回滚日志):是 Innodb 存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和 MVCC。 redo log(重做日志):是 Innodb 存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复; binlog (归档日志):是 Server 层生成
逻辑格式的日志,在执行 undo 的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log 的。
每当 InnoDB 引擎对一条记录进行操作(修改、删除、新增)时,要把回滚时需要的信息都记录到 undo log 里,比如:
事务开始之前 ,MySQL 会先记录更新前的数据到 undo log 日志文件里面,当事务回滚时,可以利用 undo log 来进行回滚。同时undo 也会产生 redo 来保证undo log的可靠性。
undo log 和数据页的刷盘策略是一样的,都需要通过 redo log 保证持久化。产生undo日志的时候,同样会伴随类似于保护事务持久化机制的redolog的产生。
buffer pool 中有 undo 页,对 undo 页的修改也都会记录到 redo log。redo log 会每秒刷盘,提交事务时也会刷盘,数据页和 undo 页都是靠这个机制保证持久化的,具体看下面内容。
物理格式的日志,记录的是物理数据页面的修改的信息,其 redo log 是顺序写入redo log file 的物理文件中去的。同时,在内存修改 Undo log 后,也需要记录undo log对应的 redo log。
redo log 和 undo log 区别:
事务开始之后就产生redo log,redo log的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo log文件中。
事务提交之前发生了崩溃,重启后会通过 undo log 回滚事务,事务提交之后发生了崩溃,重启后会通过 redo log 恢复事务,如下图:
redo log 要写到磁盘,数据也要写磁盘,为什么要多此一举?
写入 redo log 的方式使用了追加操作, 所以磁盘操作是顺序写,而写入数据需要先找到写入位置,然后才写到磁盘,所以磁盘操作是随机写。磁盘的「顺序写 」比「随机写」 高效的多,因此 redo log 写入磁盘的开销更小。
实际上, 执行一个事务的过程中,产生的 redo log 也不是直接写入磁盘的,因为这样会产生大量的 I/O 操作,而且磁盘的运行速度远慢于内存。
redo log有一个缓存区 Innodb_log_buffer,Innodb_log_buffer 的默认大小为 16M,每当产生一条 redo log 时,会先写入到 redo log buffer,后续再持久化到磁盘。
然后会通过以下三种方式将innodb log buffer的日志刷新到磁盘:
因此redo log buffer的写盘,并不一定是随着事务的提交才写入redo log文件的,而是随着事务的开始,逐步开始的。
即使某个事务还没有提交,Innodb存储引擎仍然每秒会将redo log buffer刷新到redo log文件。
这一点是必须要知道的,因为这可以很好地解释再大的事务的提交(commit)的时间也是很短暂的。
两个 redo 日志的文件名叫 :ib_logfile0 和 ib_logfile1。
redo log文件组是以循环写的方式工作的, InnoDB 存储引擎会先写 ib_logfile0 文件,当 ib_logfile0 文件被写满的时候,会切换至 ib_logfile1 文件,当 ib_logfile1 文件也被写满时,会切换回 ib_logfile0 文件;相当于一个环形。
因此,如果 write pos 追上了 checkpoint,就意味着 redo log 文件满了,这时 MySQL 不能再执行新的更新操作,也就是说 MySQL 会被阻塞
binlog 有 3 种格式类型,分别是 STATEMENT(默认格式)、ROW、 MIXED,区别如下:
注意:不同的日志类型在主从复制下除了有动态函数的问题,同样对对更新时间也有影响。一般来说,数据库中的update_time都会设置成ON UPDATE CURRENT_TIMESTAMP,即自动更新时间戳列。在主从复制下,
如果日志格式类型是STATEMENT,由于记录的是sql语句,在salve端是进行语句重放,那么更新时间也是重放时的时间,此时slave会有时间延迟的问题;
如果日志格式类型是ROW,这是记录行数据最终被修改成什么样了,这种从库的数据是与主服务器完全一致的。
事务 提交的时候 ,一次性将事务中的sql语句(一个事物可能对应多个sql语句)按照一定的格式记录到binlog中。
binlog 文件是记录了所有数据库表结构变更和表数据修改的日志,不会记录查询类的操作,比如 SELECT 和 SHOW 操作。
这里与redo log很明显的差异就是binlog 是追加写,写满一个文件,就创建一个新的文件继续写,不会覆盖以前的日志,保存的是全量的日志。redo log 是循环写,日志空间大小是固定,全部写满就从头开始,保存未被刷入磁盘的脏页日志。
也就是说,如果不小心整个数据库的数据被删除了,只能使用 bin log 文件恢复数据。因为redo log循环写会擦除数据。
MySQL 的主从复制依赖于 binlog ,也就是记录 MySQL 上的所有变化并以二进制形式保存在磁盘上。复制的过程就是将 binlog 中的数据从主库传输到从库上。
这个过程一般是异步的,也就是主库上执行事务操作的线程不会等待复制 binlog 的线程同步完成。
MySQL 集群的主从复制过程如下:
在刷盘时机上与redolog不一样,redolog即使事务没提交,也可以每隔1秒就刷盘。但是一个事务的 binlog 是不能被拆开的,因此无论这个事务有多大(比如有很多条语句),也要保证一次性写入。如果一个事务的 binlog 被拆开的时候,在备库执行就会被当做多个事务分段自行,这样就破坏了原子性,是有问题的。
bin log日志与redo log类似,也有对应的缓存,叫 binlog cache。事务提交的时候,再把 binlog cache 写到 binlog 文件中。
MySQL提供一个 sync_binlog 参数来控制数据库的 binlog 刷到磁盘上的频率:
显然,在MySQL中系统默认的设置是 sync_binlog = 0,也就是不做任何强制性的磁盘刷新指令,这时候的性能是最好的,但是风险也是最大的。因为一旦主机发生异常重启,还没持久化到磁盘的数据就会丢失。
而当 sync_binlog 设置为 1 的时候,是最安全但是性能损耗最大的设置。因为当设置为 1 的时候,即使主机发生异常重启,最多丢失一个事务的 binlog,而已经持久化到磁盘的数据就不会有影响,不过就是对写入性能影响太大。
如果能容少量事务的 binlog 日志丢失的风险,为了提高写入的性能,一般会 sync_binlog 设置为 100~1000 中的某个数值。
事务提交后,redo log 和 binlog 都要持久化到磁盘,但是这两个是独立的逻辑,可能出现半成功的状态,这样就造成两份日志之间的逻辑不一致。如下:
两阶段提交把单个事务的提交拆分成了 2 个阶段,分别是「准备(Prepare)阶段」和「提交(Commit)阶段」
事务的提交过程有两个阶段,就是将 redo log 的写入拆成了两个步骤:prepare 和 commit,中间再穿插写入binlog,具体如下:
总的来说就是,事务提交后,redo log变成prepare 阶段,再写入binlog,返回成功后redo log 进入commit 阶段。
当优化器分析出成本最小的执行计划后,执行器就按照执行计划开始进行更新操作。
具体更新一条记录 UPDATE t_user SET name = 'xiaolin' WHERE id = 1; 的流程如下:
Java面试题专栏 已上线,欢迎访问。
那么可以私信我,我会尽我所能帮助你。
真实飞行员模拟 中文版 1.0.4 91.17 MB
下载
湘ICP备2022002427号-10 湘公网安备:43070202000427号
© 2013~2024 haote.com 好特网