「ERROR: canceling statement due the statement timeout」というエラーメッセージが表示される AWS DMS タスクのトラブルシューティング方法を教えてください。
最終更新日: 2019 年 9 月 30 日
AWS Database Migration Service (AWS DMS) を使用して、オンプレミスの PostgreSQL データベースとの間でデータを移行しています。AWS DMS タスクはしばらくの間正常に実行されますが、それからエラーで失敗します。このエラーをトラブルシューティングして解決するにはどうすれば良いですか?
簡単な説明
PostgreSQL データベースが移行タスクのソースである場合、AWS DMS は全ロードフェーズでテーブルからデータを取得します。その後、AWS DMS は、変更データキャプチャ (CDC) フェーズで、レプリケーションスロットによって保持されている先書きログ (WAL) から読み込みます。
PostgreSQL データベースが移行タスクのターゲットである場合、AWS DMS はソースからデータを取得し、レプリケーションインスタンスに CSV ファイルを作成します。次に、AWS DMS は全ロードフェーズで COPY コマンドを実行し、それらのレコードをターゲットに挿入します。ただし、トランザクション適用モードでは、AWS DMS は CDC フェーズでソースの WAL ログから正確な DML ステートメントを実行します。バッチ適用モードの場合も、AWS DMS は CDC フェーズで CSV ファイルを作成し、COPY コマンドを実行してターゲットに差分変更を挿入します。
AWS DMS がソースからデータを取得するか、ターゲットにデータを配置するコマンドを実行する際、AWS DMS はデフォルトのタイムアウト設定である 60 秒を使用します。ソースまたはターゲットが高負荷であるか、テーブルにロックがある場合には、AWS DMS は 60 秒以内にこれらのコマンドの実行を終了できません。その結果、タスクは失敗して、「canceling statement due to statement timeout (ステートメントタイムアウトが原因でステートメントをキャンセルする)」というエラーになり、ログに次のいずれかのエントリが表示されます。
メッセージ |
---|
]E: RetCode: SQL_ERROR SqlState: 57014 NativeError: 1 Message: ERROR: canceling statement due to statement timeout; |
これらのエラーをトラブルシューティングして解決するには、以下の手順を実行します。
- コマンドの実行時間が長くなる原因を特定します。
- タイムアウト値を増やし、スロット作成タイムアウト値を確認します。
- スロット作成の問題をトラブルシューティングします。
解決方法
コマンドの実行時間が長くなる原因を特定する
タイムアウト期間中に実行できなかったコマンドを見つけるには、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. ナビゲーションペインから [ Endpoints (エンドポイント)] を選択します。
3. PostgreSQL エンドポイントを選択します。
4. [Actions (アクション)] を選択し、[Modify (変更)] を選択します。
5. [Endpoint-specific settings (エンドポイント特有の設定)] セクションを展開します。
6. [Extra connection attributes (追加の接続属性)] のフィールドに、次の値を入力します。
executeTimeout=3600;
7. [Save] を選択します。
8. [Endpoints (エンドポイント)] ペインで、PostgreSQL エンドポイントの名前を選択します。
9. [Connections (接続)]セクションで、エンドポイントの[Status (ステータス)] が Testing から Successful に変わります。
PostgreSQL DB インスタンスの statement_timeout パラメータを増やします (ミリ秒単位)。デフォルト値は 0 で、クエリのタイムアウトは無効になります。lock_timeout パラメータを増やすこともできます。デフォルト値は 0 で、ロックのタイムアウトは無効になります。
スロット作成の問題のトラブルシューティング
PostgreSQL データベースでレプリケーションスロットを作成したときにタイムアウトが発生した場合は、次のようなログエントリが表示されます。
メッセージ |
---|
]E: wal_slot_create(...) - Unable to create slot 'xxxxxxxxxxxxxxxx_00016391_c4a70947_84c9_4a55_8d54_ff63f2f69a52' (on execute(...) phase) [1020101] (postgres_endpoint_wal_utils.c:3215) |
レプリケーションインスタンスでバージョン 3.1.3 以前が実行されている場合、このコマンドにはデフォルトのタイムアウト設定の 60 秒が適用されます。executeTimeout の値は上書きされます。この問題を解決するには、このコマンドのデフォルトタイムアウトが 600 秒であるバージョン 3.1.4 を使用してください。このタイムアウトは、[Task settings (タスク設定)] セクションの TransactionConsistencyTimeout パラメータを設定することで増やすことができます。
データベースユーザーテーブルにアクティブなロックがある場合、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>');
最後に、移行タスクを再開します。