TiCDC の動作の変更
更新イベントを削除イベントと挿入イベントに分割する
単一の更新変更を含むトランザクション
v6.5.3、v7.1.1、v7.2.0 以降では、MySQL 以外のシンクを使用する場合、単一の更新変更のみを含むトランザクションでは、更新イベントで主キーまたは null 以外の一意のインデックス値が変更されると、TiCDC はこのイベントを削除イベントと挿入イベントに分割します。詳細については、GitHub の問題#9086を参照してください。
この変更は主に次の問題に対処します。
- CSV および AVRO プロトコルを使用する場合、古い値は出力されずに新しい値のみが出力されます。そのため、主キーまたは null 以外の一意のインデックス値が変更されると、コンシューマーは新しい値しか受信できず、変更前の値を処理する (たとえば、古い値を削除する) ことができなくなります。
- インデックス値ディスパッチャーを使用して、キーに基づいて異なる Kafka パーティションにデータを分散する場合、下流のコンシューマー グループ内の複数のコンシューマー プロセスが Kafka トピック パーティションを個別に消費します。消費の進行状況が異なるため、データの不整合が発生する可能性があります。
次の SQL を例に挙げます。
CREATE TABLE t (a INT PRIMARY KEY, b INT);
INSERT INTO t VALUES (1, 1);
UPDATE t SET a = 2 WHERE a = 1;
この例では、主キーa
が1
から2
に更新されます。更新イベントが分割されていない場合は、次のようになります。
- CSV および AVRO プロトコルを使用する場合、コンシューマーは新しい値
a = 2
のみを取得し、古い値a = 1
を取得できません。これにより、下流のコンシューマーは古い値1
を削除せずに、新しい値2
のみを挿入する可能性があります。 - インデックス値ディスパッチャーを使用する場合、挿入イベント
(1, 1)
がパーティション 0 に送信され、更新イベント(2, 1)
がパーティション 1 に送信される場合があります。パーティション 1 の消費の進行がパーティション 0 の消費よりも速い場合、下流に対応するデータがないためエラーが発生する可能性があります。そのため、TiCDC は更新イベントを削除イベントと挿入イベントに分割します。削除イベント(1, 1)
はパーティション 0 に送信され、書き込みイベント(2, 1)
はパーティション 1 に送信され、コンシューマーの進行に関係なくイベントが正常に消費されることが保証されます。
複数の更新変更を含むトランザクション
v6.5.4、v7.1.2、v7.4.0 以降では、複数の変更を含むトランザクションの場合、更新イベントで主キーまたは null 以外の一意のインデックス値が変更されると、TiCDC はイベントを削除イベントと挿入イベントに分割し、すべてのイベントが挿入イベントに先行する削除イベントのシーケンスに従うようにします。詳細については、GitHub の問題#9430を参照してください。
この変更は主に、MySQL シンクを使用してこれら 2 つのイベントをダウンストリームに直接書き込むときに主キーまたは一意キーの競合が発生し、変更フィード エラーが発生する可能性がある問題に対処します。Kafka シンクまたはその他のシンクを使用する場合、コンシューマーがリレーショナル データベースにメッセージを書き込むか、同様の操作を実行すると、同じエラーが発生する可能性があります。
次の 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 つの更新変更イベント、つまり主キーa
を1
から2
に変更し、主キーa
を2
から1
に変更するイベントのみを受信します。MySQL シンクがこれらの 2 つの更新イベントをダウンストリームに直接書き込むと、主キーの競合が発生し、変更フィード エラーが発生する可能性があります。
したがって、TiCDC はこれら 2 つのイベントを 4 つのイベントに分割し、レコード(1, 1)
と(2, 2)
を削除し、レコード(2, 1)
と(1, 2)
を書き込みます。