MySQL Group Commit 组提交(BLGC)

MySQL 组提交

prepare_commit_mutex锁

  • MySQL5.6以前,为了保证数据库上层二进制日志的写入顺序和InnoDB层的事务提交顺序一致,MySQL数据库内部使用了prepare_commit_mutex锁。但是持有这把锁之后,会导致组提交失败。锁的持有与释放在二阶段中如下:
    • InnoDB prepare (持有prepare_commit_mutex);
    • write/sync Binlog;
    • InnoDB commit (写入COMMIT标记后释放prepare_commit_mutex)。
  • 这样事务提交就是一个一个执行,导致组提交失败。

Binary Log Group Commit(BLGC)

  • MySQL5.6通过BLGC的方式实现了binlog的组提交。
  • binlog组提交的基本思想是,引入队列机制保证innodb commit顺序与binlog落盘顺序一致,并将事务分组,组内的binlog刷盘动作交给一个事务进行,实现组提交目的。 

  • binlog提交将提交分为了3个阶段,FLUSH阶段,SYNC阶段和COMMIT阶段。每个阶段都有一个队列,队列中的第一个事务称为leader,其他事务称为follower,leader控制着follower的行为。BLGC的步骤分为以下三个阶段:

  • FLUSH阶段:
    • 持有Lock_log mutex [leader持有,follower等待]
    • 获取队列中的一组binlog(队列中的所有事务)
    • 将binlog buffer到I/O cache
    • 通知dump线程dump binlog
  • SYNC阶段:
    • 释放Lock_log mutex,持有Lock_sync mutex[leader持有,follower等待]
    • 将一组binlog 落盘(sync动作,最耗时,也是group commit实现了的优化的重点所在)
  • COMMIT阶段:
    • 释放Lock_sync mutex,持有Lock_commit mutex[leader持有,follower等待]
    • 遍历队列中的事务,逐一进行innodb commit(这里不用写redo log,在prepare阶段已写)
    • 释放Lock_commit mutex
    • 唤醒队列中等待的线程
  • 每个stage分配一个线程进行操作。
  • 这种实现的优势在于三个阶段可以并发执行,从而提升效率。(PS:innodb prepare阶段没有变,还是write/sync redo log,打上prepare标记)
  • 每个stage都有自己的队列。每个队列各自有mutex保护,队列之间是顺序的。只有flush完成后,才能进入到sync阶段的队列中;sync完成后,才能进入到commit阶段的队列中。但是,这三个阶段的作业是可以同时并发执行的,即当一组事务在进行commit阶段时,其他新事务可以进行flush阶段,实现了group commit。
  • 当一个事务来到一个stage是一个空队列,那么他就是leader,后面来的事务就是follower,leader控制队列中follower的行为。如果leader带着自己的follower去下一个stage,是非空队列,那么leader变成follower。但是follower不会变成leader。
  • Tips:当引入Group Commit后,sync_binlog的含义就变了,假定设为1000,表示的不是1000个事务后做一次fsync,而是1000个事务组。也就是说,当设置sync_binlog=1,binlog还未落盘,此时系统crash,会丢失对应的最后一个事务组;如果这个事务组内有10个事务,那么这10个事务都会丢失。
  • 如何查看是否属于一个事务组:通过mysqlbinlog可以查看binlog日志中last_committed值,如果值一样,表明是在同一事务组内。
 
  
  1. ### INSERT INTO `wukong_test`.`wukong`
  2. ### SET
  3. ### @1=3 /* INT meta=0 nullable=1 is_null=0 */
  4. ### @2='ccccc' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
  5. # at 496468
  6. #170527 4:17:35 server id 12001 end_log_pos 496499 CRC32 0xd6e7f69f Xid = 5556
  7. COMMIT/*!*/;
  8. # at 496499
  9. #170527 4:17:35 server id 12001 end_log_pos 496564 CRC32 0x28816d5c GTID last_committed=1845 sequence_number=1846
  10. SET @@SESSION.GTID_NEXT= '0a646c88-36e2-11e7-937d-fa163ed7a7b1:3624'/*!*/;
  11. # at 496564
  12. #170527 4:17:35 server id 12001 end_log_pos 496632 CRC32 0x03150d48 Query thread_id=1852 exec_time=0 error_code=0
  13. SET TIMESTAMP=1495873055/*!*/;
  14. BEGIN


参考资料:
http://www.cnblogs.com/cchust/p/4439107.html
http://www.csdn.net/article/2015-01-16/2823591
http://www.linuxidc.com/Linux/2015-11/124942.htm

猜你喜欢

转载自blog.csdn.net/wukong_666/article/details/73321290
今日推荐