オプティミスティック モードでシャード テーブルからデータをマージおよび移行する
このドキュメントでは、楽観的モードでデータ移行 (DM) によって提供されるシャーディング サポート機能を紹介します。この機能を使用すると、アップストリームの MySQL または MariaDB インスタンス内の同じまたは異なるテーブル スキーマを持つテーブルのデータを、ダウンストリームの TiDB 内の 1 つの同じテーブルにマージして移行できます。
注記:
楽観的モードとその制限事項を詳しく理解していない場合は、このモードの使用はお勧めしません。そうしないと、移行が中断されたり、データの不整合が発生する可能性があります。
背景
DM は、シャーディング DDL と呼ばれるシャーディング テーブルでの DDL ステートメントのオンライン実行をサポートし、デフォルトで「悲観的モード」を使用します。このモードでは、上流のシャーディング テーブルで DDL ステートメントが実行されると、同じ DDL ステートメントが他のすべてのシャーディング テーブルで実行されるまで、このテーブルのデータ移行は一時停止されます。その時点でのみ、この DDL ステートメントが下流で実行され、データ移行が再開されます。
悲観的モードでは、ダウンストリームに移行されたデータが常に正しいことが保証されますが、データ移行が一時停止されるため、アップストリームで A/B 変更を行うのに適していません。場合によっては、ユーザーは単一のシャード テーブルで DDL ステートメントを実行するのに長い時間を費やし、検証期間が経過した後にのみ他のシャード テーブルのスキーマを変更することがあります。悲観的モードでは、これらの DDL ステートメントによってデータ移行がブロックされ、多くのbinlogイベントが蓄積されます。
したがって、「楽観的モード」が必要です。このモードでは、シャード テーブルで実行された DDL ステートメントは、他のシャード テーブルと互換性のあるステートメントに自動的に変換され、すぐにダウンストリームに移行されます。このように、DDL ステートメントは、シャード テーブルによる DML 移行の実行をブロックしません。
楽観的モードのコンフィグレーション
楽観的モードを使用するには、タスク設定ファイルのshard-mode項目をoptimisticに指定します。 strict-optimistic-shard-mode設定を有効にすることで、楽観的モードの動作を制限できます。詳細なサンプル設定ファイルについては、 DM 高度なタスクコンフィグレーションファイル参照してください。
制限
楽観的モードを使用するには、ある程度のリスクが伴います。使用時には、次のルールに従ってください。
DDL ステートメントのバッチを実行する前と実行後に、各シャード テーブルのスキーマが相互に一貫していることを確認します。
A/B テストを実行する場合は、1 つのシャード テーブルでのみテストを実行します。
A/B テストが終了したら、最も直接的な DDL ステートメントのみを最終スキーマに移行します。テストのすべての正しいステップまたは間違ったステップを再実行しないでください。
たとえば、シャード テーブルで
ADD COLUMN A INT; DROP COLUMN A; ADD COLUMN A FLOAT;実行した場合、他のシャード テーブルではADD COLUMN A FLOAT実行するだけで済みます。3 つの DDL ステートメントすべてを再度実行する必要はありません。DDL ステートメントを実行するときに、DM 移行のステータスを確認します。エラーが報告された場合は、この DDL ステートメントのバッチによってデータの不整合が発生するかどうかを判断する必要があります。
楽観的モードでは、アップストリームで実行された DDL ステートメントのほとんどが、追加の作業を必要とせずにダウンストリームに自動的に移行されます。これらの DDL ステートメントは、「タイプ 1 DDL」と呼ばれます。
列名、列タイプ、または列のデフォルト値を変更する DDL ステートメントは、「タイプ 2 DDL」と呼ばれます。アップストリームでタイプ 2 DDL ステートメントを実行する場合は、すべてのシャード テーブルで DDL ステートメントを同じ順序で実行するようにしてください。
タイプ 2 DDL ステートメントの例をいくつか示します。
- 列のタイプを変更します: 
ALTER TABLE table_name MODIFY COLUMN column_name VARCHAR(20)。 - 列の名前を変更します: 
ALTER TABLE table_name RENAME COLUMN column_1 TO column_2;. - デフォルト値のない
NOT NULL列を追加します:ALTER TABLE table_name ADD COLUMN column_1 NOT NULL;。 - インデックスの名前を変更します: 
ALTER TABLE table_name RENAME INDEX index_1 TO index_2;。 
シャード テーブルが上記の DDL ステートメントを実行する場合、 strict-optimistic-shard-mode: trueが設定されている場合はタスクが直接中断され、エラーが報告されます。3 strict-optimistic-shard-mode: false設定されているか指定されていない場合は、シャード テーブル内の DDL ステートメントの実行順序が異なるため、移行が中断されます。例:
- シャード 1 は列の名前を変更し、列の種類を変更します。
- 列の名前を変更します: 
ALTER TABLE table_name RENAME COLUMN column_1 TO column_2;. - 列のタイプを変更します: 
ALTER TABLE table_name MODIFY COLUMN column_3 VARCHAR(20);。 
 - 列の名前を変更します: 
 - シャード 2 は列の種類を変更し、列の名前を変更します。
- 列の種類を変更します: 
ALTER TABLE table_name MODIFY COLUMN column_3 VARCHAR(20)。 - 列の名前を変更します: 
ALTER TABLE table_name RENAME COLUMN column_1 TO column_2;. 
 - 列の種類を変更します: 
 
さらに、楽観的モードと悲観的モードの両方に次の制限が適用されます。
DROP TABLEまたはDROP DATABASEサポートされていません。TRUNCATE TABLEはサポートされていません。- 各 DDL ステートメントには、1 つのテーブルに対する操作のみが含まれる必要があります。
 - TiDB でサポートされていない DDL ステートメントは、DM でもサポートされていません。
 - 新しく追加された列のデフォルト値には、 
current_timestamp、rand()、uuid()を含めることはできません。そうしないと、上流と下流の間でデータの不整合が発生する可能性があります。 
リスク
移行タスクに楽観的モードを使用すると、DDL ステートメントはすぐにダウンストリームに移行されます。このモードを誤って使用すると、アップストリームとダウンストリームの間でデータの不整合が発生する可能性があります。
データの不整合を引き起こす操作
各シャード テーブルのスキーマは相互に互換性がありません。例:
- 同じ名前の 2 つの列がそれぞれ 2 つのシャード テーブルに追加されていますが、列のタイプは異なります。
 - 同じ名前の 2 つの列がそれぞれ 2 つのシャード テーブルに追加されていますが、列のデフォルト値は異なります。
 - 同じ名前の 2 つの生成された列がそれぞれ 2 つのシャード テーブルに追加されますが、列は異なる式を使用して生成されます。
 - 同じ名前の 2 つのインデックスが 2 つのシャード テーブルにそれぞれ追加されますが、キーは異なります。
 - 同じ名前を持つ他の異なるテーブル スキーマ。
 
シャード テーブル内のデータを破損する可能性のある DDL ステートメントを実行し、ロールバックを試みます。
たとえば、列
Xを削除してから、この列を再度追加します。
例
次の 3 つのシャード テーブルをマージして TiDB に移行します。

tbl01に新しい列Ageを追加し、列のデフォルト値を0に設定します。
ALTER TABLE `tbl01` ADD COLUMN `Age` INT DEFAULT 0;

tbl00に新しい列Ageを追加し、列のデフォルト値を-1に設定します。
ALTER TABLE `tbl00` ADD COLUMN `Age` INT DEFAULT -1;

そうなると、 DEFAULT 0とDEFAULT -1互いに互換性がないため、 tbl00のAge列目は不整合になります。この状況では、DM はエラーを報告しますが、データの不整合を手動で修正する必要があります。
実施原則
楽観的モードでは、DM ワーカーはアップストリームから DDL ステートメントを受け取った後、更新されたテーブル スキーマを DM マスターに転送します。DM ワーカーは各シャード テーブルの現在のスキーマを追跡し、DM マスターはこれらのスキーマを、すべてのシャード テーブルの DML ステートメントと互換性のある複合スキーマにマージします。次に、DM マスターは対応する DDL ステートメントをダウンストリームに移行します。DML ステートメントはダウンストリームに直接移行されます。

例
アップストリーム MySQL に 3 つのシャード テーブル ( tbl00 、 tbl01 、 tbl02 ) があるとします。これらのシャード テーブルをダウンストリーム TiDB のtblテーブルにマージして移行します。次の図を参照してください。

アップストリームにLevel列を追加します。
ALTER TABLE `tbl00` ADD COLUMN `Level` INT;

次に、TiDB はtbl00 (列Levelを含む) からの DML ステートメントと、 tbl01およびtbl02テーブル (列Levelを含まない) からの DML ステートメントを受け取ります。

次の DML ステートメントは、変更せずにダウンストリームに移行できます。
UPDATE `tbl00` SET `Level` = 9 WHERE `ID` = 1;
INSERT INTO `tbl02` (`ID`, `Name`) VALUES (27, 'Tony');

tbl01にLevel列を追加します。
ALTER TABLE `tbl01` ADD COLUMN `Level` INT;

この時点で、ダウンストリームにはすでに同じLevel列があるため、DM マスターはテーブル スキーマを比較した後、何も操作を実行しません。
tbl01にName列をドロップします。
ALTER TABLE `tbl01` DROP COLUMN `Name`;

その後、ダウンストリームはName列を含むtbl00とtbl02からの DML ステートメントを受信するため、この列はすぐには削除されません。
同様に、すべての DML ステートメントをダウンストリームに移行できます。
INSERT INTO `tbl01` (`ID`, `Level`) VALUES (15, 7);
UPDATE `tbl00` SET `Level` = 5 WHERE `ID` = 5;

tbl02にLevel列を追加します。
ALTER TABLE `tbl02` ADD COLUMN `Level` INT;

その時までに、すべてのシャード テーブルにLevel列が存在します。
それぞれtbl00とtbl02のName列目を削除します。
ALTER TABLE `tbl00` DROP COLUMN `Name`;
ALTER TABLE `tbl02` DROP COLUMN `Name`;

その時までに、 Name列はすべてのシャード テーブルから削除され、ダウンストリームで安全に削除できます。
ALTER TABLE `tbl` DROP COLUMN `Name`;
