DBGuide

데드락 이해와 예방

📖 약 2🏷 트랜잭션

데드락이란?

두 트랜잭션이 서로 상대방이 보유한 락을 기다리며 무한히 대기하는 상황입니다.

트랜잭션 A: users 행 1 락 획득 → orders 행 1 락 대기
트랜잭션 B: orders 행 1 락 획득 → users 행 1 락 대기
→ 데드락!

데드락 발생 예제

-- 세션 A
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;  -- 1번 락
-- 잠시 대기...
UPDATE accounts SET balance = balance + 100 WHERE id = 2;  -- 2번 락 대기
COMMIT;

-- 세션 B (동시에 실행)
BEGIN;
UPDATE accounts SET balance = balance - 50 WHERE id = 2;   -- 2번 락
UPDATE accounts SET balance = balance + 50 WHERE id = 1;   -- 1번 락 대기 → 데드락!
COMMIT;

PostgreSQL은 데드락을 자동으로 감지하고 한쪽 트랜잭션을 강제 종료(rollback)합니다.

ERROR: deadlock detected
DETAIL: Process 12345 waits for ShareLock on transaction 67890;
        blocked by process 54321.

예방 전략 1: 일관된 순서로 락 획득

-- 항상 작은 ID부터 락
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = LEAST(1, 2);
UPDATE accounts SET balance = balance + 100 WHERE id = GREATEST(1, 2);
COMMIT;

예방 전략 2: 한 번에 모든 락 획득

BEGIN;
-- SELECT FOR UPDATE로 필요한 행을 한꺼번에 락
SELECT * FROM accounts
WHERE id IN (1, 2)
ORDER BY id  -- 순서 중요!
FOR UPDATE;

UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

예방 전략 3: NOWAIT / SKIP LOCKED

-- 락을 즉시 얻지 못하면 오류 발생 (대기하지 않음)
SELECT * FROM jobs WHERE status = 'pending' LIMIT 1 FOR UPDATE NOWAIT;

-- 락이 걸린 행은 건너뜀 (큐 처리에 유용)
SELECT * FROM jobs WHERE status = 'pending' LIMIT 1 FOR UPDATE SKIP LOCKED;

현재 락 상태 확인

-- 현재 대기 중인 락
SELECT
    pid,
    query,
    wait_event_type,
    wait_event,
    state
FROM pg_stat_activity
WHERE wait_event_type = 'Lock';

-- 락 의존 관계 확인
SELECT
    blocked.pid         AS blocked_pid,
    blocking.pid        AS blocking_pid,
    blocked.query       AS blocked_query,
    blocking.query      AS blocking_query
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking
    ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
WHERE cardinality(pg_blocking_pids(blocked.pid)) > 0;

데드락 타임아웃 설정

-- 트랜잭션 단위로 설정 (밀리초)
SET deadlock_timeout = '1s';  -- 기본값 1초

-- 연결 대기 타임아웃
SET lock_timeout = '5s';      -- 5초 내 락 못 얻으면 오류

댓글

... 으로 작성됩니다

댓글을 불러오는 중...