https://blog.51cto.com/13476134/2370714
本文开始讲组提交和二阶段提交前,先了解下BINLOG和REDO LOG;
两个日志关系
在ORACLE 对应的是REDO LOG和ARCHIVE LOG ,只是两者关系不一样。 在ORACLE数据库里 ARCHIVE LOG 是 REDO LOG的 历史日志记录。 REDO LOG 就记录当前数据库修改行为的日志。 REDO LOG 一般分成3组, 每组里面必须有1个日志文件,自然可以1个以上的日志文件。通过切换组 就可以把REDO LOG 文件写入到ARCHIVE LOG文件中。
在MYSQL 里面 INNDOB的REDO LOG和MYSQL 的BINLOG 是两个独立体,不像ORACLE是时间上的关系。因为MYSQL 里面可以包含多个存储引擎,每个引擎有自己的独立日志。BINLOG是处于MYSQL的服务层,而REDO LOG 是INNDODB存储引擎层。当一个事务涉及了多个存储引擎的时候,也就是跨了引擎。那么只有BINLOG记录的才是唯一正确的,而INNODB记录的只是事务修改了INNODB引擎的,而该事务修改别的引擎就无法记录了。所以在MYSQL里面一切以BINLOG为主。
REDO 组提交
所为组提交,是只一组事务一起提交。innodb Redo log的刷盘操作将会是最终影响MySQL TPS的瓶颈所在。虽然有innodb_flush_log_at_trx_commit 参数来提高性能,不过还是不给力.
该参数的有效值有 0、1、2:
0:事务提交时,不将重做日志缓冲写入磁盘,而是依靠 InnoDB 的主线程每秒执行一次刷新到磁盘。
1:事务提交时,会将重做日志缓冲写入磁盘,并且立即刷新
2:事务提交时,会将重做日志缓冲写入磁盘,但是不会立即进行刷新操作,因此只是写到了操作系统的缓冲区。
可以看到,只有1才能真正地保证事务的持久性,但是由于刷新操作 fsync() 是阻塞的,直到完成后才返回,我们知道写磁盘的速度是很慢的,因此 MySQL 的性能会明显地下降。如果不在乎事务丢失,,0和2能获得更高的性能。
我又要这个保证数据写入磁盘,又要提高并发性 ,那么怎么办才好呢?
呵呵 就一组事务提交呗! 起码提高下下性能!
在ORACLE 也有组提交功能,那就是 批量日志写
alter system set commit_logging=batch scope=both;alter system set commit_wait=nowait scope=both;
在ORACLE写日志文件的行为由LGWR进程完成,写文件时机有以下几点
1 数据文件写
2 日志缓存满了1MB
3 日志缓存满了1/3
4 每隔3秒
5 事务的COMMIT语句。
设置了批量日志写参数后,实际上就忽略掉了第五个条件。从而达到了组提交的功能。
虽然实现了REDO LOG的组提交,却挖了坑埋掉了BINLOG的主从关系,因为组提交导致了主从数据不一致。原本BINLOG和REDO LOG 之间如何协调的呢?
当事务提交的时候,BINLOG向各个存储引擎喊话,兄弟们我要提交了,各个兄弟收到了! 然后BINLOG听到了兄弟的回应后,就再不管兄弟们了,自己把日志同步到磁盘上,然后在BINLOG打下COMMIT标记而已。
这坑就是 你兄弟玩组提交,我提交了你没提交,你大爷的中间时间主机崩溃了,启动了从库来当主库。 从库起来后发现BINLOG该事务提交了,而INNODB里面毛该数据。本来在单实例中,恢复的时候INNODB会参考BINLOG,如果BINLOG该事务提交了,那我INNODB该事务没有提交就提交下。如果BINLOG该事务没有提交,而我提交了则回滚掉。
二阶段提交:
就是解决这个BINLOG和REDO LOG 数据不一致性。其实呢分成了4个阶段,每个阶段都使用队列锁来控制。其实算法不好理解。总之是BINLOG和兄弟们之间加强了关系。也就是BINLOG除了前面说的喊话后,收到了回应,还要等兄弟们把日志同步完,自己才做同步工作,然后给两个日志都打上COMMIT标记。
- Prepare Innodb:
a) Write prepare record to Innodb's log buffer
b) Sync log file to disk -- redo组提交
c) Take prepare_commit_mutex
- "Prepare" binary log:
a) Write transaction to binary log
b) Sync binary log based on sync_binlog
- Commit Innodb:
a) Write commit record to log
b) Release prepare_commit_mutex
c) Sync log file to disk
d) Innodb locks are released
- "Commit" binary log:
a) Nothing necessary to do here.
MySQL 5.6 引入BLGC(Binary Log Group Commit),二进制日志的提交过程分成三个阶段,Flush stage、Sync stage、Commit stage。
那么事务提交过程简化为:
存储引擎(InnoDB) Prepare ----> 数据库上层(Binary Log) Flush Stage ----> Sync Stage ----> 调存储引擎(InnoDB)Commit stage.
看不懂上面的,就看下面的图吧!