DB
PostgreSQL 락 대기 때문에 마이그레이션이 멈춘 뒤 statement_timeout을 정한 회고
운영 마이그레이션이 멈춘 원인을 느린 SQL이 아닌 열린 트랜잭션에서 찾고 제한 시간을 정한 회고다.
실행 중이라는 말만 보고 기다렸다
운영 배포에서 인덱스 추가 단계가 오래 걸렸다. CPU 사용률은 높지 않았고 프로세스도 종료되지 않아 쿼리가 느린 줄 알았다. 실제로는 다른 세션이 테이블을 잡고 있어 lock을 기다리는 상태였다.
SELECT pid, state, wait_event_type, wait_event,
now() - query_start AS running_for, query
FROM pg_stat_activity
WHERE datname = current_database()
ORDER BY query_start;
두 종류의 timeout을 구분했다
lock_timeout은 잠금을 기다리는 시간이고 statement_timeout은 문장 전체 실행 시간이다. 둘을 같은 의미로 기록하면 원인을 놓치므로 배포 로그에도 구분해서 남겼다.
SET lock_timeout = '5s';
SET statement_timeout = '10min';
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_events_created_at
ON events (created_at);
처음에는 대기 PID를 무조건 종료하려 했다. 이제는 블로커의 쿼리와 트랜잭션 시작 시각을 먼저 보고, 업무 쿼리라면 담당 작업이 끝난 뒤 재시도한다. CONCURRENTLY처럼 트랜잭션 제약이 있는 명령도 별도 실행한다.
다음 배포 순서
- 트래픽이 낮은 시간과 열린 트랜잭션을 확인한다.
- 마이그레이션 전용 세션에 timeout을 건다.
- 실패하면 블로커를 확인하고 반복 종료하지 않는다.
- 성공 뒤 인덱스 존재 여부와 쿼리 계획을 확인한다.
“오래 걸린다”를 하나의 상태로 기록하지 않는 것이 이번 회고의 결론이다. 실행 중인지 잠금 대기인지부터 나눠 봐야 다음 조치가 안전하다.