AWS DMS タスクが失敗し、エラーメッセージ "ERROR: canceling statement due to statement timeout" が表示される場合のトラブルシューティング方法を教えてください。
AWS Database Migration Service (AWS DMS) を使用し、オンプレミス PostgreSQL データベースをソースまたは宛先とするデータ移行を行っています。AWS DMS タスクは、しばらく正常に実行された後、エラーが発生して失敗します。エラーのトラブルシューティングと解決方法を教えてください。
簡単な説明
PostgreSQL データベースが移行タスクのソースである場合、AWS DMS はフルロードフェーズ中にテーブルからデータを取得します。次に、AWS DMS は変更データキャプチャ (CDC) フェーズ中、レプリケーションスロットに保持された先行書き込みログ (WAL) から読み取ります。
PostgreSQL データベースがターゲットの場合は、AWS DMS はソースからデータを取得し、レプリケーションインスタンスに CSV ファイルを作成します。次に、AWS DMSは COPY コマンドを実行し、そのレコードをフルロードフェーズ中にターゲットに挿入します。
ただし CDC フェーズ中、トランザクション適用モードでは、AWS DMS はソースの WAL ログから厳密に同一の DML ステートメントを実行します。バッチ適用モードでは、AWS DMS は CDC フェーズ中に CSV ファイルも作成します。次に DMS は COPY コマンドを実行し、正味変更をターゲットに挿入します。
AWS DMS がソースからのデータ取得またはターゲットへのデータ配置を試行する際は、デフォルトのタイムアウト設定である 60 秒が適用されます。ソースまたはターゲットの負荷が高いか、テーブルにロックが発生している場合、AWS DMS はコマンドの実行を 60 秒以内に完了できません。結果的にタスクは失敗し、"canceling statement due to statement timeout," というエラーメッセージが表示されます。また、ログには次のいずれかのエントリが表示されます。
Messages:
"]E: RetCode: SQL_ERROR SqlState: 57014 NativeError: 1 Message: ERROR: canceling statement due to statement timeout; Error while executing the query [1022502] (ar_odbc_stmt.c:2738)" (ステートメントのタイムアウト)
"]E: test_decoding_create_replication_slot(...) - Unable to create slot 'lrcyli7hfxcwkair_00016402_8917165c_29f0_4070_97dd_26e78336e01b' (on execute(...) phase) [1022506] (postgres_test_decoding.c:392))" (スロットの作成失敗)
エラーをトラブルシューティングして解決するには、次の手順を実行します。
- コマンド実行時間が長くなる原因を特定します。
- タイムアウト値を増やし、スロット作成のタイムアウト値を確認します。
- スロット作成に関する問題をトラブルシューティングします。
解決策
コマンド実行時間が長くなる原因を特定する
タイムアウト期間中に実行できなかったコマンドを特定するには、AWS DMS タスクログ、およびそのタスクのテーブル統計情報セクションを確認します。パラメータ log_min_error_statement の深刻度が ERROR 以下である場合は、この情報は PostgreSQL のエラーログファイルにも表示されます。実行できなかったコマンドを特定した後、障害が発生したテーブル名を特定します。PostgreSQL エラーログのエラーメッセージ例を次に示します。
ERROR: canceling statement due to statement timeout STATEMENT: <The statement executed>"
関連するテーブルでのロックを特定するには、ソースまたはターゲットで次のコマンドを実行します (エラーの発生場所に応じて)。
SELECT blocked_locks.pid AS blocked_pid, blocked_activity.usename AS blocked_user, blocking_locks.pid AS blocking_pid, blocking_activity.usename AS blocking_user, blocked_activity.query AS blocked_statement, blocking_activity.query AS current_statement_in_blocking_process FROM pg_catalog.pg_locks blocked_locks JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid JOIN pg_catalog.pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid AND blocking_locks.pid != blocked_locks.pid JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid WHERE NOT blocked_locks.GRANTED;
ブロックされている PID が存在する場合は、次のコマンドを実行し、ブロックされた PID を停止するか完全終了します。
SELECT pg_terminate_backend(blocking_pid);
デッドロー (別称「タプル」) が原因で SELECT の所要時間が増加する可能性があるため、次のコマンドを実行し、ソーステーブルに大量のデッドローが存在しないか確認します。
select * from pg_stat_user_tables where relname= 'table_name';
障害が発生したターゲットテーブルにプライマリキーまたは一意のインデックスが存在するかどうかを確認します。テーブルにプライマリキーも一意のインデックスも存在しない場合は、UPDATE ステートメントの実行中にテーブル全体のスキャンが実行されます。このテーブルスキャンは、長時間を要する可能性があります。
タイムアウト値を増やす
AWS DMS は、ソースエンドポイント、ターゲットエンドポイントの両方で追加接続属性である executeTimeout を使用します。executeTimeout のデフォルト値は 60 秒であり、クエリの実行時間が 60 秒を上回った場合 AWS DMS はタイムアウトを発生させます。
エラーが Source_Unload または Source_Capture で発生する場合は、ソースで executeTimeout のタイムアウト値を設定します。エラーが Target_Load または Target_Apply で発生する場合は、ターゲットで executeTimeout のタイムアウト値を設定します。タイムアウト値を増やすには、次の手順を実行します。
1. AWS DMS コンソールを開きます。
2.ナビゲーションペインで [エンドポイント] を選択します。
3.PostgreSQL エンドポイントを選択します。
4.[アクション] を選択し、[変更] を選択します。
5.[エンドポイント固有の設定] セクションを展開します。
6.[追加の接続属性] フィールドに次の値を入力します。
executeTimeout=3600;
7.[保存] を選択します。
8.[エンドポイント] ペインで目的の PostgreSQL 名を選択します。
9.[接続] セクション内では、エンドポイントの [ステータス] が Testing から Successful に変化します。
PostgreSQL DB インスタンスの statement_timeout パラメータは、ミリ秒単位で増やすことができます。デフォルト値である 0 では、すべてのクエリに対し、タイムアウトは無効です。lock_timeout パラメータを増やすこともできます。デフォルト値である 0 では、ロックに対するタイムアウトは無効です。
スロット作成に関する問題のトラブルシューティング
PostgreSQL データベースにレプリケーションスロットを作成する際にタイムアウトが発生した場合は、次の例に類似したログエントリが表示されます。
Messages
"]E: test_decoding_create_replication_slot(...) - Unable to create slot 'lrcyli7hfxcwkair_00016402_8917165c_29f0_4070_97dd_26e78336e01b' (on execute(...) phase) [1022506] (postgres_test_decoding.c:392)"
このタイムアウトを増やすには、[タスク設定] セクションの TransactionConsistencyTimeout パラメータを構成します。デフォルト値は 600 秒です。
データベースユーザーテーブルにアクティブなロックが存在する場合、PostgreSQL はレプリケーションスロットを作成できません。ロックが発生していないか確認するには、次のコマンドを実行します。
select * from pg_locks;
次に、エラーが解決されたかどうかをテストするために、次のコマンドを実行し、ソース側の PostgreSQL データベースにレプリケーションスロットを手動で作成します。
select xlog_position FROM pg_create_logical_replication_slot('<Slot name as per the task log>', 'test_decoding');
このコマンドでもスロットを作成できない場合は、ボトルネックを特定し、データベースを構成するために PostgreSQL DBA と連携する必要が生じる可能性があります。コマンドを正常に実行できた場合は、テスト用に作成したスロットを削除します。
select pg_drop_replication_slot(‘<slot name>');
最後の手順として、移行タスクを再開します。
関連情報
クライアント接続のデフォルト設定に関する PostgreSQL ドキュメント
PostgreSQL を AWS DMS のターゲットとして使用する場合の追加の接続属性
- 言語
- 日本語

関連するコンテンツ
質問済み 1年前
