理解MYSQL組提交和二階段提交

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標記。

  1. Prepare Innodb:

a) Write prepare record to Innodb's log buffer

b) Sync log file to disk -- redo組提交

c) Take prepare_commit_mutex

  1. "Prepare" binary log:

a) Write transaction to binary log

b) Sync binary log based on sync_binlog

  1. Commit Innodb:

a) Write commit record to log

b) Release prepare_commit_mutex

c) Sync log file to disk

d) Innodb locks are released

  1. "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.

看不懂上面的,就看下面的圖吧!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章