1.什么是两阶段提交
1.1binlog与redolog
1.2两阶段提交
2.为什么需要两阶段提交
3.小结
为什么要两阶段提交?一阶段提交不行吗?
小伙伴们知道,MySQL中的事务是两阶段提交,我们见到的很多分布式事务也都是两阶段提交的,例如Seata,那么为什么要两阶段提交呢?一次直接提交了不行吗?今天我们来聊聊这个话题。
关于分布式事务seata,不懂的小伙伴可以参考松哥之前的文章,传送门:
五分钟带你体验一把分布式事务!soeasy!看了那么多博客,还是不懂TCC,不妨看看这个案例!XA事务水很深,小伙子我怕你把握不住!你这Saga事务保“隔离性”吗?1.什么是两阶段提交1.1binlog与redologbinlogbinlog我们中文一般称作归档日志,如果大家看过松哥之前发的MySQL主从搭建,应该对这个日志有印象,当我们搭建MySQL主从的时候就离不开binlog(传送门:MySQL8主从复制踩坑指南)。
binlog是MySQLServer层的日志,而不是存储引擎自带的日志,它记录了所有的DDL和DML(不包含数据查询语句)语句,而且是以事件形式记录,还包含语句所执行的消耗的时间等,需要注意的是:
binlog是一种逻辑日志,他里边所记录的是一条SQL语句的原始逻辑,例如给某一个字段+1,注意这个区别于redolog的物理日志(在某个数据页上做了什么修改)。binlog文件写满后,会自动切换到下一个日志文件继续写,而不会覆盖以前的日志,这个也区别于redolog,redolog是循环写入的,即后面写入的可能会覆盖前面写入的。一般来说,我们在配置binlog的时候,可以指定binlog文件的有效期,这样在到期后,日志文件会自动删除,这样避免占用较多存储空间。根据MySQL官方文档的介绍,开启binlog之后,大概会有1%的性能损耗,不过这还是可以接受的,一般来说,binlog有两个重要的使用场景:
MySQL主从复制时:在主机上开启binlog,主机将binlog同步给从机,从机通过binlog来同步数据,进而实现主机和从机的数据同步。MySQL数据恢复,通过使用mysqlbinlog工具再结合binlog文件,可以将数据恢复到过去的某一时刻。redolog前面我们说的binlog是MySQL自己提供的,在MySQL的server层,而redolog则不是MySQL提供的,是存储引擎InnoDB自己提供的。所以在MySQL中就存在两类日志binlog和redolog,存在两类日志既有历史原因(InnoDB最早不是MySQL官方存储引擎)也有技术原因,这个咱们以后再细聊。
我们都知道,事务的四大特性里面有一个是持久性,即只要事务提交成功,那么对数据库做的修改就被永久保存下来了,写到磁盘中了,怎么做到的呢?其实我们很容易想到是在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中,一旦写到磁盘中,就不怕数据丢失了。
但是要是每次都这么搞,数据库就不知道慢到哪里去了!因为Innodb是以页为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这个时候将完整的数据页刷到磁盘的话,不仅效率低,也浪费资源。效率低是因为这些数据页在物理上并不连续,将数据页刷到磁盘会涉及到随机IO。
有鉴于此,MySQL设计了redolog,在redolog中只记录事务对数据页做了哪些修改。那有人说,写redolog不就是磁盘IO吗?而写数据到磁盘也是磁盘IO,既然都是磁盘IO,那干嘛不把直接把数据写到磁盘呢?还费这事!
此言差矣。
写redolog跟写数据有一个很大的差异,那就是redolog是顺序IO,而写数据涉及到随机IO,写数据需要寻址,找到对应的位置,然后更新/添加/删除,而写redolog则是在一个固定的位置循环写入,是顺序IO,所以速度要高于写数据。
redolog本身又分为:
日志缓冲(redologbuffer),该部分日志是易失性的。重做日志(redologfile),这是磁盘上的日志文件,该部分日志是持久的。MySQL每执行一条DML语句,先将记录写入redologbuffer,后续在某个时间点再一次性将多个操作记录写到redologfile,这种先写日志再写磁盘的技术就是MySQL里经常说到的WAL(Write-AheadLogging)技术(预写日志)。
1.2两阶段提交在MySQL中,两阶段提交的主角就是binlog和redolog,我们来看一个两阶段提交的流程图:
从上图中可以看出,在最后提交事务的时候,有3个步骤:
写入redolog,处于prepare状态。写binlog。修改redolog状态变为