[PostgreSQL] 락 트랜잭션 경합

반응형
PostgreSQL 락 트랜잭션 경합

PostgreSQL 락 / 트랜잭션 경합으로 인한 지연·실패

유형: 일반오류형 · 성능 저하 → 장애로 확장되기 쉬운 고위험 유형

1️⃣ 장애 개요

PostgreSQL은 MVCC 구조를 사용하지만, UPDATE / DELETE / DDL이 수행될 때는 여전히 다양한 수준의 락(Lock)이 사용됩니다.
여러 트랜잭션이 동일한 자원(row, table, index)을 동시에 요구하면 대기 → 지연 → 타임아웃 또는 데드락으로 이어질 수 있습니다.

2️⃣ 대표 오류 메시지

ERROR: deadlock detected
ERROR: canceling statement due to lock timeout
ERROR: canceling statement due to statement timeout

3️⃣ 사용자 입장에서 보이는 증상

  • 특정 화면이나 기능이 계속 로딩 상태
  • 동일 기능인데 어떤 사용자는 성공, 어떤 사용자는 실패
  • 재시도하면 성공하거나, 특정 타이밍에만 오류 발생
  • 전체 서비스는 살아 있지만 체감 성능 급격히 저하
현장 특징
- “가끔 느리다”가 점점 “자주 실패한다”로 발전
- 피크타임 또는 배치 실행 시간대에 집중 발생
- 단일 쿼리가 아니라 연쇄적으로 여러 기능에 영향

4️⃣ 운영 환경에서 자주 터지는 원인

  • UPDATE / DELETE 경쟁
    동일 row 또는 동일 범위를 동시에 수정
  • DDL과 DML 충돌
    ALTER TABLE, CREATE INDEX가 서비스 트래픽과 겹침
  • 긴 트랜잭션
    COMMIT 되지 않은 채 락을 오래 점유
  • idle in transaction
    작업은 끝났지만 트랜잭션 상태로 방치
  • 인덱스 미흡
    풀스캔으로 처리 시간이 길어져 락 유지 시간 증가

5️⃣ 운영 대응 포인트 (가장 중요한 관점)

핵심 질문
“누가 락을 잡고 있고, 누가 기다리고 있는가?”
락 문제는 반드시 “가해자 세션”과 “피해자 세션”이 존재합니다.

단순히 느린 쿼리를 찾는 것이 아니라, 트랜잭션 단위로 락 보유 관계를 파악해야 합니다.

6️⃣ 단기 대응 전략

즉시 조치(운영 중 장애 대응)
- 장기 트랜잭션 및 idle in transaction 세션 정리
- 서비스 영향 없는 배치/관리 작업 일시 중단
- 데드락 반복 쿼리의 실행 순서 조정

주의: 무작정 세션을 종료하면 롤백 비용 증가 및 추가 락 경합을 유발할 수 있으므로, 반드시 트랜잭션 상태 확인 후 조치해야 합니다.

7️⃣ 중·장기 대응 전략

구조 개선 방향
- 트랜잭션 범위 축소(짧게 가져가기)
- 자주 경합되는 컬럼/조건에 인덱스 보강
- UPDATE 순서 통일(항상 동일한 키 순서)
- DDL 작업은 별도 점검 시간대에 수행

특히 “한 트랜잭션에서 너무 많은 일을 처리”하는 구조는 락 문제의 가장 흔한 근본 원인입니다.
트랜잭션을 작고 빠르게 쪼개는 것만으로도 체감 성능과 안정성이 크게 개선됩니다.

8️⃣ 기본 오류 대응 4단계

1) 증상 구분: 지연 vs 타임아웃 vs 데드락
2) 현황 파악: 락 보유 세션과 대기 세션 식별
3) 원인 분석: 장기 트랜잭션, 인덱스, DDL 충돌 여부 확인
4) 구조 개선: 쿼리/인덱스 튜닝 + 트랜잭션 설계 개선

락/트랜잭션 경합은 “언젠가 터지는 문제”가 아니라 “이미 터지고 있는데 눈에 안 보이는 문제”인 경우가 많습니다.
조기 진단과 구조 개선이 가장 큰 예방책입니다.

반응형