DMセーフモード
セーフ モードは、DM が増分レプリケーションを実行するための特別な操作モードです。セーフ モードでは、DM 増分レプリケーションコンポーネントがbinlogイベントをレプリケートするときに、DM はダウンストリームで実行する前に、すべてのINSERTとUPDATEステートメントを強制的に書き換えます。
セーフ モードでは、1 つのbinlogイベントを、冪等性が保証された状態でダウンストリームに繰り返し複製できます。したがって、増分レプリケーションは安全です。
チェックポイントからデータ レプリケーション タスクを再開した後、DM は一部のbinlogイベントを繰り返しレプリケートすることがあり、次の問題が発生します。
- 増分レプリケーション中、DML を実行する操作とチェックポイントを書き込む操作は同時に行われません。チェックポイントを書き込む操作と下流のデータベースにデータを書き込む操作はアトミックではありません。そのため、 DM が異常終了した場合、チェックポイントには終了ポイントの前の復元ポイントのみが記録される可能性があります。
 - DM がレプリケーション タスクを再開し、チェックポイントから増分レプリケーションを再開すると、チェックポイントと終了ポイント間の一部のデータは異常終了前にすでに処理されている可能性があります。これにより、一部の SQL ステートメントが繰り返し実行されます。
 INSERTステートメントが繰り返し実行されると、主キーまたは一意のインデックスで競合が発生し、レプリケーションが失敗する可能性があります。3UPDATEが繰り返し実行されると、フィルター条件で以前に更新されたレコードを見つけられない可能性があります。
セーフ モードでは、DM は SQL ステートメントを書き換えて、前述の問題を解決できます。
動作原理
セーフ モードでは、DM は SQL ステートメントを書き換えることで、 binlogイベントの冪等性を保証します。具体的には、次の SQL ステートメントが書き換えられます。
INSERTステートメントがREPLACEステートメントに書き換えられます。UPDATEステートメントが分析され、更新された行の主キーまたは一意のインデックスの値を取得します。次に、UPDATEステートメントが次の 2 つの手順でDELETE+REPLACEステートメントに書き換えられます。DM は主キーまたは一意のインデックスを使用して古いレコードを削除し、REPLACEステートメントを使用して新しいレコードを挿入します。
REPLACE 、データを挿入するための MySQL 固有の構文です。 REPLACE使用してデータを挿入し、新しいデータと既存のデータに主キーまたは一意制約の競合がある場合、MySQL は競合するレコードをすべて削除し、挿入操作を実行します。これは、「強制挿入」に相当します。詳細については、MySQL ドキュメントのREPLACEステートメント参照してください。
dummydb.dummytblテーブルに主キーidがあると仮定します。このテーブルに対して次の SQL ステートメントを繰り返し実行します。
INSERT INTO dummydb.dummytbl (id, int_value, str_value) VALUES (123, 999, 'abc');
UPDATE dummydb.dummytbl SET int_value = 888999 WHERE int_value = 999;   -- Suppose there is no other record with int_value = 999
UPDATE dummydb.dummytbl SET id = 999 WHERE id = 888;    -- Update the primary key
セーフ モードを有効にすると、前述の SQL ステートメントがダウンストリームで再度実行されると、次のように書き換えられます。
REPLACE INTO dummydb.dummytbl (id, int_value, str_value) VALUES (123, 999, 'abc');
DELETE FROM dummydb.dummytbl WHERE id = 123;
REPLACE INTO dummydb.dummytbl (id, int_value, str_value) VALUES (123, 888999, 'abc');
DELETE FROM dummydb.dummytbl WHERE id = 888;
REPLACE INTO dummydb.dummytbl (id, int_value, str_value) VALUES (999, 888888, 'abc888');
前のステートメントでは、 UPDATE DELETE + INSERTではなくDELETE + REPLACEに書き換えられます。ここでINSERTを使用すると、 id = 999の重複レコードを挿入すると、データベースは主キーの競合を報告します。これが、代わりにREPLACE使用される理由です。新しいレコードが既存のレコードを置き換えます。
SQL ステートメントを書き換えることにより、DM は重複した挿入または更新操作を実行するときに、新しい行データを使用して既存の行データを上書きします。これにより、挿入および更新操作が繰り返し実行されることが保証されます。
セーフモードを有効にする
セーフ モードは自動または手動で有効にできます。このセクションでは詳細な手順について説明します。
自動的に有効にする
DM がチェックポイントから増分レプリケーション タスクを再開すると (たとえば、DM ワーカーの再起動やネットワークの再接続)、DM は一定期間 (デフォルトでは 60 秒) セーフ モードを自動的に有効にします。
セーフ モードを有効にするかどうかは、チェックポイントのsafemode_exit_pointに関係します。増分レプリケーション タスクが異常に一時停止すると、DM はメモリ内のすべての DML ステートメントをダウンストリームにレプリケートしようとし、DML ステートメントの中で最新のbinlog位置をsafemode_exit_pointとして記録し、最後のチェックポイントに保存します。
詳細なロジックは次のとおりです。
チェックポイントに
safemode_exit_point含まれている場合、増分レプリケーション タスクは異常に一時停止しています。 DM がタスクを再開すると、再開するチェックポイントのbinlog位置 (開始位置) はsafemode_exit_pointより前になります。これは、開始位置とsafemode_exit_point間のbinlogイベントがダウンストリームで処理された可能性があることを示します。 そのため、再開プロセス中に、一部のbinlogイベントが繰り返し実行される可能性があります。 したがって、セーフ モードを有効にすると、これらのbinlog位置を安全にすることができます。 バイナリbinlog位置がsafemode_exit_pointを超えると、セーフ モードを手動で有効にしない限り、DM は自動的にセーフ モードを無効にします。チェックポイントに
safemode_exit_point含まれていない場合、次の 2 つのケースが考えられます。- これは新しいタスクです。または、このタスクは予想どおり一時停止されています。
 - このタスクは異常に一時停止されていますが、DM は
safemode_exit_point記録できないか、DM プロセスが異常終了します。 
2 番目のケースでは、DM はチェックポイント後のどのbinlogイベントがダウンストリームで実行されるかを認識しません。繰り返し実行されるbinlogイベントによって問題が発生しないようにするために、DM は最初の 2 つのチェックポイント間隔中にセーフ モードを自動的に有効にします。2 つのチェックポイント間のデフォルトの間隔は 30 秒です。つまり、通常の増分レプリケーション タスクが開始されると、最初の 60 秒間 (2 * 30 秒) はセーフ モードが強制されます。
通常、増分レプリケーション タスクの開始時にセーフ モード期間を調整するためにチェックポイント間隔を変更することは推奨されません。ただし、変更が必要な場合は、syncer 構成の項目セーフモードを手動で有効にする (推奨) または
checkpoint-flush-intervalを変更できます。
手動で有効にする
Syncer 構成のsafe-mode項目を設定すると、レプリケーション プロセス全体でセーフ モードを有効にすることができます。 safe-modeは bool 型のパラメーターで、デフォルトはfalseです。 trueに設定すると、DM は増分レプリケーション プロセス全体でセーフ モードを有効にします。
以下は、セーフ モードを有効にしたタスク構成の例です。
syncers:                              # The running configurations of the sync processing unit.
  global:                            # Configuration name.
    # Other configuration items are not provided in this example.
    safe-mode: true                  # Enables safe mode for the whole incremental replication process.
    # Other configuration items are not provided in this example.
# ----------- Instance configuration -----------
mysql-instances:
  -
    source-id: "mysql-replica-01"
    # Other configuration items are not provided in this example.
    syncer-config-name: "global"            # Name of the syncers configuration.
セーフモードに関する注意事項
安全上の理由から、レプリケーション プロセス全体でセーフ モードを有効にする場合は、次の点に注意してください。
- セーフ モードでの増分レプリケーションでは、余分なオーバーヘッドが発生します。2 + 
DELETEREPLACE操作を頻繁に実行すると、主キーまたは一意のインデックスが頻繁に変更されるため、UPDATEステートメントのみを実行する場合よりもパフォーマンスのオーバーヘッドが大きくなります。 - セーフ モードでは、同じ主キーを持つレコードが強制的に置き換えられるため、ダウンストリームでデータが失われる可能性があります。アップストリームからダウンストリームにシャードをマージして移行する場合、構成が間違っていると、多数の主キーまたは一意のキーの競合が発生する可能性があります。このような状況でセーフ モードを有効にすると、ダウンストリームで例外が表示されずに大量のデータが失われ、深刻なデータの不整合が発生する可能性があります。
 - セーフ モードでは、競合を検出するために主キーまたは一意のインデックスに依存します。ダウンストリーム テーブルに主キーまたは一意のインデックスがない場合、DM は
REPLACE使用してレコードを置き換えたり挿入したりすることはできません。この場合、セーフ モードが有効になっていて、DM がINSERT~REPLACEステートメントを書き換えても、重複したレコードがダウンストリームに挿入されます。 
要約すると、アップストリーム データベースに重複する主キーを持つデータがあり、アプリケーションが重複レコードの損失とパフォーマンスのオーバーヘッドを許容する場合は、セーフ モードを有効にしてデータの重複を無視できます。