mysql 5.7基於組提交,group commit

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值,如果值一樣,表明是在同一事務組內。

### INSERT INTO `wukong_test`.`wukong`
### SET
###   @1=3 /* INT meta=0 nullable=1 is_null=0 */
###   @2='ccccc' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
# at 496468
#170527  4:17:35 server id 12001  end_log_pos 496499 CRC32 0xd6e7f69f   Xid = 5556
COMMIT/*!*/;
# at 496499
#170527  4:17:35 server id 12001  end_log_pos 496564 CRC32 0x28816d5c   GTID    last_committed=1845 sequence_number=1846
SET @@SESSION.GTID_NEXT= '0a646c88-36e2-11e7-937d-fa163ed7a7b1:3624'/*!*/;
# at 496564
#170527  4:17:35 server id 12001  end_log_pos 496632 CRC32 0x03150d48   Query   thread_id=1852  exec_time=0 error_code=0
SET TIMESTAMP=1495873055/*!*/;
BEGIN
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章