地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【MySQL】binlogとredoログの2PC

Auroraの機能で2PCに対する最適化を行うというのがあった。そういえばbinlogとredoログの2PCについてよく理解してないのでまとめる

2PCとは

DBの2PC(Two-Phase Commit)は、分散データベースシステムでのトランザクションのコミットプロトコルの一つです。分散データベースシステムでは、複数のデータベースやリソースが関与するトランザクションを処理する際に、トランザクションの一貫性を確保するために2PCが使用されます。

2PCは、トランザクションのコミットプロセスを2つの段階に分けて行います。

Prepare Phase: トランザクションをコミットする際、まずコーディネータ(通常はトランザクションマネージャやコーディネータノード)が各参加ノードに対して準備を依頼します。各参加ノードは、トランザクションを実際にコミットしても良いかどうかを確認し、準備ができたら「準備完了」を通知します。

Commit Phase: コーディネータが各参加ノードから「準備完了」の通知を受け取った後、トランザクションを正式にコミットするかどうかを判断します。全ての参加ノードが準備完了の通知を返した場合、コーディネータは各参加ノードに対してコミットを要求します。参加ノードはコミットを実施し、それに応じた応答を返します。

2PCプロトコルを使用することで、分散データベースシステムにおいて、トランザクションがアトミックかつ一貫した状態でコミットされることが保証されます。

ここまで書いていると気づくが2PCは全体の性能を低下させる要因となる。MySQLはbinlogとredologへの書き込みはこの2PCを通して行われています。

binlogとredo log

MySQL のログは、binlogと redo logの 2 つのデータソースに保存する必要があり、保存時に一貫性の問題が必然的に発生します。例えばredoログに書き込んだ後にMySQLがクラッシュしたとしたらbinlogとの内容が一致しないということが起こり得ます。処理としては以下のようになります。

  1. prepare状態にしredo logへ書き込む
  2. binlogへ書き込む
  3. redo logをcommitへ変更する

リカバリ

  1. 最後のbinlogをスキャンして xid を抽出します (binlog内のイベントを特定します)
  2. xid は redo logにも書き込まれます。redo logのprepareの xid と最後のbinlogの xid を比較します。 binlogに存在する場合はcommit、存在しない場合はロールバックを行う

Auroraのすごさ

こういった流れが必要となる。clientには3が完了するまでcommitは返らないので性能に影響があるということでした。それぞれメモリに書くだけじゃなくfsync(2)までやってるだろうから(syncのタイミングはチューニングできるが)仕方のない話に思えるがAuroraはこれを最適化してきたということですごい...となったのでした。

Aurora MySQL はバイナリログをバイナリログ用に最適化された特殊なストレージノードに保存するという手法で2PCを並列でやることで高速化を図ったというものらしい。並列化するとredo logとbinlogで書き込まれる内容の順序に不整合が起きそうだがこの特殊なストレージノードで順番を入れ替えてしまうらしい。なんともすごい技術だ。