UPDATE イベントを分割する際の TiCDC の動作

MySQLシンクのUPDATEイベントを分割する

v6.5.10、v7.1.6、v7.5.2、v8.1.1 以降では、MySQL シンクを使用する場合、テーブルのレプリケーション要求を受信したすべての TiCDC ノードは、ダウンストリームへのレプリケーションを開始する前に、PD から現在のタイムスタンプthresholdTS取得します。このタイムスタンプの値に基づいて、TiCDC はUPDATEイベントを分割するかどうかを決定します。

  • 1 つまたは複数のUPDATE変更を含むトランザクションの場合、トランザクションcommitTSthresholdTS未満であれば、TiCDC はUPDATEイベントをDELETEイベントとINSERTイベントに分割してから、それらを Sorter モジュールに書き込みます。
  • トランザクションcommitTSthresholdTS以上であるUPDATEのイベントの場合、TiCDC はそれらを分割しません。詳細については、GitHub の問題#10918を参照してください。

注記:

v8.1.0 では、MySQL Sink を使用する場合、TiCDC はthresholdTSの値に基づいてUPDATEイベントを分割するかどうかも決定しますが、 thresholdTS別の方法で取得されます。具体的には、v8.1.0 では、 thresholdTS TiCDC の起動時に PD から取得される現在のタイムスタンプですが、この方法ではマルチノード シナリオでデータの不整合の問題が発生する可能性があります。詳細については、GitHub の問題#11219を参照してください。

この動作の変更 (つまり、 thresholdTSに基づいてUPDATEイベントを分割するかどうかを決定する) は、TiCDC が受信したUPDATEのイベントの順序が誤っている可能性があり、その結果、分割されたDELETEおよびINSERTイベントの順序が誤っているために発生するダウンストリーム データの不整合の問題を解決します。

次の SQL ステートメントを例に挙げます。

CREATE TABLE t (a INT PRIMARY KEY, b INT); INSERT INTO t VALUES (1, 1); INSERT INTO t VALUES (2, 2); BEGIN; UPDATE t SET a = 3 WHERE a = 2; UPDATE t SET a = 2 WHERE a = 1; COMMIT;

この例では、トランザクション内の 2 つのUPDATEステートメントは実行時に順次依存関係を持ちます。主キーa 2から3に変更され、次に主キーa 1から2に変更されます。このトランザクションが実行されると、上流データベースのレコードは(2, 1)(3, 2)なります。

ただし、TiCDC が受信するUPDATEイベントの順序は、上流トランザクションの実際の実行順序と異なる場合があります。例:

UPDATE t SET a = 2 WHERE a = 1; UPDATE t SET a = 3 WHERE a = 2;
  • この動作変更の前は、TiCDC はこれらのUPDATEイベントを Sorter モジュールに書き込み、それらをDELETE INSERTイベントに分割していました。分割後、ダウンストリームでのこれらのイベントの実際の実行順序は次のようになります。

    BEGIN; DELETE FROM t WHERE a = 1; REPLACE INTO t VALUES (2, 1); DELETE FROM t WHERE a = 2; REPLACE INTO t VALUES (3, 2); COMMIT;

    ダウンストリームがトランザクションを実行した後、データベース内のレコードは(3, 2)になりますが、これはアップストリーム データベース内のレコード ( (2, 1)(3, 2) ) と異なり、データの不整合の問題があることを示しています。

  • この動作変更後、TiCDC が対応するテーブルをダウンストリームに複製し始めたときに、トランザクションcommitTS PD から取得されたthresholdTSより少ない場合、TiCDC はこれらのUPDATEイベントをDELETEINSERTイベントに分割してから、Sorter モジュールに書き込みます。Sorter モジュールによるソート後、ダウンストリームでのこれらのイベントの実際の実行順序は次のようになります。

    BEGIN; DELETE FROM t WHERE a = 1; DELETE FROM t WHERE a = 2; REPLACE INTO t VALUES (2, 1); REPLACE INTO t VALUES (3, 2); COMMIT;

    ダウンストリームがトランザクションを実行すると、ダウンストリーム データベースのレコードはアップストリーム データベースのレコード ( (2, 1)(3, 2)と同じになり、データの一貫性が確保されます。

前の例からわかるように、 UPDATEイベントをDELETE INSERTイベントに分割してから Sorter モジュールに書き込むと、分割後のINSERTイベントの前にDELETEイベントがすべて実行されるため、TiCDC が受信したUPDATEイベントの順序に関係なく、データの一貫性が維持されます。

注記:

この動作変更後、MySQL シンクを使用すると、ほとんどの場合、TiCDC はUPDATEイベントを分割しません。その結果、changefeed 実行時に主キーまたは一意キーの競合が発生し、changefeed が自動的に再起動される可能性があります。再起動後、TiCDC は競合するUPDATEイベントをDELETE INSERTイベントに分割してから、Sorter モジュールに書き込みます。これにより、同じトランザクション内のすべてのイベントが正しく順序付けられ、 DELETEイベントすべてがINSERTイベントより前に来るため、データ レプリケーションが正しく完了します。

非MySQLシンクの主キーまたは一意キーのUPDATEイベントを分割する

単一のUPDATE変更を含むトランザクション

v6.5.3、v7.1.1、v7.2.0 以降では、MySQL 以外のシンクを使用する場合、単一の更新変更のみを含むトランザクションで、主キーまたは null 以外の一意のインデックス値がUPDATEイベントで変更されると、TiCDC はこのイベントをDELETEつとINSERTイベントに分割します。詳細については、GitHub の問題#9086を参照してください。

この変更は主に、CSV および AVRO プロトコルを使用する場合、TiCDC がデフォルトで古い値なしで新しい値のみを出力するという問題に対処します。この問題により、主キーまたは null 以外の一意のインデックス値が変更されると、コンシューマーは新しい値しか受信できず、変更前の値を処理することができなくなります (たとえば、古い値を削除する)。次の SQL を例に挙げます。

CREATE TABLE t (a INT PRIMARY KEY, b INT); INSERT INTO t VALUES (1, 1); UPDATE t SET a = 2 WHERE a = 1;

この例では、主キーa1から2に更新されます。 UPDATEイベントが分割されていない場合、CSV および AVRO プロトコルを使用すると、コンシューマーは新しい値a = 2のみを取得でき、古い値a = 1取得できません。これにより、下流のコンシューマーは古い値1削除せずに、新しい値2のみを挿入する可能性があります。

複数のUPDATE変更を含むトランザクション

v6.5.4、v7.1.2、v7.4.0 以降では、複数の変更を含むトランザクションの場合、主キーまたは null 以外の一意のインデックス値がUPDATE番目のイベントで変更されると、TiCDC はイベントをDELETEつとINSERTのイベントに分割し、すべてのイベントがINSERTイベントの前のDELETEのイベントのシーケンスに従うようにします。詳細については、GitHub の問題#9430を参照してください。

この変更は主に、Kafka シンクまたは他のシンクからリレーショナル データベースにデータ変更を書き込むとき、または同様の操作を実行するときにコンシューマーが遭遇する可能性のある主キーまたは一意キーの競合の潜在的な問題に対処します。この問題は、TiCDC が受信したUPDATEのイベントの順序が間違っている可能性があることによって発生します。

次の SQL を例に挙げます。

CREATE TABLE t (a INT PRIMARY KEY, b INT); INSERT INTO t VALUES (1, 1); INSERT INTO t VALUES (2, 2); BEGIN; UPDATE t SET a = 3 WHERE a = 1; UPDATE t SET a = 1 WHERE a = 2; UPDATE t SET a = 2 WHERE a = 3; COMMIT;

この例では、2 つの行の主キーを交換する 3 つの SQL 文を実行することで、TiCDC は 2 つの更新変更イベント、つまり主キーa1から2に変更し、主キーa 2から1に変更するイベントのみを受信します。コンシューマーがこれら 2 つのUPDATEイベントをダウンストリームに直接書き込むと、主キーの競合が発生し、変更フィード エラーが発生します。

したがって、TiCDC はこれら 2 つのイベントを 4 つのイベントに分割し、レコード(1, 1)(2, 2)削除し、レコード(2, 1)(1, 2)書き込みます。

主キーまたは一意キーのUPDATEイベントを分割するかどうかを制御する

v6.5.10、v7.1.6、v7.5.3、v8.1.1 以降では、MySQL 以外のシンクを使用する場合、TiCDC は、GitHub の問題#11211で説明されているように、 output-raw-change-eventパラメータを介してプライマリ キーまたは一意のキーUPDATEイベントを分割するかどうかの制御をサポートします。このパラメータの具体的な動作は次のとおりです。

  • output-raw-change-event = false設定すると、主キーまたは null 以外の一意のインデックス値がUPDATEイベントで変更された場合、TiCDC はイベントをDELETEINSERTイベントに分割し、すべてのイベントがINSERTイベントの前のDELETEイベントのシーケンスに従うようにします。
  • output-raw-change-event = true設定すると、TiCDC はUPDATEイベントを分割せず、コンシューマー側が非MySQLシンクの主キーまたは一意キーのUPDATEイベントを分割するで説明した問題に対処する必要があります。そうしないと、データの不整合が発生するリスクがあります。テーブルの主キーがクラスター化インデックスである場合、主キーの更新は TiDB でDELETEINSERTイベントに分割され、このような動作はoutput-raw-change-eventパラメータの影響を受けません。

注記

次の表では、UK/PK は主キーまたは一意キーを表します。

リリース 6.5 の互換性

バージョンプロトコルスプリットUK/PK UPDATEイベントUK/PK UPDATEイベントを分割しないコメント
<= v6.5.2全て
v6.5.3 / v6.5.4運河/オープン
バージョン6.5.3CSV/アブロ分割しますが、並べ替えは行いません#9086参照してください。
バージョン6.5.4運河/オープン複数の変更を含むトランザクションのみを分割して並べ替える
v6.5.5 ~ v6.5.9全て
= v6.5.10全て✓ (デフォルト値: output-raw-change-event = false )✓ (オプション: output-raw-change-event = true )

リリース 7.1 の互換性

バージョンプロトコルスプリットUK/PK UPDATEイベントUK/PK UPDATEイベントを分割しないコメント
バージョン7.1.0全て
バージョン7.1.1運河/オープン
バージョン7.1.1CSV/アブロ分割しますが、並べ替えは行いません#9086参照してください。
v7.1.2 ~ v7.1.5全て
= v7.1.6全て✓ (デフォルト値: output-raw-change-event = false )✓ (オプション: output-raw-change-event = true )

リリース 7.5 の互換性

バージョンプロトコルスプリットUK/PK UPDATEイベントUK/PK UPDATEイベントを分割しないコメント
<= v7.5.2全て
= v7.5.3全て✓ (デフォルト値: output-raw-change-event = false )✓ (オプション: output-raw-change-event = true )

リリース 8.1 の互換性

バージョンプロトコルスプリットUK/PK UPDATEイベントUK/PK UPDATEイベントを分割しないコメント
バージョン8.1.0全て
= v8.1.1全て✓ (デフォルト値: output-raw-change-event = false )✓ (オプション: output-raw-change-event = true )

このページは役に立ちましたか?