Documentation Home
MySQL 8.0 リファレンスマニュアル
Download this Manual
PDF (US Ltr) - 36.1Mb
PDF (A4) - 36.2Mb


このページは機械翻訳したものです。

17.1.3.2 GTID ライフサイクル

GTID のライフサイクルは、次のステップで構成されます:

  1. トランザクションが実行され、ソースでコミットされます。 このクライアントトランザクションには、ソース UUID と、このサーバーでまだ使用されていないゼロ以外の最小のトランザクションシーケンス番号で構成される GTID が割り当てられます。 GTID はソースバイナリログ (ログ内のトランザクション自体の直前) に書き込まれます。 クライアントトランザクションがバイナリログに書き込まれない場合 (たとえば、トランザクションがフィルタで除外されたか、トランザクションが読み取り専用だったため)、GTID は割り当てられません。

  2. GTID がトランザクションに割り当てられている場合、GTID はトランザクションの開始時にバイナリログに (Gtid_log_event として) 書き込むことによって、コミット時に原子的に永続化されます。 バイナリログがローテーションされるか、サーバーがシャットダウンされるたびに、サーバーは以前のバイナリログファイルに書き込まれたすべてのトランザクションの GTID を mysql.gtid_executed テーブルに書き込みます。

  3. GTID がトランザクションに割り当てられている場合、GTID は gtid_executed システム変数 (@@GLOBAL.gtid_executed) の GTID のセットに追加することで、非原子的に (トランザクションのコミット直後に) 外部化されます。 この GTID セットには、コミットされたすべての GTID トランザクションのセットの表現が含まれ、サーバーの状態を表すトークンとしてレプリケーションで使用されます。 バイナリロギングが有効になっている (ソースに必要な) 場合、gtid_executed システム変数内の GTID のセットは適用されるトランザクションの完全なレコードですが、最新の履歴がまだ現在のバイナリログファイル内にあるため、mysql.gtid_executed テーブルは適用されません。

  4. バイナリログデータがレプリカに転送され、レプリカリレーログに格納されたあと (このプロセスで確立されたメカニズムを使用して、セクション17.2「レプリケーションの実装」 を参照)、レプリカは GTID を読み取り、その gtid_next システム変数の値を GTID として設定します。 これは、この GTID を使用して次のトランザクションをログに記録する必要があることをレプリカに通知します。 レプリカはセッションコンテキストで gtid_next を設定することに注意してください。

  5. レプリカは、トランザクションを処理するために、gtid_next で GTID の所有権を取得しているスレッドがないことを検証します。 レプリケートされたトランザクション GTID を最初に読み取ってチェックすることで、トランザクション自体を処理する前に、レプリカは、この GTID を持つ以前のトランザクションがレプリカに適用されていないことだけでなく、この GTID をまだ読み取っていないが、関連付けられたトランザクションをまだコミットしていないことも保証します。 そのため、複数のクライアントが同時に同じトランザクションを適用しようとすると、サーバーはいずれか一方のクライアントのみを実行できるようにしてこれを解決します。 レプリカの gtid_owned システム変数 (@@GLOBAL.gtid_owned) には、現在使用中の各 GTID とそれを所有するスレッドの ID が表示されます。 GTID がすでに使用されている場合、エラーは発生せず、自動スキップ機能を使用してトランザクションが無視されます。

  6. GTID が使用されていない場合、レプリカはレプリケートされたトランザクションを適用します。 gtid_next はソースによってすでに割り当てられている GTID に設定されているため、レプリカはこのトランザクションに対して新しい GTID を生成しようとせず、かわりに gtid_next に格納されている GTID を使用します。

  7. バイナリロギングがレプリカで有効になっている場合、GTID はトランザクションの開始時にバイナリログに (Gtid_log_event として) 書き込むことによって、コミット時に原子的に永続化されます。 バイナリログがローテーションされるか、サーバーがシャットダウンされるたびに、サーバーは以前のバイナリログファイルに書き込まれたすべてのトランザクションの GTID を mysql.gtid_executed テーブルに書き込みます。

  8. バイナリロギングがレプリカで無効になっている場合、GTID は mysql.gtid_executed テーブルに直接書き込むことによって原子的に永続化されます。 MySQL は、GTID をテーブルに挿入するステートメントをトランザクションに追加します。 MySQL 8.0 からは、この操作は DDL ステートメントおよび DML ステートメントに対してアトミックです。 この状況では、mysql.gtid_executed テーブルはレプリカに適用されるトランザクションの完全なレコードです。

  9. レプリケートされたトランザクションがレプリカでコミットされるとすぐに、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 はトランザクション以外の他の変更にも割り当てることができ、場合によっては単一のトランザクションに複数の 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_next システム変数

デフォルトでは、ユーザーセッションでコミットされた新しいトランザクションの場合、サーバーは自動的に新しい GTID を生成して割り当てます。 トランザクションがレプリカに適用されると、オリジンのサーバーからの GTID が保持されます。 この動作は、gtid_next システム変数のセッション値を設定することで変更できます:

  • gtid_nextAUTOMATIC(デフォルト) に設定され、トランザクションがコミットされてバイナリログに書き込まれると、サーバーは自動的に新しい 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 システム変数

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_purgedgtid_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 実行履歴のリセット

サーバーで 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 実行履歴には影響しません。