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

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

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

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

この動作の変更により、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ステートメントは実行時に順次依存関係を持ちます。主キーa2から3に変更され、次に主キーa1から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に変更し、主キーa2から1に変更するイベントのみを受信します。コンシューマーがこれら 2 つのUPDATEイベントをダウンストリームに直接書き込むと、主キーの競合が発生し、変更フィード エラーが発生します。

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

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

v6.5.10、v7.1.6、v7.5.3 以降では、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イベントを分割しません。テーブルの主キーがクラスター化インデックスである場合、主キーの更新は TiDB でDELETEイベントとINSERTイベントに分割され、このような動作は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/アブロ分割しますが、並べ替えは行いません。1 #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/アブロ分割しますが、並べ替えは行いません。1 #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 )

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