GTID のライフサイクルは、次のステップで構成されます:
トランザクションが実行され、ソースでコミットされます。 このクライアントトランザクションには、ソース UUID と、このサーバーでまだ使用されていないゼロ以外の最小のトランザクションシーケンス番号で構成される GTID が割り当てられます。 GTID はソースバイナリログ (ログ内のトランザクション自体の直前) に書き込まれます。 クライアントトランザクションがバイナリログに書き込まれない場合 (たとえば、トランザクションがフィルタで除外されたか、トランザクションが読み取り専用だったため)、GTID は割り当てられません。
GTID がトランザクションに割り当てられている場合、GTID はトランザクションの開始時にバイナリログに (
Gtid_log_event
として) 書き込むことによって、コミット時に原子的に永続化されます。 バイナリログがローテーションされるか、サーバーがシャットダウンされるたびに、サーバーは以前のバイナリログファイルに書き込まれたすべてのトランザクションの GTID をmysql.gtid_executed
テーブルに書き込みます。GTID がトランザクションに割り当てられている場合、GTID は
gtid_executed
システム変数 (@@GLOBAL.gtid_executed
) の GTID のセットに追加することで、非原子的に (トランザクションのコミット直後に) 外部化されます。 この GTID セットには、コミットされたすべての GTID トランザクションのセットの表現が含まれ、サーバーの状態を表すトークンとしてレプリケーションで使用されます。 バイナリロギングが有効になっている (ソースに必要な) 場合、gtid_executed
システム変数内の GTID のセットは適用されるトランザクションの完全なレコードですが、最新の履歴がまだ現在のバイナリログファイル内にあるため、mysql.gtid_executed
テーブルは適用されません。バイナリログデータがレプリカに転送され、レプリカリレーログに格納されたあと (このプロセスで確立されたメカニズムを使用して、セクション17.2「レプリケーションの実装」 を参照)、レプリカは GTID を読み取り、その
gtid_next
システム変数の値を GTID として設定します。 これは、この GTID を使用して次のトランザクションをログに記録する必要があることをレプリカに通知します。 レプリカはセッションコンテキストでgtid_next
を設定することに注意してください。レプリカは、トランザクションを処理するために、
gtid_next
で GTID の所有権を取得しているスレッドがないことを検証します。 レプリケートされたトランザクション GTID を最初に読み取ってチェックすることで、トランザクション自体を処理する前に、レプリカは、この GTID を持つ以前のトランザクションがレプリカに適用されていないことだけでなく、この GTID をまだ読み取っていないが、関連付けられたトランザクションをまだコミットしていないことも保証します。 そのため、複数のクライアントが同時に同じトランザクションを適用しようとすると、サーバーはいずれか一方のクライアントのみを実行できるようにしてこれを解決します。 レプリカのgtid_owned
システム変数 (@@GLOBAL.gtid_owned
) には、現在使用中の各 GTID とそれを所有するスレッドの ID が表示されます。 GTID がすでに使用されている場合、エラーは発生せず、自動スキップ機能を使用してトランザクションが無視されます。GTID が使用されていない場合、レプリカはレプリケートされたトランザクションを適用します。
gtid_next
はソースによってすでに割り当てられている GTID に設定されているため、レプリカはこのトランザクションに対して新しい GTID を生成しようとせず、かわりにgtid_next
に格納されている GTID を使用します。バイナリロギングがレプリカで有効になっている場合、GTID はトランザクションの開始時にバイナリログに (
Gtid_log_event
として) 書き込むことによって、コミット時に原子的に永続化されます。 バイナリログがローテーションされるか、サーバーがシャットダウンされるたびに、サーバーは以前のバイナリログファイルに書き込まれたすべてのトランザクションの GTID をmysql.gtid_executed
テーブルに書き込みます。バイナリロギングがレプリカで無効になっている場合、GTID は
mysql.gtid_executed
テーブルに直接書き込むことによって原子的に永続化されます。 MySQL は、GTID をテーブルに挿入するステートメントをトランザクションに追加します。 MySQL 8.0 からは、この操作は DDL ステートメントおよび DML ステートメントに対してアトミックです。 この状況では、mysql.gtid_executed
テーブルはレプリカに適用されるトランザクションの完全なレコードです。レプリケートされたトランザクションがレプリカでコミットされるとすぐに、GTID はレプリカの
gtid_executed
システム変数 (@@GLOBAL.gtid_executed
) 内の GTID のセットに追加され、非原子的に外部化されます。 ソースに関して、この GTID セットには、コミットされた GTID トランザクションのセットの表現が含まれます。 レプリカでバイナリロギングが無効になっている場合、mysql.gtid_executed
テーブルはレプリカに適用されたトランザクションの完全なレコードでもあります。 バイナリロギングがレプリカで有効になっている場合、つまり一部の GTID がバイナリログにのみ記録される場合、gtid_executed
システム変数内の GTID のセットのみが完全なレコードになります。
ソースで完全にフィルタで除外されたクライアントトランザクションに GTID が割り当てられていないため、gtid_executed
システム変数のトランザクションセットに追加されたり、mysql.gtid_executed
テーブルに追加されることはありません。 ただし、レプリカで完全にフィルタで除外されたレプリケートされたトランザクションの GTID は永続化されます。 バイナリロギングがレプリカで有効になっている場合、フィルタリングされたトランザクションは Gtid_log_event
としてバイナリログに書き込まれ、その後に BEGIN
および COMMIT
ステートメントのみを含む空のトランザクションが続きます。 バイナリロギングが無効になっている場合は、フィルタ処理されたトランザクションの GTID が mysql.gtid_executed
テーブルに書き込まれます。 フィルタ処理されたトランザクションの GTID を保持することで、mysql.gtid_executed
テーブルおよび GTID のセットを gtid_executed
システム変数に確実に圧縮できます。 また、セクション17.1.3.3「GTID 自動配置」 で説明されているように、レプリカがソースに再接続した場合、フィルタで除外されたトランザクションが再度取得されないようにします。
マルチスレッドレプリカ (slave_parallel_workers > 0
を使用) では、トランザクションをパラレルに適用できるため、レプリケートされたトランザクションは順序どおりにコミットできません (slave_preserve_commit_order=1
が設定されていない場合)。 その場合、gtid_executed
システム変数内の GTID のセットには、GTID 間にギャップがある複数の GTID 範囲が含まれます。 (ソースまたはシングルスレッドレプリカでは、数値間のギャップなしで GTID が単調に増加します。) マルチスレッドのレプリカのギャップは、最後に適用されたトランザクション間でのみ発生し、レプリケーションの進行に応じて埋められます。 STOP REPLICA | SLAVE
ステートメントを使用してレプリケーションスレッドが正常に停止されると、ギャップが埋められるように進行中のトランザクションが適用されます。 サーバー障害や KILL
ステートメントを使用してレプリケーションスレッドを停止した場合、ギャップが残ることがあります。
一般的なシナリオは、サーバーがコミットされたトランザクションに対して新しい GTID を生成することです。 ただし、GTID はトランザクション以外の他の変更にも割り当てることができ、場合によっては単一のトランザクションに複数の GTID を割り当てることができます。
バイナリログに書き込まれるすべてのデータベース変更 (DDL または DML) に GTID が割り当てられます。 これには、自動コミットされる変更と、BEGIN
および COMMIT
または START TRANSACTION
ステートメントを使用してコミットされる変更が含まれます。 GTID は、データベースの作成、変更または削除、およびプロシージャ、ファンクション、トリガー、イベント、ビュー、ユーザー、ロールまたは付与などのテーブル以外のデータベースオブジェクトにも割り当てられます。
非トランザクション更新およびトランザクション更新に GTID が割り当てられます。 また、非トランザクション更新では、バイナリログキャッシュへの書き込み中にディスク書き込み障害が発生し、そのためバイナリログにギャップが作成された場合、生成されるインシデントログイベントに GTID が割り当てられます。
バイナリログ内の生成されたステートメントによってテーブルが自動的に削除されると、GTID がステートメントに割り当てられます。 レプリカが開始したばかりのソースからイベントの適用を開始し、ステートメントベースレプリケーションが使用中 (binlog_format=STATEMENT
) で、開いている一時テーブルを持つユーザーセッションが切断されると、一時テーブルは自動的に削除されます。 MEMORY
ストレージエンジンを使用するテーブルは、サーバーの起動後にはじめてアクセスされたときに自動的に削除されます。これは、シャットダウン中に行が失われた可能性があるためです。
トランザクションが起点のサーバー上のバイナリログに書き込まれない場合、サーバーは GTID を割り当てません。 これには、ロールバックされたトランザクションと、バイナリロギング中に実行されたトランザクションがオリジンのサーバーでグローバルに (サーバー構成で --skip-log-bin
が指定された状態で) またはセッションに対して (SET @@SESSION.sql_log_bin = 0
) 無効化された状態で含まれます。 これには、行ベースレプリケーションが使用されている場合の no-op トランザクションも含まれます (binlog_format=ROW
)。
XA トランザクションには、トランザクションの XA PREPARE
フェーズおよびトランザクションの XA COMMIT
または XA ROLLBACK
フェーズ用に個別の GTID が割り当てられます。 XA トランザクションは、障害発生時にユーザーがコミットまたはロールバックできるように永続的に準備されます (レプリケーショントポロジでは、別のサーバーへのフェイルオーバーが含まれる場合があります)。 したがって、トランザクションの 2 つの部分は個別にレプリケートされるため、ロールバックされる非 XA トランザクションに GTID がなくても、独自の GTID が必要です。
次の特殊なケースでは、単一のステートメントで複数のトランザクションを生成できるため、複数の GTID を割り当てることができます:
複数のトランザクションをコミットするストアドプロシージャが起動されます。 プロシージャがコミットするトランザクションごとに GTID が 1 つ生成されます。
複数テーブルの
DROP TABLE
ステートメントは、異なるタイプのテーブルを削除します。 いずれかのテーブルがアトミック DDL をサポートしていないストレージエンジンを使用している場合、またはいずれかのテーブルが一時テーブルである場合は、複数の GTID を生成できます。CREATE TABLE ... SELECT
ステートメントは、行ベースのレプリケーションが使用中 (binlog_format=ROW
) の場合に発行されます。CREATE TABLE
処理に対して GTID が生成され、行挿入処理に対して GTID が生成されます。
デフォルトでは、ユーザーセッションでコミットされた新しいトランザクションの場合、サーバーは自動的に新しい GTID を生成して割り当てます。 トランザクションがレプリカに適用されると、オリジンのサーバーからの GTID が保持されます。 この動作は、gtid_next
システム変数のセッション値を設定することで変更できます:
gtid_next
がAUTOMATIC
(デフォルト) に設定され、トランザクションがコミットされてバイナリログに書き込まれると、サーバーは自動的に新しい GTID を生成して割り当てます。 トランザクションが別の理由でロールバックされるか、バイナリログに書き込まれない場合、サーバーは GTID を生成して割り当てません。gtid_next
を有効な GTID (コロンで区切られた UUID とトランザクション順序番号で構成) に設定すると、サーバーはその GTID をトランザクションに割り当てます。 この GTID は、トランザクションがバイナリログに書き込まれない場合や、トランザクションが空の場合でも、gtid_executed
に割り当てられて追加されます。
gtid_next
を特定の GTID に設定し、トランザクションがコミットまたはロールバックされた後、明示的な SET @@SESSION.gtid_next
ステートメントを他のステートメントの前に発行する必要があります。 GTID を明示的に割り当てない場合は、GTID 値を AUTOMATIC
に戻すためにこれを使用できます。
レプリケーションアプライヤスレッドがレプリケートされたトランザクションを適用する場合、この手法を使用して、@@SESSION.gtid_next
をオリジンサーバーに割り当てられているレプリケートされたトランザクションの GTID に明示的に設定します。 これは、レプリカによって生成および割り当てられる新しい GTID ではなく、起点のサーバーからの GTID が保持されることを意味します。 また、バイナリロギングまたはレプリカ更新ロギングがレプリカで無効になっている場合、またはトランザクションが no-op であるかレプリカでフィルタで除外されている場合でも、GTID がレプリカ上の gtid_executed
に追加されることを意味します。
クライアントは、トランザクションを実行する前に@@SESSION.gtid_next
を特定の GTID に設定することで、レプリケートされたトランザクションをシミュレートできます。 この手法は、GTID を保持するためにクライアントがリプレイできるバイナリログのダンプを生成するために、mysqlbinlog によって使用されます。 クライアントを介してコミットされたシミュレートされたレプリケートされたトランザクションは、レプリケーションアプライヤスレッドを介してコミットされたレプリケートされたトランザクションと完全に同等であり、実際には区別できません。
gtid_purged
システム変数 (@@GLOBAL.gtid_purged
) 内の GTID のセットには、サーバー上でコミットされたが、サーバー上のバイナリログファイルには存在しないすべてのトランザクションの GTID が含まれています。gtid_purged
は、gtid_executed
のサブセットです。 GTID の次のカテゴリが gtid_purged
にあります:
レプリカでバイナリロギングを無効にしてコミットされたレプリケートされたトランザクションの GTID。
現在パージされているバイナリログファイルに書き込まれたトランザクションの GTID。
ステートメント
SET @@GLOBAL.gtid_purged
によってセットに明示的に追加された GTID。
特定の GTID セット内のトランザクションが適用されたことをサーバーに記録するために、gtid_purged
の値を変更できますが、それらはサーバー上のバイナリログには存在しません。 GTID を gtid_purged
に追加すると、gtid_executed
にも追加されます。 このアクションのユースケースの例は、サーバー上の 1 つ以上のデータベースのバックアップをリストアするが、サーバー上のトランザクションを含む関連するバイナリログがない場合です。 MySQL 8.0 より前は、gtid_executed
(および gtid_purged
) が空の場合にのみ、gtid_purged
の値を変更できました。 MySQL 8.0 からは、この制限は適用されず、gtid_purged
内の GTID セット全体を指定された GTID セットに置き換えるか、指定された GTID セットを gtid_purged
内の GTID に追加するかを選択することもできます。 これを行う方法の詳細は、gtid_purged
の説明を参照してください。
gtid_executed
および gtid_purged
システム変数内の GTID のセットは、サーバーの起動時に初期化されます。 すべてのバイナリログファイルは、以前のすべてのバイナリログファイル (前のファイル Previous_gtids_log_event
の GTID および前のファイル自体のすべての Gtid_log_event
の GTID から構成される) 内の GTID のセットを含むイベント Previous_gtids_log_event
から始まります。 もっとも古いバイナリログファイルと最新のバイナリログファイル内の Previous_gtids_log_event
の内容は、サーバーの起動時に gtid_executed
および gtid_purged
セットを計算するために使用されます:
gtid_executed
は、最新のバイナリログファイル内のPrevious_gtids_log_event
内の GTID、そのバイナリログファイル内のトランザクションの GTID、およびmysql.gtid_executed
テーブルに格納されている GTID の結合として計算されます。 この GTID セットには、現在サーバー上のバイナリログファイル内にあるかどうかに関係なく、サーバー上で使用された (またはgtid_purged
に明示的に追加された) GTID がすべて含まれます。 サーバー (@@GLOBAL.gtid_owned
) で現在処理されているトランザクションの GTID は含まれません。gtid_purged
は、まず最新のバイナリログファイルにPrevious_gtids_log_event
の GTID を追加し、そのバイナリログファイルにトランザクションの GTID を追加することによって計算されます。 この手順では、サーバー (gtids_in_binlog
) のバイナリログに現在記録されている GTID、または一度も記録されていた GTID のセットを提供します。 次に、もっとも古いバイナリログファイル内のPrevious_gtids_log_event
内の GTID がgtids_in_binlog
から差し引かれます。 この手順では、サーバー (gtids_in_binlog_not_purged
) のバイナリログに現在記録されている GTID のセットを提供します。 最後に、gtids_in_binlog_not_purged
がgtid_executed
から減算されます。 結果は、サーバー上で使用されているが、現在サーバー上のバイナリログファイルに記録されていない GTID のセットであり、この結果はgtid_purged
の初期化に使用されます。
これらの計算に MySQL 5.7.7 以前のバイナリログが含まれている場合は、gtid_executed
および gtid_purged
に対して不正な GTID セットを計算でき、サーバーがあとで再起動されても正しくないままになります。 詳細は、GTID セットを計算するためにバイナリログを繰り返す方法を制御する binlog_gtid_simple_recovery
システム変数の説明を参照してください。 説明されているいずれかの状況がサーバーに当てはまる場合は、サーバー構成ファイルで binlog_gtid_simple_recovery=FALSE
を設定してから起動します。 この設定により、サーバーは (もっとも新しいものともっとも古いものだけでなく) すべてのバイナリログファイルを反復して GTID イベントが表示される場所を見つけます。 GTID イベントのないバイナリログファイルがサーバーに多数ある場合、このプロセスには時間がかかることがあります。
サーバーで GTID 実行履歴をリセットする必要がある場合は、RESET MASTER
ステートメントを使用します。 たとえば、テストクエリーを実行して新しい GTID 対応サーバーでレプリケーション設定を検証した後、または新しいサーバーをレプリケーショングループに結合するが、グループレプリケーションで受け入れられない不要なローカルトランザクションが含まれている場合に、これを行う必要があります。
必要な GTID 実行履歴およびバイナリログファイルが失われないように、RESET MASTER
を慎重に使用してください。
RESET MASTER
を発行する前に、サーバーのバイナリログファイルとバイナリログインデックスファイル (ある場合) のバックアップがあることを確認し、gtid_executed
システム変数のグローバル値に保持されている GTID セットを取得して保存します (たとえば、SELECT @@GLOBAL.gtid_executed
ステートメントを発行して結果を保存します)。 その GTID セットから不要なトランザクションを削除する場合は、mysqlbinlog を使用してトランザクションの内容を調べ、値がなく、保存またはレプリケートが必要なデータがなく、サーバーでデータが変更されなかったことを確認します。
RESET MASTER
を発行すると、次のリセット操作が実行されます:
gtid_purged
システム変数の値は空の文字列 (''
) に設定されます。gtid_executed
システム変数のグローバル値 (セッション値ではない) が空の文字列に設定されています。mysql.gtid_executed
テーブルがクリアされます (mysql.gtid_executed テーブル を参照)。サーバーでバイナリロギングが有効になっている場合、既存のバイナリログファイルは削除され、バイナリログインデックスファイルはクリアされます。
サーバーがバイナリロギングが無効になっているレプリカであっても、RESET MASTER
は GTID 実行履歴をリセットする方法であることに注意してください。 RESET REPLICA | SLAVE
は GTID 実行履歴には影響しません。