グローバルトランザクション識別子 (GTID) は、発生元のサーバー (ソース) でコミットされた各トランザクションに作成および関連付けられる一意の識別子です。 この識別子は、それが発生したサーバーに対して一意であるだけでなく、特定のレプリケーショントポロジ内のすべてのサーバーで一意です。
GTID 割当では、ソースでコミットされるクライアントトランザクションと、レプリカで再現されるレプリケートトランザクションが区別されます。 クライアントトランザクションがソースでコミットされると、そのトランザクションがバイナリログに書き込まれた場合、新しい GTID が割り当てられます。 クライアントトランザクションでは、生成された番号間のギャップなしで GTID が単調に増加することが保証されます。 クライアントトランザクションがバイナリログに書き込まれない場合 (たとえば、トランザクションがフィルタで除外されたか、またはトランザクションが読み取り専用だったため)、そのトランザクションには起点のサーバー上の GTID は割り当てられません。
レプリケートされたトランザクションは、オリジンのサーバー上のトランザクションに割り当てられた GTID と同じ GTID を保持します。 GTID は、レプリケートされたトランザクションの実行が開始される前に存在し、レプリケートされたトランザクションがレプリカのバイナリログに書き込まれていない場合や、レプリカでフィルタで除外されている場合でも保持されます。 MySQL システムテーブル mysql.gtid_executed
は、現在アクティブなバイナリログファイルに格納されているトランザクションを除き、MySQL サーバーに適用されたすべてのトランザクションの割り当てられた GTID を保持するために使用されます。
GTID の自動スキップ機能は、ソースでコミットされたトランザクションをレプリカに複数回適用でき、一貫性の保証に役立ちます。 指定された GTID を持つトランザクションが指定されたサーバーでコミットされると、同じ GTID を持つ後続のトランザクションを実行しようとする試みはそのサーバーによって無視されます。 エラーは発生せず、トランザクション内のステートメントは実行されません。
指定された GTID を持つトランザクションがサーバー上で実行を開始したが、まだコミットまたはロールバックされていない場合、同じ GTID ブロックを持つサーバー上で同時トランザクションを開始しようとする試みはすべて行われます。 サーバーは、同時トランザクションの実行を開始せず、クライアントに制御を返しません。 トランザクションでの最初の試行がコミットまたはロールバックされると、同じ GTID でブロックしていた同時セッションが続行される可能性があります。 最初の試行がロールバックされた場合、1 つのコンカレントセッションがトランザクションの試行を続行し、同じ GTID でブロックしていた他のコンカレントセッションはブロックされたままになります。 最初の試行がコミットされると、すべての同時セッションがブロックされなくなり、トランザクションのすべてのステートメントが自動スキップされます。
GTID は座標のペアとして表現され、次に示すように、コロン文字 (:
) で区切られます。
GTID = source_id:transaction_id
source_id
は発生元サーバーを識別します。 通常、この目的にはソース server_uuid
が使用されます。 transaction_id
は、ソースでトランザクションがコミットされた順序によって決定される順序番号です。 たとえば、コミットされる最初のトランザクションには transaction_id
として 1
があり、同じオリジンサーバーでコミットされる 10 番目のトランザクションには 10
の transaction_id
が割り当てられます。 トランザクションに、GTID のシーケンス番号として 0
を割り当てることはできません。 たとえば、UUID が 3E11FA47-71CA-11E1-9E33-C80AA9429562
の発生元サーバーでコミットされた 23 番目のトランザクションの GTID は次のとおりです。
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
サーバーインスタンス上の GTID の順序番号の上限は、符号付き 64 ビット整数 (2 から 63-1 の累乗、つまり 9,223,372,036,854,775,807) の負でない値の数です。 GTID が不足すると、サーバーは binlog_error_action
によって指定されたアクションを実行します。 MySQL 8.0.23 からは、サーバーインスタンスが制限に近づいたときに警告メッセージが発行されます。
トランザクションの GTID は、mysqlbinlog からの出力に表示され、replication_applier_status_by_worker
などのパフォーマンススキーマレプリケーションステータステーブル内の個々のトランザクションを識別するために使用されます。 gtid_next
システム変数 (@@GLOBAL.gtid_next
) によって格納される値は単一 GTID です。
GTID セットは、1 つ以上の GTID または GTID の範囲で構成されるセットです。 GTID セットは、いくつかの方法で MySQL サーバーで使用されます。 たとえば、gtid_executed
および gtid_purged
システム変数によって格納される値は GTID セットです。 START REPLICA | SLAVE
句 UNTIL SQL_BEFORE_GTIDS
および UNTIL SQL_AFTER_GTIDS
を使用すると、GTID セット内の最初の GTID までのレプリカプロセストランザクションのみを作成したり、GTID セット内の最後の GTID の後に停止したりできます。 GTID_SUBSET()
および GTID_SUBTRACT()
の組み込み関数には、GTID セットが入力として必要です。
次に示すように、同じサーバーから発生した GTID の範囲を単一の式に縮小できます:
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
前述の例は、server_uuid
が 3E11FA47-71CA-11E1-9E33-C80AA9429562
である MySQL サーバーで発生した最初から 5 番目のトランザクションを表しています。 次の例のように、GTID または範囲をコロンで区切って、同じサーバーから発生した GTID の複数の単一 GTID または範囲を単一の式に含めることもできます:
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-3:11:47-49
GTID セットには、単一 GTID と GTID の範囲の任意の組合せを含めることができ、異なるサーバーから発生した GTID を含めることができます。 この例は、複数のソースからトランザクションを適用したレプリカの gtid_executed
システム変数 (@@GLOBAL.gtid_executed
) に格納されている GTID セットを示しています:
2174B383-5441-11E8-B90A-C80AA9429562:1-3, 24DA167-0C0C-11E8-8442-00059A3C7B00:1-19
GTID セットがサーバー変数から返されると、UUID はアルファベット順になり、数値間隔がマージされて昇順になります。
GTID セットの構文は次のとおりです:
gtid_set:
uuid_set [, uuid_set] ...
| ''
uuid_set:
uuid:interval[:interval]...
uuid:
hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh
h:
[0-9|A-F]
interval:
n[-n]
(n >= 1)
GTID は、mysql
データベースの gtid_executed
という名前のテーブルに格納されます。 このテーブルの行には、GTID または GTID が表す GTID のセットごとに、元のサーバーの UUID、およびセットの開始トランザクション ID と終了トランザクション ID が含まれます。単一 GTID のみを参照する行の場合、これらの最後の 2 つの値は同じです。
mysql.gtid_executed
テーブルは、MySQL Server のインストールまたはアップグレード時に、次に示すような CREATE TABLE
ステートメントを使用して作成されます (まだ存在しない場合):
CREATE TABLE gtid_executed (
source_uuid CHAR(36) NOT NULL,
interval_start BIGINT(20) NOT NULL,
interval_end BIGINT(20) NOT NULL,
PRIMARY KEY (source_uuid, interval_start)
)
他の MySQL システムテーブルと同様に、このテーブルを自分で作成または変更しないでください。
mysql.gtid_executed
テーブルは、MySQL サーバーによる内部使用のために提供されています。 これにより、レプリカでバイナリロギングが無効になっているときにレプリカが GTID を使用できるようになり、バイナリログが失われたときに GTID 状態の保持が有効になります。 RESET MASTER
を発行すると、mysql.gtid_executed
テーブルがクリアされることに注意してください。
GTID は、gtid_mode
が ON
または ON_PERMISSIVE
の場合にのみ mysql.gtid_executed
テーブルに格納されます。 バイナリロギングが無効になっている (log_bin
が OFF
)、または log_slave_updates
が無効になっている場合、サーバーは、トランザクションのコミット時に、各トランザクションに属する GTID を mysql.gtid_executed
テーブルにトランザクションとともに格納します。 また、mysql.gtid_executed テーブル圧縮 で説明されているように、テーブルはユーザーが構成可能なレートで定期的に圧縮されます。
バイナリロギングが有効になっている (log_bin
が ON
)、InnoDB
ストレージエンジンの MySQL 8.0.17 からのみ、サーバーはバイナリロギングまたはレプリカ更新ロギングが無効になっている場合と同じ方法で mysql.gtid_executed
テーブルを更新し、トランザクションのコミット時にトランザクションごとに GTID を格納します。 ただし、MySQL 8.0.17 より前のリリースやその他のストレージエンジンでは、バイナリログがローテーションされるか、サーバーがシャットダウンされたときにのみ、サーバーは mysql.gtid_executed
テーブルを更新します。 この時点で、サーバーは、前のバイナリログに書き込まれたすべてのトランザクションの GTID を mysql.gtid_executed
テーブルに書き込みます。 この状況は、MySQL 8.0.17 より前のソース、バイナリロギングが有効になっている MySQL 8.0.17 より前のレプリカ、または InnoDB
以外のストレージエンジンでは、次のような結果になります:
サーバーが予期せず停止した場合、現在のバイナリログファイルから GTID のセットは
mysql.gtid_executed
テーブルに保存されません。 これらの GTID は、レプリケーションを続行できるように、回復中にバイナリログファイルからテーブルに追加されます。 ただし、(--skip-log-bin
または--disable-log-bin
を使用して) サーバーの再起動時にバイナリロギングを無効にした場合は例外です。 その場合、サーバーはバイナリログファイルにアクセスして GTID を回復できないため、レプリケーションを開始できません。mysql.gtid_executed
テーブルには、実行されたすべてのトランザクションの GTID の完全なレコードは保持されません。 この情報は、gtid_executed
システム変数のグローバル値によって提供されます。 MySQL 8.0.17 より前のリリースおよびInnoDB
以外のストレージエンジンでは、mysql.gtid_executed
テーブルをクエリーする代わりに、コミットのたびに更新される@@GLOBAL.gtid_executed
を使用して、MySQL サーバーの GTID 状態を表します。
MySQL サーバーは、サーバーが読取り専用モードまたはスーパー読取り専用モードの場合でも、mysql.gtid_executed
テーブルに書き込むことができます。 MySQL 8.0.17 より前のリリースでは、これらのモードでバイナリログファイルをローテーションできます。 書き込みのために mysql.gtid_executed
テーブルにアクセスできず、バイナリログファイルが最大ファイルサイズ (max_binlog_size
) に達しない理由でローテーションされた場合、現在のバイナリログファイルが引き続き使用されます。 ローテーションをリクエストしたクライアントにエラーメッセージが返され、サーバーに警告が記録されます。 書込みのために mysql.gtid_executed
テーブルにアクセスできず、max_binlog_size
に到達した場合、サーバーは binlog_error_action
設定に従って応答します。 IGNORE_ERROR
が設定されている場合、サーバーにエラーが記録され、バイナリロギングが停止されます。または、ABORT_SERVER
が設定されている場合、サーバーはシャットダウンします。
この間、mysql.gtid_executed
テーブルには、同じサーバー上で発生し、次に示すような範囲を構成するトランザクション ID を持つ個々の GTID を参照する多数の行を入力できます:
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
|--------------------------------------+----------------+--------------|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 37 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 38 | 38 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 39 | 39 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 40 | 40 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 41 | 41 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 42 | 42 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 43 | 43 |
...
領域を節約するために、MySQL サーバーでは、mysql.gtid_executed
テーブルを定期的に圧縮できます。このような行の各セットを、次のようなトランザクション識別子の間隔全体にわたる単一行に置き換えます:
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
|--------------------------------------+----------------+--------------|
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 43 |
...
サーバーは、thread/sql/compress_gtid_table
という専用のフォアグラウンドスレッドを使用して圧縮を実行できます。 このスレッドは SHOW PROCESSLIST
の出力にはリストされませんが、次に示すように、threads
テーブルの行として表示できます:
mysql> SELECT * FROM performance_schema.threads WHERE NAME LIKE '%gtid%'\G
*************************** 1. row ***************************
THREAD_ID: 26
NAME: thread/sql/compress_gtid_table
TYPE: FOREGROUND
PROCESSLIST_ID: 1
PROCESSLIST_USER: NULL
PROCESSLIST_HOST: NULL
PROCESSLIST_DB: NULL
PROCESSLIST_COMMAND: Daemon
PROCESSLIST_TIME: 1509
PROCESSLIST_STATE: Suspending
PROCESSLIST_INFO: NULL
PARENT_THREAD_ID: 1
ROLE: NULL
INSTRUMENTED: YES
HISTORY: YES
CONNECTION_TYPE: NULL
THREAD_OS_ID: 18677
サーバーでバイナリロギングが有効になっている場合、この圧縮方法は使用されず、代わりに mysql.gtid_executed
テーブルはバイナリログのローテーションごとに圧縮されます。 ただし、バイナリロギングがサーバーで無効になっている場合、thread/sql/compress_gtid_table
スレッドは指定された数のトランザクションが実行されるまでスリープしてから、mysql.gtid_executed
テーブルの圧縮を実行するためにウェイクアップします。 その後、同じ数のトランザクションが発生するまでスリープしてから、圧縮を再度実行するためにウェイクアップし、このループを無期限に繰り返します。 テーブルが圧縮される前に経過したトランザクションの数、つまり圧縮率は、gtid_executed_compression_period
システム変数の値によって制御されます。 この値を 0 に設定すると、スレッドはウェイクアップしません。つまり、この明示的な圧縮方法は使用されません。 かわりに、圧縮は必要に応じて暗黙的に行われます。
MySQL 8.0.17 から、InnoDB
トランザクションは InnoDB
以外のトランザクションに対する個別のプロセスによって mysql.gtid_executed
テーブルに書き込まれます。 このプロセスは、別のスレッドである innodb/clone_gtid_thread
によって制御されます。 この GTID 永続スレッドは GTID をグループ単位で収集し、mysql.gtid_executed
テーブルにフラッシュしてから、テーブルを圧縮します。 サーバーに、mysql.gtid_executed
テーブルに個別に書き込まれる InnoDB
トランザクションと InnoDB
以外のトランザクションが混在している場合、compress_gtid_table
スレッドによって実行される圧縮は GTID 永続スレッドの作業を妨げ、大幅に遅くなる可能性があります。 このため、このリリースからは、compress_gtid_table
スレッドがアクティブ化されないように、gtid_executed_compression_period
を 0 に設定することをお薦めします。
MySQL 8.0.23 からは、gtid_executed_compression_period
のデフォルト値は 0 で、InnoDB
トランザクションと InnoDB
以外のトランザクションの両方が GTID 永続性スレッドによって mysql.gtid_executed
テーブルに書き込まれます。
MySQL 8.0.17 より前のリリースでは、gtid_executed_compression_period
のデフォルト値 1000 を使用できます。つまり、1000 トランザクションごとにテーブルの圧縮が実行されるか、別の値を選択できます。 これらのリリースでは、値 0 を設定し、バイナリロギングが無効になっている場合、mysql.gtid_executed
テーブルで明示的な圧縮は実行されないため、これを行うと、テーブルで必要になる可能性のあるディスク容量が大幅に増加する可能性がある準備をするようにしてください。
サーバーインスタンスの起動時に、gtid_executed_compression_period
がゼロ以外の値に設定され、thread/sql/compress_gtid_table
スレッドが起動された場合、ほとんどのサーバー構成では、mysql.gtid_executed
テーブルに対して明示的な圧縮が実行されます。 MySQL 8.0.17 より前のリリースでは、バイナリロギングが有効になっている場合、圧縮は起動時にローテーションされるバイナリログによってトリガーされます。 MySQL 8.0.20 からのリリースでは、圧縮はスレッドの起動によってトリガーされます。 介在するリリースでは、圧縮は起動時に行われません。