Global Transaction IDを使ってレプリケーション構成とした際の制限

2012/11/08に一部追記しました。

Global Transaction IDを有効にしてレプリケーション構成とした際の制限について簡単にまとめてみる。微妙な訳になっている部分もあるだろうし、勘違いしてる箇所もあるかもしれないのでご注意下さい。

よって、アレ?、というのがありましたら基本的には公式ドキュメントを参照して下さい。
むしろ誤りあったら突っ込んでもらえると助かります。

前提
MySQL5.6 RC版(5.6.7-rc)でgtidを使ったレプリケーション環境で確認

トランザクションが使えないストレージエンジンは使用出来ない(MyISAM等)

前の日記でも書いていますが、以下のようにエラーとなります。

ERROR 1785 (HY000): Updates to non-transactional tables are forbidden when DISABLE_GTID_UNSAFE_STATEMENTS = 1.

MasterとSlaveで同一テーブルで異なるストレージエンジンは使用してはいけない

MasterとSlaveで異なるbinlog_formatは使用してはいけない

ちょっとこの部分は実際に上手く試せなかったのでどうなるかはっきりとしていません。MasterでInnoDB、SlaveでMyISAMの組み合わせだと当然以下のようにSlave側でエラーが起きます。

Last_Errno: 1785
Last_Error: Error 'Updates to non-transactional tables are forbidden when DISABLE_GTID_UNSAFE_STATEMENTS = 1.' on query. Default database: 'test'. Query: 'insert into test values ()'

InnoDB以外のトランザクションが使用可能なストレージエンジンの場合はエラーにならないけどgtidがおかしくなるのかもしれません。

異なるbinlog_formatですがドキュメント通りにMasterでROW、SlaveでSTATEMENTにしたけどエラーは発生せず、ぱっとみ普通に動いているように見えました。クエリの種類にもよるのかな… Slaveではlog_slave_updatesを有効にしているのでshow binlog events in 'mysql-bin.000002'で見た感じではSET @@SESSION.GTID_NEXT= の右辺は同じでした。

上手く行かない状況がよく分からなかったので 使用してはいけない という記述にしました。とはいえ、ドキュメントにあるのだから同じにしておく方が良いでしょう。

CREATE TABLE ... SELECT はサポートされない(使用出来ない)

以下のようにエラーになります。

mysql> create table test_copy ( id int not null auto_increment, primary key(id)) select * from test;
ERROR 1786 (HY000): CREATE TABLE ... SELECT is forbidden when DISABLE_GTID_UNSAFE_STATEMENTS = 1.

以下だいぶ適当な訳。
CREATE TABLE ... SELECTはSTATEMENTベースのレプリケーションだと安全では無い、んじゃROWベースならOKかというとバイナリログのイベントとしては以下の2つに分割されるためそうでもない。

  • 1つはCREATE TABLE
  • もう1つはINSERT

またトランザクション内でCREATE TABLE ... SELECTを実行した場合、上記の2つのイベントが場合によっては同じトランザクションIDとしてSlaveに送られる事があり、その場合、SlaveではINSERTはスキップされることになる。よってCREATE TABLE ... SELECTはサポートされない。

CREATE TEMPORARY TABLE と DROP TEMPORARY TABLEはサポートされない

2012/11/08追記
勘違いしてたようでトランザクション内だとエラーになるようです。

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> create temporary table test (id int not null, primary key(id) ) ENGINE=InnoDB;
ERROR 1787 (HY000): When DISABLE_GTID_UNSAFE_STATEMENTS = 1, the statements CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE can be executed in a non-transactional context only, and require that AUTOCOMMIT = 1.
mysql> 

まぁ、なんにしろオプション名とか変わるみたいなので、正式版リリースされたら再度確認かな…
追記ここまで

5.6.7-rcだと動いちゃうようですが、バグのようなので新しいバージョンが出たら再度試したいと思います(参考リンク)
以下リンク先の記載抜粋。

Prior to MySQL 5.6.9, this option was named --disable-gtid-unsafe-statements. (Bug #14775984)

Prior to MySQL 5.6.7, using this option caused nontransactional DML on temporary tables to fail, although 
changes to temporary tables are not logged when using row-based binary logging. In MySQL 5.6.7 and later, 
nontransactional DML statements are allowed on temporary tables with --disable-gtid-unsafe-statements 
(--enforce-gtid-consistency beginning with MySQL 5.6.9) as long as all affected tables are temporary tables (Bug #14272672).

gtidが有効な場合のmysqldump

5.6.10からmysqldumpからスレーブを作成可能だったので訂正しています。gtidを使用した環境でのmysqldump
ダンプの取得は可能です。ただ、--all-databasesのように全てのデータベースを対象とした場合ダンプファイルにはmysql.userのようなトランザクションをサポートしないテーブルのデータも含まれるためgtid-mode=ONな場合はリストア時にエラーになります。もちろん、対象としてInnoDBしか存在しないデータベースを指定してダンプした場合はリストアでもエラーになりません。

ただ、mysqldumpを使ったダンプファイルを使用して新規にgtidを使用したSlaveを追加出来るかというと出来ません。mysqldumpではgtidを記録してくれないためです。
gtid-mode=ONなサーバにリストアを行うと新規にgtidを割り当ててしまい、CHANGE MASTER TOでMASTER_AUTO_POSITION=1としてもエラーが発生します。
よってgtidも含めてリストアをしたいのであればバイナリログとmysqlbinlogコマンドを使用する必要があります。

とまぁ、こんな感じだと思うんだけど非常に微妙。mysqldumpでリストアした後、後続のイベントを2、3個、mysqlbinlog使って読み込ませた上でstart slaveしたけどエラーになりました。なんか上手いやり方ないのかと模索中です。正直バイナリログを全部取っておくのはしんどい。
お金あるところであれば遅延レプリケーション使ってバックアップ用のサーバ用意しておくとかでMySQL停止、datadirをまるっとコピー、とかで直せそうだけど、そんなところ多くないし。gtid使わなければ良いと言われればその通り。今の所mysqlfailoverを使う場合やレプリケーション設定時にMASTER_LOG_FILE, MASTER_LOG_POSを指定しなくて良いという以外の使いどころが分かってないので使いどころ見極めないと面倒くさい事になりそう。

gtidが有効な場合のmysql_upgradeコマンド

5.6.7以降は--write-binlog=OFFがデフォルトなので特別意識しなくて大丈夫ですが、レプリケーション構成の場合はMaster, Slaveそれぞれで実行する必要があります。
5.6.7より前は--write-binlog=ONのため、MyISAM型テーブルへの更新が入るためエラーとなっていたようです。