MySQL是如何实现事务ACID四个特性的?

对于原子性

undolog记录了反向的操作

对于一致性

使用undolog保证了事务要么提交要么回滚

使用MVCC保证事务内的读一读一致性

对于隔离性

MySQL有四个隔离级别来保证隔离性

通过锁和MVCC实现隔离级别下的读写隔离

对于持久性

通过redolog重做日志来保证事务的持久性

1、redo

实现事务的持久性,由两部分组成,重做日志缓冲(易失)和重做日志文件(持久)

redo日志是物理日志,记录的是页的物理修改操作(例如增大表空间),这一点和undo日志有区别,undo记录的是逻辑操作,对于物理操作不能恢复

每次commit事务后,InnoDB引擎会调用一个fsync将缓冲区的重做日志刷新到磁盘中,所以在这方面来说磁盘的性能决定了数据库的性能

我们可以设置redo机制的发生——设置innodb_flush_log_at_trx_commit,0、1、2分别代表三种状态

默认是1:每次commit事务执行一次fsync

0:commit时不执行fsync,而是在某个空闲的时间段写入,但是当数据库宕机就会有数据的丢失

2:将重做日志写入文件的缓冲区,但是不调用fsync写入磁盘中,这样当数据库宕机时虽然不会丢失事务的修改,但是当操作系统宕机就会造成数据丢失,因为没有写入到磁盘中

2、undo

实现事务的一致性。与redo重做日志文件不同,它是放在数据库内部的共享表空间的

两个数据字典表,分别是INNODB_TRX_ROLLBACK_SEGMENTINNODB_TRX_UNOD

undo日志是逻辑日志,只能将数据库逻辑地恢复到原来的样子,对于数据结构和页不能恢复

undo实现了MVCC,提供了多版本的非锁定读

undo log也会产生redo log,因为undo log也需要持久化

通过查看数据字典表我们可以发现,当执行delete操作时,并没有直接删除数据,而是将delete flag标志为1,而最终的删除操作是在purge操作中完成的;当执行update操作时,对于非主键的update会只有一个update操作,而对于一个主键的update会先delete操作(同样是delete flag置为1),再进行insert操作。

3、purge

上面提到过delete和update操作并不会直接删除原有数据,只是标记为删除,真正的操作被延时到purge操作中完成。所有操作产生的undolog按照事务提交的顺序,保存在history list中,在执行purge时,会从该链表头部开始找到第一个需要被清理的记录,并根据事务id向后检测该undolog是否被其他事务使用,如果未使用则进行purge操作并删除,否则放弃,继续判断链表的下一个undolog。

    为了提高purge效率,可以通过 innodb_purge_batch_size 设置每次purge操作需要清理的undolog数量,越大则每次回收undo页越多,可供重用的undo页就越多,减少了磁盘存储空间和分配的开销。不过该参数设置得过大,会导致每次需要purge的undo配置越多,从而导致CPU和磁盘IO过于集中使用,使性能下降。

    全局动态参数 innodb_max_purge_lag 用来控制history list的长度,若长度大于该参数时,会延缓DML操作(dalay单位为毫秒),默认值为0,表示不对list大小做任限制,但是当InnoDB存储引擎压力太大时,purge操作并不高效。
4、group commit
什么是group commit?

是非只读事务提交时需要进行一次fsync操作,保证重做日志成功刷盘,以便当数据库发生宕机时,可以通过重做日志进行数据恢复。为了提高磁盘fsync的效率,数据库提供了group commit功能,在一次fsync时可以刷新多个事务日志写入磁盘。

事务提交后的操作

1)将重做日志写入重做日志缓冲区

2)将缓冲区的重做日志刷新到磁盘中

事务提交的两个阶段来说,多个事务可以先进行第一阶段,再进行一次第二阶段,提高了性能。

group commit失效问题

在MySQL5.6之前即InnoDB引擎1.2版本之前,开启了二进制日志,导致了InnoDB存储引擎的group commit失效

为了保证InnoDB存储引擎层的事物和二进制日志的一致性,在事物提交时采用了如下操作:

1)InnoDB存储引擎进行prepare操作

2)MYSQL数据库层写入二进制日志

3)InnoDB存储引擎层将重做日志写入到重做日志文件(上面的两个阶段)

每个步骤都需要进行一次fsync操作才能保证MYSQL层和InnoDB层的一致性,在内部使用了prepare_commit_mutex锁,导致了InnoDB的group commit失效。

如何解决失效?

在MYSQL5.6开始采用了一个Binary Log Group Commit(BLGC),在MYSQL数据库层通过Group commit来写入二进制日志

参考:MYSQL技术内幕 InnoDB存储引擎

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值