MySQLのレプリケーション機能は非常に便利で、冗長構成としてレプリケーションを構築しているサービスは多くあるかと思います。レプリケーションを運用する上で悩ましい点としては、ソースとレプリカにおいて、データの差分が発生してしまう恐れがあるということです。これを防ぐためにread_onlyオプションをレプリカ側で設定したり、運用面でデータの差分チェックの工夫を入れたりしているかもしれません。enforce_gtid_consistencyというオプションを設定することで一部の発生しうるデータ不整合を防ぐことが可能です。今回はenforce_gtid_consistencyの説明をしていきたいと思います。
なお、利用しているMySQLについてはバージョン8.0.28となります。
enforce_gtid_consistency
こちらのオプションはMySQL5.6で追加されたオプションでスコープはグローバルとなり、特定の条件で設定変更が可能です(後述します) 。設定できる値としてはON,OFF,WARN(WARNは5.7.6で追加)の3つがあり、それぞれ以下のようになります。
OFF
すべてのトランザクションにおいて、GTID整合性に違反してもよい
ON
GTID整合性に違反するトランザクションを禁止する
WARN
すべてのトランザクションはGTID整合性に違反してもよいが警告(WARN)が発生する
WARNを設定することでGTID整合性に違反するようなトランザクションを許可しつつ、警告を出すことができます。出力された警告はerror.logにも書き込まれます。
mysql> CREATE TEMPORARY TABLE tmp_table1(id int);
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show warnings\G
*************************** 1. row ***************************
Level: Warning
Code: 3748
Message: Statement violates GTID consistency: CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE are not allowed inside a transaction or inside a procedure in a transactional context when @@session.binlog_format=STATEMENT.
1 row in set (0.00 sec)
enforce_gtid_consistencyはGTID_MODEをONにするためには必要な設定であるため、enforce_gtid_consistencyを変更するにはGTID_MODEの現在の値によって設定できる値が異なります。
GTID_MODEがOFF、OFF_PERMISSIVE、ON_PERMISSIVEの場合には、enforce_gtid_consistencyはON、OFF、WARNいずれも設定が可能です。GTID_MODEがONの場合はenforce_gtid_consistencyはONしか設定できず、他の値に変更しようとすると、以下のエラーが発生します。
mysql> SET GLOBAL enforce_gtid_consistency = WARN;
ERROR 1779 (HY000): GTID_MODE = ON requires ENFORCE_GTID_CONSISTENCY = ON.
また、GTID_MODEがON_PERMISSIVEの状態で、enforce_gtid_consistencyがON以外の値の場合だと、GTID_MODEをONにすることができません。このあたりのオンラインでのGTID_MODEの設定については第25回GTIDを使用したレプリケーション構成を作成する にて説明がありますので、こちらをご覧ください。
mysql> SET GLOBAL gtid_mode = 'ON';
ERROR 3111 (HY000): SET @@GLOBAL.GTID_MODE = ON is not allowed because ENFORCE_GTID_CONSISTENCY is not ON.
GTID整合性に違反するトランザクション
enforce_gtid_consistencyがONのときに利用できないもの(GTID整合性に違反するトランザクション)は、以下のようなものになります。
MySQLのバージョンが8.0.21未満の場合でbinlog_formatがROWベースのレプリケーションを利用している場合は、CREATE TABLE as … SELECT構文は利用できません(8.0.21以降のバージョンではアトミックDDLをサポートするストレージエンジンで利用可能になります) 。
CREATE/DROP TEMPORARY TABLEにおいて、binlog_format がstatementベースの場合、トランザクション、プロシージャ、関数、トリガー内では利用できません(GTID_MODEがONでautocommit=1である場合はトランザクション、プロシージャ、関数、トリガーの外である場合は利用できます) 。binlog_formatがrow, mixedの場合、バージョンが8.0.13以降であれば、トランザクション、プロシージャ、関数、トリガー内でもあってもCREATE/DROP TEMPORARY TABLEが利用できます。
このあたりの挙動については公式ドキュメントのGTID ベースレプリケーションの制約 にも記述があるので、詳しくはこちらをご覧ください。
statementベースでtransaction内でCREATE TEMPORARY TABLEを利用した場合のエラー
mysql> begin;
mysql> CREATE TEMPORARY TABLE tmp_table1(id int);
ERROR 3748 (HY000): Statement violates GTID consistency: CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE are not allowed inside a transaction or inside a procedure in a transactional context when @@session.binlog_format=STATEMENT.
その他
enforce-gtid-consistency は、log_bin=1の場合にのみ有効です。 バイナリログがサーバーで無効になっている場合、またはステートメントがレプリケーションフィルタによってバイナリログに書き込まれない場合はチェックの対象となりません。
まとめ
今回は、enforce_gtid_consistencyについて説明しました。一部の例においては、enforce_gtid_consistencyを利用することで特定のクエリをエラーとすることが可能であり、設定自体はGTIDを自体を利用していなくても利用可能です。このため、現状でenforce_gtid_consistencyに違反するようなことがなければ―つまりWARNを設定して警告が出ないことが確認できれば、enforce_gtid_consistencyはONに設定することをおすすめします。