MySQL的两阶段提交
Posted 生活过于潦草的学习小屋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL的两阶段提交相关的知识,希望对你有一定的参考价值。
mysql的两阶段提交
解决的问题:保证了事务在多个日志间的原子性
在MySQL中存在着两个日志系统:server层的binlog和执行引擎层的redolog,如何保证两个日志的原子性,即要么都提交要么都终止?
- 在此MySQL使用了两阶段提交:
这里我借用了丁奇大佬的示意图。
两阶段提交保证了原子性,也保证了crash safe能力,这里存在的一点疑惑是,究竟如何实现的?考量到大佬没有讲更多实现细节,我查找了一些资料总结一下。
MySQL 内部XA
MySQL采用了如下过程实现了内部XA的两阶段提交:
- Prepare阶段:InnoDB将回滚端设置为prepare阶段,redolog落盘,这里在45讲中没有说清楚的是,redolog也是会持久化到磁盘上的,并不是只存在于内存中,否侧系统奔溃时一样失去crash safe能力,不过相较于在数据库中的随机IO,redolog落盘是顺序IO,相较有更好的性能。
- Commit阶段:binlog写入文件,落盘,InnoDB commit
崩溃恢复的具体情况:
需要注意的是,commit标志不是事务的成功与否标志,binlog写入才是
- prepare阶段奔溃,写入了redolog但没有写入binlog--->回滚
- commit阶段奔溃,若没有成功写入binlog---->回滚
- 如果成功写入binlog,commit标志不再重要,会重新写入commit标志---->提交事务
崩溃恢复过程
以binlog中的xid为准
- 找到最后一个binlog,将redolog刷盘,将binlog中的xid添加到一个hash中,提交给InnoDB引擎
- InnoDB引擎遍历每一个还在prepared状态的事务,确定是否要回滚
// recovery mode
if (info->commit_list
? info->commit_list->count(x) != 0
: tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT) {
// 1. 如果 XID 在 hash 里,说明 redolog 和 binlog 都已经完成了事务的刷盘,可以提交
hton->commit_by_xid(hton, &info->list[i].id);
} else {
// 2. 如果 XID 不在 hash 里,说明 redolog 完成刷盘,但是 binlog 还没有刷盘,2PC 没有成功,需要回滚
hton->rollback_by_xid(hton, &info->list[i].id);
}
可以看到的是一切以binlog中的xid为基准进行提交或回滚
参数设置
innodb_flush_log_at_trx_commit
参数:
- {0|1|2} : 指定何时将事务日志刷到磁盘,默认为1。
- 0表示每秒将"log buffer"同步到"os buffer"且从"os buffer"刷到磁盘日志文件中。
- 1表示每事务提交都将"log buffer"同步到"os buffer"且从"os buffer"刷到磁盘日志文件中。
- 2表示每事务提交都将"log buffer"同步到"os buffer"但系统决定"os buffer"刷到磁盘日志文件中的时间。
sync_binlog
:
- 这个参数设置成 1 的时候,表示每次事务的 binlog 都持久化到磁盘。这个参数我也建议你设置成 1,这样可以保证 MySQL 异常重启之后 binlog 不丢失
以上是关于MySQL的两阶段提交的主要内容,如果未能解决你的问题,请参考以下文章