MySQL 8.0 リファレンスマニュアル


17.1.3.1 GTID 形式および格納

グローバルトランザクション識別子 (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 番目のトランザクションには 10transaction_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 セット

GTID セットは、1 つ以上の GTID または GTID の範囲で構成されるセットです。 GTID セットは、いくつかの方法で MySQL サーバーで使用されます。 たとえば、gtid_executed および gtid_purged システム変数によって格納される値は GTID セットです。 START REPLICA | SLAVEUNTIL 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_uuid3E11FA47-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)
mysql.gtid_executed テーブル

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_modeON または ON_PERMISSIVE の場合にのみ mysql.gtid_executed テーブルに格納されます。 バイナリロギングが無効になっている (log_binOFF)、または log_slave_updates が無効になっている場合、サーバーは、トランザクションのコミット時に、各トランザクションに属する GTID を mysql.gtid_executed テーブルにトランザクションとともに格納します。 また、mysql.gtid_executed テーブル圧縮 で説明されているように、テーブルはユーザーが構成可能なレートで定期的に圧縮されます。

バイナリロギングが有効になっている (log_binON)、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 テーブル圧縮

この間、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 からのリリースでは、圧縮はスレッドの起動によってトリガーされます。 介在するリリースでは、圧縮は起動時に行われません。


関連キーワード:  GTID, トランザクション, gtid, サーバー, テーブル, executed, バイナリ, ソース, 圧縮, セット