オプティミスティックモードでシャードテーブルからデータをマージおよび移行する
このドキュメントでは、オプティミスティックモードのデータ移行(DM)によって提供されるシャーディングサポート機能を紹介します。この機能を使用すると、アップストリームのMySQLまたはMariaDBインスタンスにある同じまたは異なるテーブルスキーマを持つテーブルのデータを、ダウンストリームのTiDBにある1つの同じテーブルにマージして移行できます。
ノート:
オプティミスティックモードとその制限について詳しく理解していない場合は、このモードを使用することはお勧めしません。そうしないと、移行の中断やデータの不整合が発生する可能性があります。
バックグラウンド
DMは、シャーディングDDLと呼ばれるシャーディングテーブルでのオンラインでのDDLステートメントの実行をサポートし、デフォルトで「ペシミスティックモード」を使用します。このモードでは、アップストリームのシャードテーブルでDDLステートメントが実行されると、他のすべてのシャードテーブルで同じDDLステートメントが実行されるまで、このテーブルのデータ移行が一時停止されます。その時までに、このDDLステートメントがダウンストリームで実行され、データ移行が再開されます。
ペシミスティックモードは、ダウンストリームに移行されたデータが常に正しいことを保証しますが、データ移行を一時停止します。これは、アップストリームでA/Bを変更するのに適していません。場合によっては、ユーザーは単一のシャードテーブルでDDLステートメントを実行するのに長い時間を費やし、検証期間の後にのみ他のシャードテーブルのスキーマを変更することがあります。ペシミスティックモードでは、これらのDDLステートメントはデータ移行をブロックし、多くのbinlogイベントを積み上げます。
したがって、「楽観的なモード」が必要です。このモードでは、シャードテーブルで実行されたDDLステートメントは、他のシャードテーブルと互換性のあるステートメントに自動的に変換され、すぐにダウンストリームに移行されます。このように、DDLステートメントはシャードテーブルによるDML移行の実行をブロックしません。
楽観的なモードのConfiguration / コンフィグレーション
オプティミスティックモードを使用するには、タスク構成ファイルのshard-mode
項目をoptimistic
として指定します。詳細なサンプル構成ファイルについては、 DM高度なタスクConfiguration / コンフィグレーションファイルを参照してください。
制限
楽観的なモードを使用するには、いくつかのリスクが伴います。使用するときは、次のルールに従ってください。
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ステートメントのバッチがデータの不整合を引き起こすかどうかを判断する必要があります。
現在、次のステートメントはオプティミスティックモードではサポートされていません。
ALTER TABLE table_name ADD COLUMN column_name datatype NOT NULL
(デフォルト値なしでNOT NULL
列を追加します)。ALTER TABLE table_name ADD COLUMN column_name datetime DEFAULT NOW()
(値が変化する列を追加するため)。ALTER TABLE table_name ADD COLUMN col1 INT, DROP COLUMN col2
(1つのDDLステートメントにADD COLUMN
とDROP COLUMN
の両方が含まれます)。ALTER TABLE table_name RENAME COLUMN column_1 TO column_2;
(列の名前を変更します)。ALTER TABLE table_name RENAME INDEX index_1 TO index_2;
(インデックスの名前を変更します)。
さらに、次の制限が楽観的モードと悲観的モードの両方に適用されます。
- インクリメンタルレプリケーションタスクでは、タスクの開始時のbinlog位置に対応する各シャーディングテーブルのスキーマが互いに整合していることを確認してください。
- シャーディンググループに追加された新しいテーブルには、他のメンバーのテーブルスキーマと一貫性のあるテーブルスキーマが必要です。 DDLステートメントのバッチが実行されている場合、
CREATE/RENAME TABLE
ステートメントは禁止されています。 DROP TABLE
またはDROP DATABASE
はサポートされていません。TRUNCATE TABLE
はサポートされていません。- 各DDLステートメントには、1つのテーブルのみに対する操作が含まれている必要があります。
- TiDBでサポートされていないDDLステートメントは、DMでもサポートされていません。
- 新しく追加された列のデフォルト
rand()
には、current_timestamp
を含めることはできませ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-workerがアップストリームからDDLステートメントを受信した後、更新されたテーブルスキーマをDM-masterに転送します。 DM-workerは、各シャーディングテーブルの現在のスキーマを追跡し、DM-masterは、これらのスキーマを、すべてのシャードテーブルのDMLステートメントと互換性のある複合スキーマにマージします。次に、DMマスターは対応するDDLステートメントをダウンストリームに移行します。 DMLステートメントは、ダウンストリームに直接移行されます。
例
アップストリームのMySQLにtbl01
tbl00
および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-masterはテーブルスキーマを比較した後に操作を実行しません。
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
列があります。
Name
列をそれぞれtbl00
とtbl02
にドロップします。
ALTER TABLE `tbl00` DROP COLUMN `Name`;
ALTER TABLE `tbl02` DROP COLUMN `Name`;
それまでに、 Name
列はすべてのシャーディングされたテーブルから削除され、ダウンストリームで安全に削除できます。
ALTER TABLE `tbl` DROP COLUMN `Name`;