準同期レプリケーションとは
準同期レプリケーションは完全な同期レプリケーションではなく、マスター上でトランザクションが実行されると、COMMIT が完了する前にスレーブへバイナリログの転送が完了する、という形で同期を取っている。
以下に準同期レプリケーションの概要図を示す。
準同期レプリケーションでは、クライアントへ COMMIT の応答を返す前に、スレーブから ACK が返却されるのを待つ。なお、上記の 7-1 と 7-2a は並列して実行されるため、どちらが先に完了するかはわからず、クライアントへ応答が返った時点でスレーブ上で更新の適用が完了しているかもしれないが、その保証はない。これが準同期と言われる所以である。
なお、sync_binlog=1 のとき、通常の COMMIT においても MySQL 内部ではバイナリログとストレージエンジンのデータを同期するために 2 相コミットが用いられている。まずストレージエンジン側で PREPARE し、バイナリログを更新 (write) して、ディスクへの同期 (fsync) も完了させ、その後あらためてストレージエンジン側で COMMIT が行われる。もし PREPARE が完了した時点で MySQL サーバがクラッシュした場合、再起動後のリカバリでは、バイナリログにトランザクションが残っていればあらためて COMMIT が実行され、そうでなければトランザクションはロールバックするようになっている。つまり、バイナリログへの fsync が完了したかどうかによって更新が永続化するかどうか決まる。
ステップ 6 ではスレーブに確実にデータが残ることを保証するため、ACK はリレーログのディスクへの同期を待ってから返送される。そのため、スレーブのディスクが遅いと、マスター上でのコミットに時間がかかってしまうという問題が起きる。そもそも準同期レプリケーションは通常のレプリケーションと比べてコミットのオーバーヘットが大きいが、ACK 遅延は特に問題になりやすい。
準同期レプリケーションの設定
準同期レプリケーションをセットアップするには以下の手順が必要になる。
- プラグインのインストール
- オプションの設定
- IO スレッドのリスタート
1. プラグインのインストール
準同期レプリケーションはレプリケーションのプラグインとして実装されており、初期状態では組み込まれていないので、まずはインストールする必要がある。
[ マスター側 ]
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.00 sec)
[ スレーブ側 ]
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.00 sec)
2. オプションの設定
プラグインをインストールすると、準同期レプリケーション用のシステム変数が追加されている。
[ マスター側 ]
mysql> SHOW VARIABLES LIKE 'rpl_semi%';
+------------------------------------+-------+
| 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_no_slave | ON |
+------------------------------------+-------+
4 rows in set (0.00 sec)
[ スレーブ側 ]
mysql> SHOW VARIABLES LIKE 'rpl_semi%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled | OFF |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
2 rows in set (0.00 sec)
以下のように準同期レプリケーションを有効化する。
[ マスター側 ]
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
Query OK, 0 rows affected (0.00 sec)
[ スレーブ側 ]
mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;
Query OK, 0 rows affected (0.00 sec)
なお、rpl_semi_sync_master_timeout はマスターが ACK を待つまでのタイムアウトである。もしスレーブに何らかのトラブルが発生して、長時間 ACK を返せなくなった際に備えて、タイムアウトを指定することができるようになっている。一定期間を過ぎても ACK が返ってこない場合は、自動的に非同期モードに以降するようになっている。
一旦非同期モードになった場合、スレーブから何も反応がなければずっと非同期モードのままであり、再び準同期モードに復帰するのは次にスレーブから ACK を受け取ったタイミングとなる。
3. IO スレッドのリスタート
最後に IO スレッドをリスタートする必要がある。
mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.01 sec)
mysql> START SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)