MySQL5.6新機能のGTID(Gloval Transaction ID)を試す

MySQL5.6(正確には5.6.5)よりGTIDという機能がつきました。 GTIDとはその名の通りトランザクションにグローバルなIDが付与されるんですが、これで何が嬉しいのかってマスターのポジションを指定せずともレプリケーションが組めてしまうんですな。

また、新機能のmysqlfailoverはGTIDを利用してフェイルオーバーを実現しているので、これは是非とも試さなければ、ってことで実際に試してみたので、メモとして残して起きます。

MySQLサーバー構成

シンプルにサーバー1(192.168.1.1)をマスターに、シンプルにサーバー2(192.168.1.2)をスレーブとして動作させます。

my.cnf設定

各サーバー以下の様にmy.cnfを設定します。

server-id=1
log-bin=mysql-bin
log-bin-index=mysql-bin
binlog_format=MIXED
binlog-do-db=test
expire-logs-days=3
log-slave-update
gtid-mode=ON
enforce-gtid-consistency
server-id=2
log-bin=mysql-bin
log-bin-index=mysql-bin
binlog_format=MIXED
binlog-do-db=test
expire-logs-days=3
log-slave-update
gtid-mode=ON
enforce-gtid-consistency

#master-host=192.168.1.1
#master-user=repl
#master-password=PASSWORD
relay-log=relay-bin
relay-log-index=relay-bin
replicate-do-db=test

gtid-mode=ONでGTIDが有効になります。GTIDはレプリケーションを構成するサーバー全てで有効にしておく必要があります。
enforce-gtid-consistencyは非トランザクションテーブル(MyISAMとか)を使う場合に設定します。

スレーブは起動時にレプリケーションが開始しないようにマスターの設定をコメントアウトしておきます。また、レプリケーション対象のDBをtestのみとしております。

あと、レプリケーション用のユーザーが存在しない場合は下記のようにマスターサーバー上で作成しておきましょう。

mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%' IDENTIFIED BY 'PASSWORD';

マスター再起動とバイナリログ確認

my.cnf編集後マスターを再起動します。

/etc/rc.d/init.d/mysql restart

SHOW MASTER STATUSでマスターの情報を確認してみます。

mysql> show master status\G;
*************************** 1. row ***************************
             File: mysql-bin.000001
         Position: 151
     Binlog_Do_DB: test
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
1 row in set (0.00 sec)

ERROR: 
No query specified

テーブルを作成し、再度確認します。

mysql> USE test;
Database changed
mysql> CREATE TABLE test (c1 int);
Query OK, 0 rows affected (0.02 sec)

mysql> SHOW MASTER STATUS\G
*************************** 1. row ***************************
             File: mysql-bin.000001
         Position: 299
     Binlog_Do_DB: test
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 8f3cb42e-af87-11e3-bb74-525405018412:1
1 row in set (0.00 sec)

Executed_Gtid_Setに値が追加されました。GTIDは問題なく機能していると思われます。
データを追加することでExecuted_Gtid_Setの値が変化することを確認して下さい。

mysql> INSERT INTO test VALUES(1),(2),(3);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SHOW MASTER STATUS\G
*************************** 1. row ***************************
             File: mysql-bin.000001
         Position: 565
     Binlog_Do_DB: test
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 8f3cb42e-af87-11e3-bb74-525405018412:1-2
1 row in set (0.00 sec)

Executed_Gtid_Setには実行したGTIDが表示されます。GTIDは「サーバーのUUID:番号」という形になっており、上記の結果では1-2までのGTIDが実行されたことがわかります。
サーバーのUUDIはデータディレクトリにあるauto.cnfで設定されています。レプリケーション内で重複しない値を設定する必要がありますが、デフォルトで自動作成される値をそのまま設定すれば問題無いでしょう。

バイナリログにもGTIDが出力されているかどうかは以下の様に確認できます。

mysql> SHOW BINLOG EVENTS IN 'mysql-bin.000001'\G
-- 中略 --
*************************** 5. row ***************************
   Log_name: mysql-bin.000001
        Pos: 299
 Event_type: Gtid
  Server_id: 1
End_log_pos: 347
       Info: SET @@SESSION.GTID_NEXT= '8f3cb42e-af87-11e3-bb74-525405018412:2'
*************************** 6. row ***************************
   Log_name: mysql-bin.000001
        Pos: 347
 Event_type: Query
  Server_id: 1
End_log_pos: 426
       Info: BEGIN
*************************** 7. row ***************************
   Log_name: mysql-bin.000001
        Pos: 426
 Event_type: Query
  Server_id: 1
End_log_pos: 534
       Info: use `test`; INSERT INTO test VALUES(1),(2),(3)
*************************** 8. row ***************************
   Log_name: mysql-bin.000001
        Pos: 534
 Event_type: Xid
  Server_id: 1
End_log_pos: 565
       Info: COMMIT /* xid=609 */
8 rows in set (0.00 sec)

スレーブ起動とリストア

スレーブサーバーを起動します。

/etc/rc.d/init.d/mysql start

もともと起動してあった場合は、一旦レプリケーションをストップしてRESET MASTER・RESET SLAVEしてください。

mysql> STOP SLAVE;
mysql> RESET MASTER;
mysql> RESET SLAVE;

次にCHANGE MASTERでマスターサーバーの設定を反映させます。

mysql> CHANGE MASTER TO
    -> master_host='192.168.1.1',
    -> master_port=3306,
    -> master_user='repl',
    -> master_password='PASSWORD',
    -> master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.20 sec)

master_auto_position=1にしておくことでGTIDによって自動的にポジションが指定されます。

バイナリログにすべての履歴が残っていればこのままSTART SLAVEしても問題無いですが、そうでない場合を想定し、ここでは一旦マスターのダンプデータから初期データをスレーブに入れて、そこからSTART SLAVEしてみます。

マスターサーバー上でダンプデータを作成します。

mysqldump test --opt -u root -p > test.sql

作成したダンプデータをFTPなりでスレーブサーバーに持ってきて、リストアします。

mysql -u root -p test < test.sql

もし以下のようなエラーが出た場合はスレーブサーバーを一度RESET MASTERしてください。

ERROR 1840 (HY000): @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_EXECUTED is empty.</em>

ここで一回test.sqlの中を覗いてみましょう。

SET @@GLOBAL.GTID_PURGED='8f3cb42e-af87-11e3-bb74-525405018412:1-2';

上記の行があると思います。GTID_PURGEDはバイナリログから削除されたGTIDが記録されるのですが、dumpしたGTID_PURGEDはdumpした時点のGTIDが保存されます。
こうすることで、dumpからリストアした時に余分なGTIDを読み込まないようになっているのです。

実際の運用上ではレプリケーションを構築しようとすると、スレーブサーバーのリストア中でもマスターサーバー上でデータの更新が発生してしまうため、差分が発生してしまいます。
そのため、GTIDを使用しないレプリケーションの構築では、マスターのログポジションの確認が必要でした。また、それに伴いポジションの確認からデータのダンプまでテーブル・ロックを行いデータの更新を止める必要がありましたが、GTIDを使用したレプリケーションではマスターポジションの確認も、テーブルロックの必要もありません。

2014年6月25日追記:mysqldumpの--master-dataオプションを付けてやればダンプファイルにマスターのファイル名とポジションが出力されるんですね。知らなかった。。。

差分を想定してマスターサーバー上でデータを更新します。

mysql> USE test;
Database changed
mysql> INSERT INTO test VALUES(4),(5),(6);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SHOW MASTER STATUS\G
*************************** 1. row ***************************
             File: mysql-bin.000001
         Position: 831
     Binlog_Do_DB: test
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 8f3cb42e-af87-11e3-bb74-525405018412:1-3
1 row in set (0.00 sec)

まだレプリケーションは開始していない状態ですが、スレーブサーバー上でSHOW SLAVE STATUSでスレーブの状態を確認します。

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 192.168.1.1
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: 
          Read_Master_Log_Pos: 4
               Relay_Log_File: relay-bin.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: 
             Slave_IO_Running: No
            Slave_SQL_Running: No
              Replicate_Do_DB: test
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 0
              Relay_Log_Space: 151
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 0
                  Master_UUID: 
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: 
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 8f3cb42e-af87-11e3-bb74-525405018412:1-2
                Auto_Position: 1
1 row in set (0.00 sec)

ダンプデータのSET @@GLOBAL.GTID_PURGEDが聞いているので、Executed_Gtid_Setには既に値が入っています。Executed_Gtid_Setは実行済みのGTIDが記録されます。
1-2は既に実行済みなので次は3から実行されるということになります。

レプリケーションを開始します。

mysql> START SLAVE;
Query OK, 0 rows affected (0.09 sec)

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.1
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 831
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 674
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: test
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 831
              Relay_Log_Space: 872
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 8f3cb42e-af87-11e3-bb74-525405018412
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 8f3cb42e-af87-11e3-bb74-525405018412:3
            Executed_Gtid_Set: 8f3cb42e-af87-11e3-bb74-525405018412:1-3
                Auto_Position: 1
1 row in set (0.00 sec)

レプリケーションが開始され、3つめのGTIDのトランザクションが実行されたので、Executed_Gtid_Setの値も変更されています。

最後に

今回はGTIDの導入をして基本的な動作を確認しました。レプリケーションの環境の構築がGTIDを導入するとかなり楽になります。

しかし、それだけでは導入理由にはならんのです。レプリケーションなんてしょっちゅう追加するもんじゃないですし。

2014年6月25日追記:mysqldumpの--master-dataオプションを付けてやれば、GTIDを使わなくても同じ手順でレプリケーションが組めます。

本当の目的はmysqlfailoverで高可用性の環境を構築することにあるのです。

ということで、今後はmysqlfailoverを試して行きたいと思います。と、言うか検証環境をどうやって用意しよう。。マスター1台、スレーブ2台(1台はマスタ昇格用)の計3台用意しないとな。検証環境の調整がつき次第試してみることにします。

コメントを残す