Weitere ähnliche Inhalte Ähnlich wie binary log と 2PC と Group Commit (20) Mehr von Takanori Sejima (7) binary log と 2PC と Group Commit5. 今日のお題
- 先日、 MySQL5.7 GA の Multi-threaded slave
というお題目でお話させていただく機会があった
のですが
- Multi-Threaded Slave 以外の部分、
Two-Phase Commit と Group Commit の部分
は、 5.7 も MTS も使わない人でも、知っといて
損はない内容なので、今日はそのお話を改めて
させていただきます。
7. はじめに
- そもそも、 slave の SQL_Thread がシングルス
レッドのとき、どのようにして replication で
master と同じ状態が復元されるのか?
- いたってシンプル
- master が注意深く binlog 吐いてる
8. 例えば InnoDB の場合
1. master で更新処理実行中の各スレッドが、そ
れぞれ transaction cache に更新内容をため
ていく
2. InnoDB で PREPARE する(5.7.10 以降、
innodb_support_xa は常に true)
3. 1. の transaction cache から一連の更新処理
を BEGIN&COMMIT で挟んで binlogに書く
4. InnoDBで COMMIT する
9. Two-Phase Commit & Group Commit
- MySQL の Replication 開発者であらせられる
Dr. Mats Kindahl の blog この記事がわかりや
すいですが
- Binary Log Group Commit in MySQL 5.6
- (この後の話に関連して)大事なところを二つだ
けかいつまんで解説すると
10. Two-Phase Commit(2PC)
- 参考になるのは ha_commit_trans() や
MYSQL_BIN_LOG::ordered_commit() あたり
- Binary Log Group Commit in MySQL 5.6 の
Figure.1 のとおり
- storage engine(InnoDBなど)に prepare して
- binlog に 書いて
- binlog に COMMIT(fsync) してから
- storage engineに COMMIT する
11. Transaction Coordinator Log
- ソースコード中に tc_log ってのが出てきますが
- Transaction の順序を管理するための Log の
抽象クラスが TC_LOG であって、その実装の
ひとつが MYSQL_BIN_LOG
- MYSQL_BIN_LOG::prepare() や
MYSQL_BIN_LOG::commit() が、
Two-Phase COMMIT を実現するために必要
な関数を呼んでる
12. innodb_support_xa=true と 2PC
- innodb_support_xa=true だと、 prepare のと
き undo log に xid が書き込まれる(5.7.10以降
は常にそうなる)
- undo log に xid 書き込まれた PREPARED な
transaction は、 クラッシュ後の再起動時、
binlog から xid 読み込んだ後、その xid 使って
innobase_commit_by_xid() で最終的に
COMMIT される
13. なんかややこしいですが
- クラッシュリカバリ時、xid のない PREPARED
は rollback の 対象になるんですが、 xid つき
の PREPARED は binlog からその xid が取得
できれば COMMIT にできるようです。詳しくは
- innobase_xa_prepare()
- MYSQL_BIN_LOG::recover()
- innobase_xa_recover()
- innobase_commit_by_xid()
14. というわけで、 MySQL の 2PC は
- InnoDB のクラッシュリカバリ機能単体では実現
できず、 InnoDB のクラッシュリカバリ機能と
binlog のクラッシュリカバリ機能とが組み合わ
さって、実現されてるようです
- binlog のヘッダには open するときに立てて close する
ときにリセットするフラグがあるので、正常に close した
か(クラッシュしてないか)は、フラグをみて判断してます
15. Group Commit
- Binary Log Group Commit in MySQL 5.6 の
Figure.5 を参照
- flush/sync/commit という stage がある
- binlog へ書き出す のが flush stage
- binlog に fsync() する のが sync stage
- storage engine に commit するのが commit stage
- flush stage に書きだした順序で、 commit
stage で commit することが保証されている
16. ソースコード的にいうと
- Group Commit はまさに
MYSQL_BIN_LOG::ordered_commit()
- flush/sync/commit の stage を queue で管理
することによって、 fsync() の回数を減らして、
binlog に event 書き出す順番と storage
engine に commit する順番を担保している
- そして、 binlog に書くとき、各 Transaction を
BEGIN - COMMIT でシリアライズしてる
17. だから binary log は読みやすいし
- そして slave の SQL_Thread は性能がでない
- master は Transaction を並列実行しながらも、
それらをひとかたまりの BEGIN - COMMIT に
まとめシリアライズして binlog に吐いている
- master では並列実行してる Transaction が、
slave だと BEGIN - COMMIT のひとかたまり
が、ひとつずつしか実行できない
- まぁ SQL_Thread はシングルスレッドだしね
18. ではちょっとデモ
1. debug build した mysqld を用意します
2. お手元の gdb で attach します
3. MYSQL_BIN_LOG::sync_binlog_file() あたり
に break point 張って continue します
4. 適当に INSERT などします
5. binlog を fsync() させたら gdb から kill します
6. innobase_commit_by_xid() 実行されます
19. 公式ドキュメントちょっと悩ましい
- XA PREPARE なトランザクションはロールバッ
クする とか sync_binlog=1 のときの挙動 を書
いてるんですが、現状の実装と噛み合ってない
ところもある。
- このへんバグレポートしようかと思ったけど、い
やーなんていうのがいいんだろうむずかしい