二阶段提交

什么是两阶段提交
当有数据修改时,会先将修改redo log cache和binlog cache然后在刷入到磁盘形成redo log file,当redo log file全都刷入到磁盘时(prepare 状态)和提交成功后才能将binlog cache刷入磁盘,当binlog全部刷新到磁盘后会记录一个xid,然后在relo log file上打上commit标志(commit阶段)。

https://blog.csdn.net/weixin_46370070/article/details/108060554

为什么要有两阶段提交
MySQL在修改数据时,MySQL是先从磁盘中将数据copy到内存,然后再将内存中的数据进行修改,并记录redo log buffer 然后在通过系统调用将事务日志写入磁盘redo log file 最后最后事务提交后将内存中修改后的数据在开始写入磁盘中。
1.当只有redo og,binlog失效时,会导致主库可以通过redo log来重做,而从库因为没有及时获取到binlog而不能进行回放,导致主从数据不一致。
2.当只有binlog和redo log失效时会导致在主宕机时不能根据redo log重做,而从导致主从数据不一致。

与两阶段提交相关的概念
1.redo log
redo是重做,保证数据提交后不会丢失更新。在数据修改还没有写入磁盘的时候,如果发生宕机的话,可以根据redo log 进行重做,在将修改好的数据写入磁盘。保证了数据的原子性和一致性。redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)没有提交的会进行回滚。
Redo中包含两个部分:在内存中的日志缓存redo log buffer(此部分日志是易失去的),还有一部分是写入磁盘中重做日志文件edo lorg file(是持久的,因为已经落盘了),innodb通过force log at commit机制实现事务的持久性,即在事务提交的时候,必须先将该事务的所有事务日志写入到磁盘上的redo log file和undo log file中进行持久化。
为了确保每次日志都能写入到事务日志文件中,在每次将log buffer中的日志写入日志文件的过程中都会调用一次操作系统的fsync操作(即fsync()系统调用)。因为MariaDB/MySQL是工作在用户空间的,MariaDB/MySQL的log buffer处于用户空间的内存中。要写入到磁盘上的log file中,中间还要经过操作系统内核空间的os buffer,调用fsync()的作用就是将OS buffer中的日志刷到磁盘上的log file中。
Redo log buffer 刷新到磁盘的方式有3中。
1.每秒刷新到磁盘一次,这样可以解决大事务迟迟不提交的情况。
2.每提交一次事务刷新到磁盘一次。
3.当redo log buffer的大小大于innoldb_log_buffer_size的大小的一半时就会刷盘。

MySQL支持用户自定义在commit时如何将log buffer中的日志刷log file中。这种控制通过变量 innodb_flush_log_at_trx_commit 的值来决定。该变量有3种值:0、1、2,默认为1。但注意,这个变量只是控制commit动作是否刷新log buffer到磁盘。

当设置为1的时候,事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file on disk中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。
当设置为0的时候,事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file on disk中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。每秒写入os buffer 每秒刷入到磁盘。
当设置为2的时候,每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。Redo log buffer 刷新到磁盘的方式有3中。
1.每秒刷新到磁盘一次,这样可以解决大事务迟迟不提交的情况。
2.每提交一次事务刷新到磁盘一次。
3.当redo log buffer的大小大于innoldb_log_buffer_size的大小的一半时就会刷盘。

MySQL支持用户自定义在commit时如何将log buffer中的日志刷log file中。这种控制通过变量 innodb_flush_log_at_trx_commit 的值来决定。该变量有3种值:0、1、2,默认为1。但注意,这个变量只是控制commit动作是否刷新log buffer到磁盘。

当设置为1的时候,事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file on disk中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。
当设置为0的时候,事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file on disk中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。每秒写入os buffer 每秒刷入到磁盘。
当设置为2的时候,每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。

2.undo log
Undo是回滚,撤销,在事务提交后可以根据undo log 回到任意一个版本,保证了数据的持久性。
一种情况是,查看 Undo 日志记录发现某事务有提交记录,该事务对数据库所做的全部修改均己从主存写入磁盘。所以这一事务不会造成不一致的数据库状态,对于这种已提交事务不需要进行任何处理。

另一种情况是,查看 undo日志记录发现某一事务有开始记录但没有提交记录,则可能数据库故障或崩溃前该事务对数据库的部分修改己写入磁益,而另一部分修改还保存在主存中而未写入磁盘,甚至可能还有部分修改在主存中都还未完成,这种事务属于未提交事务。由于不能确定该事务对数据库的修改是否己全部完成并写入磁盘.所以该事务必须被撤销并将其对数据库元素的修改恢复原值。根据规则 1 的规定,如果数据库故障或崩溃前,事务修改了数据库元素 X 的值,则日志中必定写入了<T , X , V>日志纪录,并且该日志记录己写入磁盘.所以只需要将数据库元素 X 的值恢复为 V 即可。
事务开始之前,系统就开始生成undolog,当事务提交之后,undo log并不能立马被删除,而是放入待清理的链表,由purge线程去处理。
回滚日志除了能够在发生错误或者用户执行 ROLLBACK 时提供回滚相关的信息,它还能够在整个系统发生崩溃、数据库进程直接被杀死后,当用户再次启动数据库进程时,还能够立刻通过查询回滚日志将之前未完成的事务进行回滚.
因为回滚只对未进行commit的事务有效,回滚日志并不能将数据库物理地恢复到执行语句或者事务之前的样子;它是逻辑日志,当回滚日志被使用时,它只会按照日志逻辑地将数据库中的修改撤销掉。

3.binlog
Binlog是在事务在进行增删改的时候就会计入binlog,可以用来备份和恢复。
Binlog的三种格式:基于语句的,基于行的,混合型的
可通过my.cnf配置文件及 set global binlog_format=‘ROW/STATEMENT/MIXED’ 进行修改,命令行 show variables like ‘binlog_format’ 命令查看binglog格式;
基于语句的(statement):记录的是每个修改的语句,每一条会修改数据的sql都会记录在binlog中。
优点:只需要记录执行语句的细节和上下文环境,避免了记录每一行的变化,在一些修改记录较多的情况下相比ROW level能大大减少binlog日志量,节约IO,提高性能;还可以用于实时的还原;同时主从版本可以不一样,从服务器版本可以比主服务器版本高
缺点:为了保证sql语句能在slave上正确执行,必须记录上下文信息,以保证所有语句能在slave得到和在master端执行时候相同的结果;另外,主从复制时,存在部分函数(如sleep,datatime())及存储过程在slave上会出现与master结果不一致的情况,而相比Row level记录每一行的变化细节,绝不会发生这种不一致的情况。
基于row:(5.7默认是row格式)
仅保存记录被修改细节,不记录sql语句上下文相关信息优点:能非常清晰的记录下每行数据的修改细节,不需要记录上下文相关信息,因此不会发生某些特定情况下的procedure、function、及trigger的调用触发无法被正确复制的问题,任何情况都可以被复制,且能加快从库重放日志的效率,保证从库数据的一致性
缺点:由于所有的执行的语句在日志中都将以每行记录的修改细节来记录,因此,可能会产生大量的日志内容,干扰内容也较多;比如一条update语句,如修改多条记录,则binlog中每一条修改都会有记录,这样造成binlog日志量会很大,特别是当执行alter table之类的语句的时候,由于表结构修改,每条记录都发生改变,那么该表每一条记录都会记录到日志中,实际等于重建了表。
binlog刷盘是由sync_binlog控制,sync_binlog=0表示由系统自己控制(性能较好,风险较大)。Sync_binlog=n表示在执行n次事务之后进行落盘(一般是n=1即每提交一次事务就落盘)

根据两阶段提交的恢复过程
恢复原理
扫描最后一个Binlog文件,提取其中的Xid_log_event重做检查点以后的redo日志,读取事务的undo段信息,搜集处于prepare阶段的事务链表,将事务的xid与binlog中的xid对比,若存在,则提交,否则就回滚。

恢复过程
1.在prepare阶段carsh
因为事务还没有提交,binlog还没有写入磁盘,该事务会直接rollback.
2.事务在将binlog cache写入磁盘的时候crash
因为该事务还没有全部写入磁盘,故此时xid不会写入到binlog,会认为该事务并没有提交,所以会将该事务回滚。
3.事务已经全部刷新到磁盘,但在引擎层还没有commit
因为在binlog中已经有该事务的xid,所以会将该事务在引擎层提交,然后将redo log checkpoint点之后的事务进行重做。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值