ロスレスレプリケーション

August 09, 2018

ロスレスレプリケーションとは

MySQL 5.6 までの準同期レプリケーションではスレーブからの ACK を待つのは、クライアントに応答を返す直前となる。この仕組みだと、もしマスターがクラッシュしてスレーブを昇格させた際に、クラッシュ前のマスターにしか存在しないデータが発生してしまう可能性がある。
例えば以下のような状況。

  1. マスターがデータ A を書き込む
  2. データ A がバイナリログに書き込まれる
  3. データ A がストレージエンジンに COMMIT される
  4. この時点でデータ A に対するロックが解除され、ほかのトランザクションはデータ A を参照できるようになる
  5. クライアントへの応答が停止され、ACK 待ち状態になる
  6. データ A がスレーブへ転送される前にマスターがクラッシュする

もしこのような状況で、アプリケーションが他のセッションからデータ A を参照してしまった場合、アプリケーションはデータ A がデータベース上に永続化することを期待するが、スレーブを昇格してもデータ A は存在しないことになる。

この問題を解決するために、MySQL 5.7 では、マスター側で COMMIT する前に ACK を待つように変更が加えられている (ロスレスレプリケーション)。
この概要を以下の図に示す。

f:id:shiro_kochi:2018××××××××:plain:w100:left

上記の仕組みにより、マスター上で COMMIT が完了したトランザクションはすべてスレーブへ伝達されたことが保証される。どのスレーブを昇格してもデータが失われることはない。
このような動作に変更したことで、クラッシュ前には InnoDB への COMMIT が完了していないため、対になるスレーブだけにデータが存在する状態ができてしまいそうであるが、その心配はない。なぜなら sync_binlog=1 (かつ innodb_support_xa = 1) の場合、内部的な 2 相コミットにより、スレーブへデータを送信する前はストレージエンジンへの PREPARE は完了しており、かつバイナリログの fsync も完了しているためである。
この状態でマスターがクラッシュし、その後再起動すると、クラッシュリカバリの処理で PREPARE されたトランザクションが COMMIT されるため、マスターでデータの損失は発生しない。
ただし、このように 2 相コミットによるバイナリログを用いたリカバリが行われるのは sync_binlog=1 の場合だけとなる。MySQL 5.7 ではデフォルトになっているので特に変更する必要はない。

なお、どこで ACK を待つかは調整可能であり、MySQL 5.6 と同じ挙動にすることも可能。その場合、rpl_semi_sync_master_wait_point オプションを AFTER_COMMIT に設定すれば良い。デフォルトはバイナリログへ書き込んだあとに ACK を待つモードである AFTER_SYNC となっており、ロスレスレプリケーションとなっている。

mysql> SHOW VARIABLES LIKE '%rpl_semi_sync%';  
+-------------------------------------------+------------+  
| Variable_name                             | Value      |  
+-------------------------------------------+------------+  
| rpl_semi_sync_master_enabled              | OFF        |  
| rpl_semi_sync_master_timeout              | 10000      |  
| rpl_semi_sync_master_trace_level          | 32         |  
| rpl_semi_sync_master_wait_for_slave_count | 1          |  
| rpl_semi_sync_master_wait_no_slave        | ON         |  
| rpl_semi_sync_master_wait_point           | AFTER_SYNC |  
+-------------------------------------------+------------+  
6 rows in set (0.00 sec)  

 © 2023, Dealing with Ambiguity