MySQL道普請便り

第25回GTIDを使用したレプリケーション構成を作成する[2]

前回の第24回 GTIDを使用したレプリケーション構成を作成する[1]に続いてGTIDについて紹介します。今回は、レプリケーションがエラーで停止してしまった際の対処方法と、MySQL5.7から可能となったオンラインでのGTIDの有効化について説明します。

特定のトランザクションをスキップする

従来のレプリケーションでは、Duplicate entryなどのエラーにてレプリケーションが停止してしまった場合に、SET GLOBAL sql_slave_skip_counter = Nを使用してトランザクションまたはSQLステートメントをスキップすることで、レプリケーションの継続ができました。しかし、GTIDを使用したレプリケーションではこの構文が使用できません。

GTIDを使用したレプリケーションでの対処方法として、以下の2点があります。

  1. 空のトランザクションを使用した方法
  2. gtid_purgedを使用した方法

 トランザクションをスキップすることはレプリケーションを継続できるだけでマスター・スレーブ間のデータの不整合の可能性はあります。

意図的にレプリケーションがエラーで停止するようにして、スレーブのステータスを確認します。

mysql> show slave status \G
 :
 :
 Slave_IO_Running: Yes
Slave_SQL_Running: No
       Last_Errno: 1062
       Last_Error: Error 'Duplicate entry '111' for key 'id'' on query. Default database: 'oo'. Query: 'insert into t values (111,111,111)'
 : 
Retrieved_Gtid_Set: 321e231b-3ce3-11e6-9fe5-0242ac110001:1-12
Executed_Gtid_Set: 3216e1ef-3ce3-11e6-9fe5-0242ac110003:1,
321e231b-3ce3-11e6-9fe5-0242ac110001:1-11

Retrieved_Gtid_Set: 321e231b-3ce3-11e6-9fe5-0242ac110001:1-12からトランザクションID:12番目まで、スレーブはマスターから更新情報を受け取っているのがわかります。

Executed_Gtid_Set: 3216e1ef-3ce3-11e6-9fe5-0242ac110003:1,321e231b-3ce3-11e6-9fe5-0242ac110001:1-11からトランザクションID:11番目までスレーブで実行されたのがわかるので、12番目のトランザクションにてLast_Error: Error 'Duplicate entryが発生したということです。

それぞれの対処方法で12番目のトランザクションをスキップさせてみます。

空のトランザクションを使用した方法

スレーブで実行します。

セッション変数GTID_NEXTに対象のGTIDを格納して、空のトランザクションを実行します。その後、GTID_NEXTAUTOMATICをセットすることでスレーブのバイナリログには12番目のトランザクションに空のトランザクションが記述され、レプリケーションを開始することで、次の13番目のトランザクションをマスターに要求するようになります。

mysql> SET GTID_NEXT='321e231b-3ce3-11e6-9fe5-0242ac110001:12';
mysql> BEGIN;
mysql> COMMIT;

mysql> SET GTID_NEXT='AUTOMATIC';

しかし、これではマスターのバイナリログとスレーブのバイナリログの内容が変わってしまうため、レプリケーションを開始する前にスレーブのバイナリログの削除が推奨されています。

FLUSH LOGSでバイナリログをローテートさせ、それ以前のログを削除します。

mysql> FLUSH LOGS;

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       198 |
| mysql-bin.000002 |       686 |
| mysql-bin.000003 |       427 |
| mysql-bin.000004 |       191 |
+------------------+-----------+

mysql> PURGE BINARY LOGS TO 'mysql-bin.000004';

そして、レプリケーションを開始させます。

mysql> START SLAVE;

gtid_purgedを使用した方法

gtid_purgedはバイナリログから消去されたすべてのトランザクションのセットを格納するグローバル変数です。gtid_purgedに対して先ほどのスキップさせたいトランザクションを設定します。

mysql> SET global gtid_purged='321e231b-3ce3-11e6-9fe5-0242ac110001:12';
ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.

実行するとエラーとなりました。gtid_executedが空欄でなければ設定できないという表示です。gtid_executedはSHOW SLAVE STATUSのExecuted_Gtid_Setと同様の値で、これをを空欄にするにはスレーブでRESET MASTERを実施します。そして、gtid_purgedを設定します。

mysql> reset master;
Query OK, 0 rows affected (0.02 sec)

mysql> show global variables like 'GTID%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| gtid_executed |       |
| gtid_mode     | ON    |
| gtid_owned    |       |
| gtid_purged   |       |
+---------------+-------+

mysql> SET global gtid_purged='321e231b-3ce3-11e6-9fe5-0242ac110001:12';
Query OK, 0 rows affected (0.01 sec)

mysql>  show global variables like 'GTID%';
+---------------+-----------------------------------------+
| Variable_name | Value                                   |
+---------------+-----------------------------------------+
| gtid_executed | 321e231b-3ce3-11e6-9fe5-0242ac110001:12 |
| gtid_mode     | ON                                      |
| gtid_owned    |                                         |
| gtid_purged   | 321e231b-3ce3-11e6-9fe5-0242ac110001:12 |
+---------------+-----------------------------------------+

RESET MASTERすることによりスレーブのバイナリログはリセットされ、指定したトランザクション番号以降(今回の例では13番目)のトランザクションから記述されます。

そして、レプリケーションを開始させます。

mysql> start slave;

MySQL5.7からオンラインでGTIDへ変更することが可能

MySQL 5.7.6以降から従来のレプリケーション構成から、オンラインにてGTIDを使用したレプリケーション構成へ変更が可能です。

今回はMySQL 5.7.13をyumリポジトリーを使用しインストールして確認しています。事前に従来の方式でレプリケーションを設定しておきます。GTIDが有効でないことを確認します。

mysql> select @@gtid_mode;
+-------------+
| @@gtid_mode |
+-------------+
| OFF         |
+-------------+
1 row in set (0.00 sec)

[手順1]マスター・スレーブ共にENFORCE_GTID_CONSISTENCYWARNに設定

mysql> SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = WARN;

WARNにすることで、前回説明したGTIDを使用したレプリケーションの制限事項に該当するワークロードが、エラーログに出力されるようになります。ここで出力されるワークロードが存在した場合は、アプリケーションのコードを直すなど、事前に対応しておきます。

# vim /var/log/mysqld.log
2016-06-28T09:15:55.818490Z 12 [Warning] Statement violates GTID consistency: CREATE TABLE ... SELECT.

[手順2]マスター・スレーブ共にENFORCE_GTID_CONSISTENCYONに設定

ONにすることでGTIDを使用したレプリケーションの制限事項に該当するワークロードがエラーログに出力されずにSQLエラーとして実行に失敗するようになります。

mysql> SET @@GLOBAL.ENFORCE_GTID_CONSISTENCY = ON;

mysql> create table tt2 select * from tt;
ERROR 1786 (HY000): Statement violates GTID consistency: CREATE TABLE ... SELECT.

[手順3]マスター・スレーブ共にGTID_MODEOFF_PERMISSIVEに設定

OFF_PERMISSIVEにすることで大きな変化はないですがバイナリログがローテートされます。

mysql> SET @@GLOBAL.GTID_MODE = OFF_PERMISSIVE;

[手順4]マスター・スレーブ共にGTID_MODEON_PERMISSIVEに設定

mysql> SET @@GLOBAL.GTID_MODE = ON_PERMISSIVE;

ON_PERMISSIVEにするとバイナリログがローテートされ、mysqlbinlogでバイナリログを解析すると、GTID_NEXTANONYMOUSからGTIDが設定されるようになります。

ON_PERMISSIVE
#160712  4:10:51 server id 1  end_log_pos 219 CRC32 0x78f904bb  Anonymous_GTID  last_committed=0        sequence_number=1
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
ON_PERMISSIVE
#160712  4:13:45 server id 1  end_log_pos 219 CRC32 0x41ba155b  GTID    last_committed=0        sequence_number=1
SET @@SESSION.GTID_NEXT= 'e2d0e2a6-3d09-11e6-8bd9-0242ac110004:1'/*!*/;

スレーブはSHOW SLAVE STATUSを確認すると、Retrieved_Gtid_SetExecuted_Gtid_SetにGTIDが設定されます。

Retrieved_Gtid_Set: e2d0e2a6-3d09-11e6-8bd9-0242ac110004:1
Executed_Gtid_Set: e2d0e2a6-3d09-11e6-8bd9-0242ac110004:1

[手順5]マスター・スレーブ共にステータス変数Ongoing_anonymous_transaction_count0まで待機

これは従来のレプリケーション方式で更新されるステートメントがなくなるまで待つということです。

mysql> SHOW STATUS LIKE 'ONGOING_ANONYMOUS_TRANSACTION_COUNT';
+-------------------------------------+-------+
| Variable_name                       | Value |
+-------------------------------------+-------+
| Ongoing_anonymous_transaction_count | 0     |
+-------------------------------------+-------+

[手順6]マスター・スレーブ共にFLUSH LOGSを実行する

GTIDを使用したバイナリログのみを残すためにFLUSH LOGSを実行し、それまでのバイナリログを削除します。GTIDが有効なバイナリログと、それ以外の状態のバイナリログが混ざるとPITRができないためです。よって、GTIDの有効化前にフルバックアップの取得とバイナリログのバックアップをしておくことは大切です。

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       833 |
| mysql-bin.000002 |       972 |
+------------------+-----------+

mysql> flush logs;
mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       833 |
| mysql-bin.000002 |       972 |
| mysql-bin.000003 |       194 |
+------------------+-----------+

mysql> purge binary logs to 'mysql-bin.000003';
mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000003 |       194 |
+------------------+-----------+

[手順7]マスター・スレーブ共にGTID_MODEONに設定

GTID_MODEONにします。

mysql> SET @@GLOBAL.GTID_MODE = ON;

[手順8]スレーブでレプリケーションの再接続を一度だけ実行

オンラインでGTIDへ変更と書きましたが一度だけスレーブを停止する必要があります。すでにGTIDを使用したレプリケーションとして稼動していますが、GTIDをベースにレプリケーションを再開できるようにレプリケーションを停止して、MASTER_AUTO_POSITIONを1にしてレプリケーションを開始します。

mysql> STOP SLAVE;
mysql> CHANGE MASTER TO MASTER_AUTO_POSITION = 1 ;
mysql> START SLAVE ;

最後にmy.cnfにGTID設定の記述を追加します。

以上でオンラインでのGTIDの有効化が完了となります。

まとめ

今回は、GTIDを使用したレプリケーション時の特定のトランザクションをスキップする方法と、MySQL5.7から可能となったオンラインでGTIDへ変更方法について説明しました。

MySQLのフェールオーバの自動化を提供するツールmysqlfailovermysqlfabricなどは、GTIDを使用したレプリケーションが前提となっています。今後のMySQLの高可用性を保つためにはGTIDが必須であるといえます。

おすすめ記事

記事・ニュース一覧