vlambda博客
学习文章列表

Mysql系列--事务日志

Mysql属于传统关系型数据库,广泛应用于各个互联网公司,Mysql的基础架构如下:

Mysql可以分成Server层和存储引擎层两部分,Server层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。存储引擎层负责数据的存储和提取,其架构模式是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎。现在最常用的存储引擎是InnoDB,它从MySQL 5.5.5版本开始成为了默认存储引擎。


Memory存储引擎主要用于内部表,Innodb和MyIsam一个比较明显的不同点是:Innodb支持事务,而MyIsam不支持事务。这里我们主要讨论Innodb如何支持数据库事务,数据库事务要符合ACID特性:

  • 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。

  • 一致性(Consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

  • 隔离性(Isolation):多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

  • 持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。 


在Innodb中如何来实现这些特性的呢?Innodb内部支持多种锁来保证不同事务间的隔离性;通过将事务提交的数据写入到磁盘进行持久化,在事务提交前需要先将Redo log持久化;通过Undo log来保证数据的原子性,当出现失败时,可以通过Undo log来恢复原来的数据;通过原子性和隔离性来一起保证一致性。


前面提到的Redo log和Undo log,都位于存储引擎层,其中Redo log是重做日志,主要记录物理数据页的更改信息,如数据页100的第100行设置为10,属于物理日志;Undo log是回滚日志,主要记录sql更新语句的逆操作,如原sql是insert则对应的Undo log记录为delete,属于逻辑日志。当然,Undo log除了用来保证事务的原子性,还可以用来实现MVCC机制,进一步提高Mysql的并发性能。


此外,我们在生产环境中进行Mysql部署时通常按照主从模式部署的,此时binlog就必不可少了。binlog位于server层,主要用于主从之间的数据同步,记录sql变更语句,属于逻辑日志。


后面会有相应的篇幅来讲解这些日志,下面我们来通过update语句来了解sql语句如何执行,并学习这些日志的写入顺序。

由图可知,在数据更新前先写undo日志,然后写redo日志,最后写binlog日志。由于文件系统缓存的原因,在写日志过程中,日志内容可能并没有刷盘,因此这里面存在着多种可能影响我们系统的稳定性,比如数据在缓存中未刷盘就宕机了,再比如在刷盘的过程中宕机,此时文件内容就可能不准确了。针对刷盘时机,Mysql提供了两个参数来分别控制redo log和binlog的刷盘:

  • innodb_flush_log_at_trx_commit:控制redo log的刷盘机制,这只是redo log众多刷盘机制中的一种情形,后面会具体介绍redo log的刷盘机制。

  • sync_binlog: 控制binlog的刷盘机制,后面也会有专门的文章介绍binlog。

当然Undo log也是需要持久化的,后面找到相关材料后再补充。另外,需要注意的是Undo log页面修改同样需要记录Redo log。


这里提个问题:为什么在事务提交时先写redo log后写binlog?