Semisynchronous Replication (半同期レプリケーション?)を試してみた

今までの非同期レプリケーションでは、同期完了前にマスターが死んだ場合に、データのロストが起きるが、MySQL5.5から導入された Semisynchronous Replication(半同期?)を使うと、スレーブ側のバイナリログの更新までが同期で行われるのでデータのロストの可能性がぐっと減る。今回はMySQL5.5.5_m3 というバージョンを使って検証した。
OSは、CentOS5.5-64bit。RPMOracle のサイトからダウンロード。

MySQL-client-5.5.5_m3-1.rhel5.x86_64.rpm
MySQL-server-5.5.5_m3-1.rhel5.x86_64.rpm
MySQL-devel-5.5.5_m3-1.rhel5.x86_64.rpm
MySQL-shared-compat-5.5.5_m3-1.rhel5.x86_64.rpm

テストを簡単にするためにDBはtestを使用し、テーブル無しの状態から。

master:10.0.7.8、 slave:10.0.7.8 とする。

  • マスター側の設定

プラグインのインストールとユーザ追加

mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

mysql> CREATE USER 'repl'@'%' IDENTIFIED BY 'pw';     #レプリケーション用のユーザの作成
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';  #レプリケーション用のユーザへの「REPLICATION SLAVE」権限設定

/etc/my.cnfの編集

[mysqld]
log-bin=mysql-bin
server-id=1
innodb_flush_log_at_trx_commit=1
sync_binlog=1

rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=10

ログの位置確認

mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      107 |              |                  |
+------------------+----------+--------------+------------------+

上記の値を以下で使用する。

  • スレーブ側の設定

プラグインのインストール

mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

/etc/my.cnfの編集

[mysqld]
server-id=2
rpl_semi_sync_slave_enabled=1
mysql> CHANGE MASTER TO MASTER_HOST='10.0.7.8', MASTER_USER='repl', MASTER_PASSWORD='pw', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=107;
mysql> STOP SLAVE IO_THREAD;
mysql> START SLAVE IO_THREAD;
mysql> START SLAVE;
  • テスト開始

マスター側

mysql> CREATE TABLE `t1` (`id` int(11) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
mysql> INSERT INTO `t1` VALUES(1);
mysql> INSERT INTO `t1` VALUES(2);
mysql> INSERT INTO `t1` VALUES(3);
mysql> SELECT * FROM `t1`;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.01 sec)

スレーブ側

mysql> SELECT * FROM `t1`;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.01 sec)

これでは、semisynchronousレプリケーション なのか、asynchronous レプリケーション のどちらでレプリケーションされたかわからない。

次に、SLAVE側のSQL_THREADを停止して、ログの位置を確認する。(878)

スレーブ側

mysql> STOP SLAVE SQL_THREAD;
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
	<省略>
          Read_Master_Log_Pos: 878
          Exec_Master_Log_Pos: 878
	<省略>
1 row in set (0.00 sec)

次にマスター側にレコードを追加してログの位置を確認する。「1062」まで進んでいるのがわかる。

mysql> INSERT INTO `t1` VALUES(4);
mysql> SELECT * FROM `t1`;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
+------+
4 rows in set (0.00 sec)

mysql> SHOW MASTER STATUS\G
*************************** 1. row ***************************
            File: mysql-bin.000002
        Position: 1062
    Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.00 sec)


次にスレーブ側のログの位置を確認する。「1062」まで作成されているが、「878」までしか実行されていない。テーブルの中身を確認すると3レコードのまま。

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
          Read_Master_Log_Pos: 1062
          Exec_Master_Log_Pos: 878

mysql> SELECT * FROM `t1`;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

semisynchronousレプリケーション により、バイナリログは正常に同期されていることがわかる。この時点で、マスター側を停止しても、スレーブ側へのレプリケーションが問題なく行われることを確認する。

マスター側のMySQLを停止する。

# service mysql stop

スレーブ側のSQL_THREADを再開する。ログの位置が「1062」まで実行されている。テーブルの中身を確認すると4レコードに増えていることを確認する。

mysql> START SLAVE SQL_THREAD;

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
          Read_Master_Log_Pos: 1062
          Exec_Master_Log_Pos: 1062

mysql> SELECT * FROM `t1`;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
+------+
4 rows in set (0.01 sec)