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


17.1.3.8 GTID を操作するストアドファンクションの例

MySQL には、GTID ベースのレプリケーションで使用する組込み (ネイティブ) 関数がいくつか含まれています。 これらの関数は次のとおりです:

GTID_SUBSET(set1,set2)

グローバルトランザクション識別子 set1 および set2 の 2 つのセットが指定されている場合、set1 内のすべての GTID も set2 内にあると true を返します。 それ以外の場合は、false を返します。

GTID_SUBTRACT(set1,set2)

グローバルトランザクション識別子 set1 および set2 の 2 つのセットがある場合、set2 にない GTID のみを set1 から返します。

WAIT_FOR_EXECUTED_GTID_SET(gtid_set[, timeout])

サーバーが、グローバルトランザクション識別子が gtid_set に含まれているすべてのトランザクションを適用するまで待機します。 オプションのタイムアウトは、指定された秒数が経過すると、関数の待機を停止します。

これらの関数の詳細は、セクション12.19「グローバルトランザクション識別子 (GTID) で使用される機能」 を参照してください。

GTID を操作する独自のストアドファンクションを定義できます。 ストアドファンクションの定義の詳細は、第25章「ストアドオブジェクト を参照してください。 次の例は、組込みの GTID_SUBSET() および GTID_SUBTRACT() 関数に基づいて作成できる便利なストアドファンクションを示しています。

これらのストアドファンクションでは、次のように delimiter コマンドを使用して MySQL ステートメントデリミタを縦棒に変更しています:

mysql> delimiter |

これらの関数はすべて GTID セットの文字列表現を引数として取るため、GTID セットと一緒に使用する場合は常に引用符で囲む必要があります。

この関数は、2 つの GTID セットが同じセットである場合、同じ方法で書式設定されていなくても、ゼロ以外 (true) を返します。

CREATE FUNCTION GTID_IS_EQUAL(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT)
RETURNS INT
  RETURN GTID_SUBSET(gtid_set_1, gtid_set_2) AND GTID_SUBSET(gtid_set_2, gtid_set_1)|

この関数は、2 つの GTID セットが非結合の場合、ゼロ以外 (true) を返します。

CREATE FUNCTION GTID_IS_DISJOINT(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT)
RETURNS INT
  RETURN GTID_SUBSET(gtid_set_1, GTID_SUBTRACT(gtid_set_1, gtid_set_2))|

この関数は、2 つの GTID セットが非結合で、sum が 2 つのセットの和集合である場合、ゼロ以外 (true) を返します。

CREATE FUNCTION GTID_IS_DISJOINT_UNION(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT, sum LONGTEXT)
RETURNS INT
  RETURN GTID_IS_EQUAL(GTID_SUBTRACT(sum, gtid_set_1), gtid_set_2) AND
         GTID_IS_EQUAL(GTID_SUBTRACT(sum, gtid_set_2), gtid_set_1)|

この関数は、GTID セットの正規化された形式をすべて大文字で返します。空白はなく、重複もありません。 UUID はアルファベット順に配置され、間隔は数値順に配置されます。

CREATE FUNCTION GTID_NORMALIZE(g LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(g, '')|

この関数は、2 つの GTID セットの和集合を返します。

CREATE FUNCTION GTID_UNION(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT)
RETURNS LONGTEXT
  RETURN GTID_NORMALIZE(CONCAT(gtid_set_1, ',', gtid_set_2))|

この関数は、2 つの GTID セットの交差を返します。

CREATE FUNCTION GTID_INTERSECTION(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT)
RETURNS LONGTEXT
  RETURN GTID_SUBTRACT(gtid_set_1, GTID_SUBTRACT(gtid_set_1, gtid_set_2))|

この関数は、2 つの GTID セット (gtid_set_1 には存在するが gtid_set_2 には存在しない GTID) と、gtid_set_2 には存在するが gtid_set_1 には存在しない GTID の対称差異を戻します。

CREATE FUNCTION GTID_SYMMETRIC_DIFFERENCE(gtid_set_1 LONGTEXT, gtid_set_2 LONGTEXT)
RETURNS LONGTEXT
  RETURN GTID_SUBTRACT(CONCAT(gtid_set_1, ',', gtid_set_2), GTID_INTERSECTION(gtid_set_1, gtid_set_2))|

この関数は GTID セットから、指定された起点からすべての GTID を削除し、残りの GTID があればそれを返します。 UUID は、トランザクションが発生したサーバーで使用される識別子で、通常は server_uuid 値です。

CREATE FUNCTION GTID_SUBTRACT_UUID(gtid_set LONGTEXT, uuid TEXT)
RETURNS LONGTEXT
  RETURN GTID_SUBTRACT(gtid_set, CONCAT(UUID, ':1-', (1 << 63) - 2))|

この関数は、指定された識別子 (UUID) を持つサーバーから発生した GTID セットの GTID のみを返すように、以前に一覧表示された関数を逆にします。

CREATE FUNCTION GTID_INTERSECTION_WITH_UUID(gtid_set LONGTEXT, uuid TEXT)
RETURNS LONGTEXT
  RETURN GTID_SUBTRACT(gtid_set, GTID_SUBTRACT_UUID(gtid_set, uuid))|

例 17.1 レプリカが最新であることの確認

組込み関数 GTID_SUBSET および GTID_SUBTRACT を使用すると、ソースが適用したすべてのトランザクションにレプリカが適用されているかどうかを確認できます。

GTID_SUBSET でこのチェックを実行するには、レプリカで次のステートメントを実行します:

SELECT GTID_SUBSET(source_gtid_executed, replica_gtid_executed)

これが 0 (false) を返す場合、source_gtid_executed の GTID の一部が replica_gtid_executed に存在しないため、レプリカが適用されていないトランザクションがソースによって適用されているため、レプリカは最新ではありません。

GTID_SUBTRACT でチェックを実行するには、レプリカで次のステートメントを実行します:

SELECT GTID_SUBTRACT(source_gtid_executed, replica_gtid_executed)

このステートメントは、source_gtid_executed にはあるが replica_gtid_executed にはない GTID を返します。 GTID が返された場合、ソースはレプリカが適用していない一部のトランザクションを適用しているため、レプリカは最新ではありません。


例 17.2 バックアップおよびリストアのシナリオ

ストアドファンクション GTID_IS_EQUALGTID_IS_DISJOINT および GTID_IS_DISJOINT_UNION を使用して、複数のデータベースおよびサーバーに関連するバックアップおよびリストア操作を検証できます。 この例のシナリオでは、server1 にデータベース db1 が含まれ、server2 にデータベース db2 が含まれています。 目的は、データベース db2server1 にコピーし、server1 での結果を 2 つのデータベースの和集合にすることです。 使用する手順は、mysqlpump または mysqldump を使用して server2 をバックアップし、server1 でこのバックアップをリストアすることです。

バックアッププログラムオプション --set-gtid-purgedON に設定されているか、AUTO のデフォルトに設定されている場合、プログラム出力には SET @@GLOBAL.gtid_purged ステートメントが含まれ、gtid_executed セットを server2 から server1gtid_purged に追加します。 gtid_purged セットには、サーバー上でコミットされたが、サーバー上のバイナリログファイルに存在しないすべてのトランザクションの GTID が含まれています。 データベース db2server1 にコピーする場合、server1 のバイナリログファイルにない server2 でコミットされたトランザクションの GTID を server1gtid_purged セットに追加して、セットを完成させる必要があります。

ストアドファンクションを使用すると、このシナリオの次のステップを実行できます:

  • GTID_IS_EQUAL を使用して、バックアップ操作によって SET @@GLOBAL.gtid_purged ステートメントの正しい GTID セットが計算されたことを確認します。 server2 では、mysqlpump または mysqldump の出力からそのステートメントを抽出し、GTID セットを $gtid_purged_set などのローカル変数に格納します。 次に、次のステートメントを実行します:

    server2> SELECT GTID_IS_EQUAL($gtid_purged_set, @@GLOBAL.gtid_executed);

    結果が 1 の場合、2 つの GTID セットは等しく、セットは正しく計算されています。

  • GTID_IS_DISJOINT を使用して、mysqlpump または mysqldump 出力の GTID セットが server1gtid_executed セットと重複していないことを確認します。 両方のサーバーに同一の GTID が存在すると、データベース db2server1 にコピーするときにエラーが発生します。 確認するには、server1 で、前述のように出力から gtid_purged セットを抽出してローカル変数に格納し、次のステートメントを実行します:

    server1> SELECT GTID_IS_DISJOINT($gtid_purged_set, @@GLOBAL.gtid_executed);

    結果が 1 の場合、2 つの GTID セット間に重複がないため、重複する GTID は存在しません。

  • GTID_IS_DISJOINT_UNION を使用して、リストア操作が server1 で正しい GTID 状態になったことを確認します。 バックアップをリストアする前に、server1 で次のステートメントを実行して既存の gtid_executed セットを取得します:

    server1> SELECT @@GLOBAL.gtid_executed;

    結果をローカル変数 $original_gtid_executed に格納します。 また、前述のように、gtid_purged セットをローカル変数に格納します。 server2 からのバックアップが server1 にリストアされたら、次のステートメントを実行して GTID 状態を確認します:

    server1> SELECT GTID_IS_DISJOINT_UNION($original_gtid_executed,
                                           $gtid_purged_set,
                                           @@GLOBAL.gtid_executed);

    結果が 1 の場合、ストアドファンクションは、server1 ($original_gtid_executed) からの元の gtid_executed セットと server2 ($gtid_purged_set) から追加された gtid_purged セットが重複していないことを検証し、server1 で更新された gtid_executed セットが、server1 からの以前の gtid_executed セットと server2 からの gtid_purged セットで構成されるようになりました。これが目的の結果です。 server1 でこれ以上のトランザクションが実行される前に、このチェックが実行されていることを確認してください。実行されていない場合、gtid_executed セットの新しいトランザクションが失敗します。


例 17.3 手動フェイルオーバー用の最新レプリカの選択

ストアドファンクション GTID_UNION を使用すると、ソースサーバーが予期せず停止した後に手動フェイルオーバー操作を実行するために、レプリカのセットから最新のレプリカを識別できます。 一部のレプリカでレプリケーションラグが発生している場合、このストアドファンクションを使用すると、すべてのレプリカが既存のリレーログを適用するのを待機せずに最新のレプリカを計算できるため、フェイルオーバー時間を最小限に抑えることができます。 この関数は、「パフォーマンススキーマ」テーブル replication_connection_status に記録されているレプリカが受信したトランザクションのセットを使用して、各レプリカの gtid_executed セットの和集合を戻すことができます。 これらの結果を比較して、すべてのトランザクションがまだコミットされていない場合でも、最新のトランザクションのレプリカレコードを検索できます。

各レプリカで、次のステートメントを発行してトランザクションの完全なレコードを計算します:

SELECT GTID_UNION(RECEIVED_TRANSACTION_SET, @@GLOBAL.gtid_executed)
    FROM performance_schema.replication_connection_status
    WHERE channel_name = 'name';

その後、各レプリカの結果を比較してトランザクションの最新レコードを確認し、このレプリカを新しいソースとして使用できます。


例 17.4 レプリカ上の無関係なトランザクションのチェック

ストアドファンクション GTID_SUBTRACT_UUID を使用すると、指定されたソースから発生しなかったトランザクションをレプリカが受信したかどうかを確認できます。 その場合は、レプリケーションの設定、またはプロキシ、ルーターまたはロードバランサに問題がある可能性があります。 この機能は、GTID セットから指定された発信元サーバーからすべての GTID を削除し、残りの GTID があればそれを返すことによって機能します。

単一のソースからレプリケートするレプリカの場合、次のステートメントを発行し、元のソースの識別子 (通常は server_uuid 値) を指定します:

SELECT GTID_SUBTRACT_UUID(@@GLOBAL.gtid_executed, server_uuid_of_source);

結果が空でない場合、返されるトランザクションは、指定されたソースから発生しなかった余分なトランザクションです。

マルチソースレプリケーショントポロジのレプリカの場合は、次の例のように機能を繰り返します:

SELECT GTID_SUBTRACT_UUID(GTID_SUBTRACT_UUID(@@GLOBAL.gtid_executed,
                                             server_uuid_of_source_1),
                                             server_uuid_of_source_2);

結果が空でない場合、返されるトランザクションは、指定されたどのソースからも発生しなかった余分なトランザクションです。


例 17.5 レプリケーショントポロジ内のサーバーが読取り専用であることの確認

ストアドファンクション GTID_INTERSECTION_WITH_UUID を使用すると、サーバーが GTID を発生させておらず、読取り専用状態であることを検証できます。 この関数は、指定された識別子を持つサーバーから発生した GTID セットから GTID のみを返します。 サーバー gtid_executed セット内のいずれかのトランザクションにサーバー独自の識別子がある場合、サーバー自体がそれらのトランザクションを開始しています。 サーバーで次のステートメントを発行して確認できます:

SELECT GTID_INTERSECTION_WITH_UUID(@@GLOBAL.gtid_executed, my_server_uuid);


例 17.6 マルチソースレプリケーション設定での追加レプリカの検証

ストアドファンクション GTID_INTERSECTION_WITH_UUID を使用すると、マルチソースレプリケーション設定にアタッチされたレプリカが、特定のソースから発生したすべてのトランザクションを適用したかどうかを確認できます。 このシナリオでは、source1source2 の両方がソースとレプリカであり、相互にレプリケートされます。source2 には、独自のレプリカもあります。 また、source2log_slave_updates=ON で構成されている場合、レプリカはソース source1 からトランザクションを受信して適用しますが、source2log_slave_updates=OFF を使用している場合は行いません。 いずれの場合も、現在、レプリカが source2 で最新であるかどうかのみを確認します。 この状況では、ストアドファンクション GTID_INTERSECTION_WITH_UUID を使用して、source2 が発生させたトランザクションを識別し、source2source1 からレプリケートしたトランザクションを破棄できます。 その後、組込み関数 GTID_SUBSET を使用して、結果をレプリカ上の gtid_executed セットと比較できます。 レプリカが source2 で最新の場合、レプリカに設定されている gtid_executed には交差セット (source2 から発生したトランザクション) 内のすべてのトランザクションが含まれます。

このチェックを実行するには、次のように、source2gtid_executed セット、source2 のサーバー UUID およびレプリカ gtid_executed セットをクライアント側の変数に格納します:

    $source2_gtid_executed :=
      source2> SELECT @@GLOBAL.gtid_executed;
    $source2_server_uuid :=
      source2> SELECT @@GLOBAL.server_uuid;
    $replica_gtid_executed :=
      replica> SELECT @@GLOBAL.gtid_executed;

次に、次のように、これらの変数を入力として GTID_INTERSECTION_WITH_UUID および GTID_SUBSET を使用します:

SELECT GTID_SUBSET(GTID_INTERSECTION_WITH_UUID($source2_gtid_executed,
                                               $source2_server_uuid),
                                               $replica_gtid_executed);

source2 ($source2_server_uuid) のサーバー識別子は、source1 で発生した GTID を除外して、source2gtid_executed セットからの GTID のみを識別して返すために GTID_INTERSECTION_WITH_UUID とともに使用されます。 結果の GTID セットは、GTID_SUBSET を使用して、レプリカで実行されたすべての GTID のセットと比較されます。 このステートメントがゼロ以外 (true) を返す場合、source2 から識別された GTID (最初のセット入力) もすべてレプリカ gtid_executed セット (2 番目のセット入力) に含まれます。つまり、レプリカは source2 から発生したすべてのトランザクションをレプリケートしています。



関連キーワード:  GTID, gtid, セット, トランザクション, executed, server, ソース, サーバー, 関数, LONGTEXT