Amazon Relational Database Service(RDS) for PostgreSQL 인스턴스에 대한 읽기 복제본을 설정했습니다. 읽기 전용 복제본을 쿼리할 때 "복구와 충돌하여 문을 취소하는 중“ 오류가 발생합니다.
간략한 설명
이 오류는 읽기 전용 복제본에서 발생하는 활동에 대한 기본 인스턴스의 가시성이 부족하기 때문에 발생할 수 있습니다. 복구와의 충돌은 WAL 정보를 읽기 전용 복제본에 적용할 수 없을 때 발생합니다. 변경 사항이 읽기 전용 복제본에서 발생하는 활동을 방해할 수 있기 때문입니다.
예를 들어 장기 실행 SELECT 문이 기본 인스턴스에서 삭제된 테이블의 읽기 전용 복제본에서 실행 중일 때 기본 인스턴스에서 DROP 문을 실행한다고 가정해 보겠습니다. 그러면 읽기 전용 복제본에는 두 가지 옵션이 존재합니다.
- WAL 레코드를 적용하기에 앞서, SELECT 문이 완료될 때까지 기다립니다. 이러한 경우 복제 지연이 증가합니다.
- WAL 레코드를 적용한 다음 SELECT 문을 취소합니다. 이 경우에는 "복구와 충돌하여 문을 취소하는 중“ 오류가 발생합니다.
읽기 전용 복제본은 max_standby_streaming_delay 및 max_standby_archive_delay 파라미터의 값에 따라 이러한 복제 충돌을 해결합니다. max_standby_streaming_delay 파라미터는 적용하려는 WAL 항목과 충돌하는 대기 쿼리를 취소하기 전에 읽기 전용 복제본이 기다려야 하는 시간을 결정합니다. 충돌하는 문이 이 기간 이후에도 계속 실행 중이면, PostgreSQL은 문을 취소하고 다음 오류 메시지를 표시합니다.
ERROR: canceling statement due to conflict with recovery
이 오류는 일반적으로 읽기 전용 복제본에서 오래 실행되는 쿼리로 인해 발생합니다.
앞의 DROP 문 예제에서 DROP 요청은 WAL 파일에 저장되어 나중에 일관성을 위해 읽기 전용 복제본에 적용합니다. max_standby_streaming_delay의 값보다 큰 런타임으로 삭제된 개체에서 데이터를 검색하려고 하는 읽기 복제본에서 SELECT 문이 이미 실행 중이라고 가정합니다. 그런 다음 SELECT 문이 취소되어 DROP 문을 적용할 수 있습니다.
세션 1 (읽기 전용 복제본) SELECT 문을 example_table에서 실행:
postgres=> SELECT * from example_table;
세션 2 (프라이머리) DROP 문을 example_table에서 실행:
postgres=> DROP TABLE example_table;
그러면 다음 오류가 발생합니다.
postgres@postgres:[27544]:ERROR: canceling statement due to conflict with recovery
postgres@postgres:[27544]:DETAIL: User was holding a relation lock for too long.
postgres@postgres:[27544]:STATEMENT: select * from example_table;
또한 읽기 전용 복제본의 트랜잭션이 기본 인스턴스에서 삭제하도록 설정한 튜플을 읽을 때 쿼리 충돌이 발생할 수 있습니다. 튜플을 삭제한 다음 기본 인스턴스에서 진공 처리하면 복제본에서 여전히 실행 중인 SELECT 쿼리와 충돌이 발생합니다. 이 경우 복제본에 대한 SELECT 쿼리가 종료되고 다음 오류 메시지가 표시됩니다.
ERROR: canceling statement due to conflict with recovery
DETAIL: User query might have needed to see row versions that must be removed.
해결 방법
읽기 전용 복제본에서 충돌이 발생하고 오류 로그에 "복구 충돌로 인해 문을 취소하는 중" 오류가 표시되면, 오류 메시지를 기반으로 특정 사용자 지정 파라미터를 설정하여 충돌의 영향을 줄일 수 있습니다. 사용자 지정 파라미터는 읽기 전용 복제본에서 설정해야 합니다.
"복구 충돌로 인해 문을 취소하는 중" 및 "DETAIL: 사용자가 너무 오랫동안 관계 잠금을 유지했습니다." 오류 메시지가 나타납니다.
max_standby_streaming_delay/max_standby_archive_delay: 이 파라미터를 사용하여 곧 적용될 WAL 항목과 충돌하는 스탠바이 명령문을 취소하기 전에 더 많은 시간을 허용할 수 있습니다. 이 값은 프라이머리 인스턴스로부터 데이터를 수신한 후 WAL 데이터를 적용하는 데 허용되는 총 시간을 나타냅니다. 이러한 파라미터는 WAL 데이터를 읽는 위치에 따라 지정됩니다. 스트리밍 복제에서 WAL 데이터를 읽는 경우 max_standby_streaming_delay 파라미터를 사용하십시오. Amazon Simple Storage Service(S3)의 아카이브 위치에서 WAL 데이터를 읽는 경우 max_standby_archive_delay 파라미터를 사용합니다.
이러한 파라미터를 설정할 때는 다음 사항에 유의하십시오.
- 이러한 파라미터의 값을 -1로 설정하면 복제본 인스턴스가 계속해서 충돌 중인 쿼리가 완료될 때까지 대기할 수 있으므로 복제 지연이 증가합니다.
- 이 파라미터의 값을 0으로 설정하면 충돌 중인 쿼리가 취소되고, WAL 항목이 복제본 인스턴스에 적용됩니다.
- 이러한 파라미터의 기본값은 30초로 설정되어 있습니다.
- 이러한 파라미터를 설정할 때 단위를 지정하지 않으면 밀리초가 단위로 간주됩니다.
이러한 파라미터의 값을 조정해, 사용 사례에 따라 쿼리 취소 또는 복제 지연의 균형을 맞춥니다.
참고: max_standby_archive_delay를 늘려 WAL 아카이브 항목 읽기와 충돌하는 쿼리를 취소하지 않도록 한 다음, max_standby_streaming_delay 또한 늘려서 스트리밍 WAL 항목과 충돌하는 취소가 발생하지 않도록 하는 방법을 고려합니다.
"DETAIL: 사용자 쿼리에서 제거해야 하는 행 버전을 확인해야 할 수 있음"과 함께 "복구와 충돌하여 문을 취소하는 중" 오류가 표시됩니다.
hot_standby_feedback: 이 파라미터를 활성화하면 가장 오래된 활성 트랜잭션 정보와 함께 읽기 전용 복제본에서 기본 인스턴스로 피드백 메시지가 전송됩니다. 따라서 프라이머리 인스턴스는 트랜잭션에 필요할 수 있는 레코드를 제거하지 않습니다.
읽기 전용 복제본에서 이 파라미터를 활성화하면, 읽기 전용 복제본에서 장기 실행 쿼리로 인해 프라이머리 인스턴스에서 테이블이 부풀려질 수 있습니다. 이는 진공 작업이 읽기 복제본에서 실행되는 쿼리에 필요할 수 있는 데드 튜플을 제거하지 않기 때문입니다. 이 파라미터는 기본적으로 작동하지 않습니다. 따라서 이 파라미터를 활성화할 때는 주의해야 합니다.
읽기 전용 복제본의 pg_stat_database_conflicts 뷰에서 읽기 전용 복제본의 복구 충돌로 인해 취소된 문에 대한 통계를 확인할 수도 있습니다.