"ERROR: canceling statement due to statement timeout" 오류 메시지를 수신하는 실패한 AWS DMS 작업의 문제를 해결하려면 어떻게 해야 합니까?

최종 업데이트 날짜: 2019년 9월 30일

AWS Database Migration Service(AWS DMS)를 사용하여 온프레미스 PostgreSQL 데이터베이스와 데이터를 마이그레이션하고 있습니다. AWS DMS 작업은 정상적으로 한동안 실행된 후 오류가 발생하면서 작업이 실패합니다. 이 오류를 해결하려면 어떻게 해야 합니까?

간략한 설명

PostgreSQL 데이터베이스가 마이그레이션 작업의 원본인 경우, AWS DMS는 전체 로드 단계 중에 테이블에서 데이터를 가져옵니다. 그런 다음 AWS DMS는 변경 데이터 캡처(CDC) 단계 중에 복제 슬롯이 보관하는 미리 쓰기 로그(WALs)에서 읽습니다.

PostgreSQL 데이터베이스가 마이그레이션 작업의 대상인 경우 AWS DMS는 원본에서 데이터를 가져와 복제 인스턴스에 CSV 파일을 생성합니다. 그런 다음 AWS DMS는 COPY 명령을 실행하여 전체 로드 단계 중에 해당 레코드를 대상에 삽입합니다. 하지만 CDC 단계 중에 AWS DMS는 트랜잭션 적용 모드에서 소스 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_Apple에 오류가 표시되는 경우 대상의 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>');

마지막으로 마이그레이션 작업을 다시 시작합니다.