어떤 개념일까?

데드락이 감지돼도 데이터베이스는 멈추지 않는다. 싸이클에 얽힌 트랜잭션 몇 개만 교착 상태일 뿐이고, DB는 그 중 하나를 골라 강제 롤백(victim)해서 매듭을 끊는다.

싸이클 밖의 트랜잭션들은 처음부터 끝까지 정상적으로 돌아간다.

데드락 처리는 감지 후 희생자 롤백 방식이 표준이라고 한다. 데드락은 둘 이상의 트랜잭션이 서로 쥐고 있는 락을 기다리며 순환 대기 에 빠진 상태이다. DB는 이 사이클을 찾아내서 한쪽을 끊어주는 역할을 한다.


어떤 문제를 해결하려고 나왔을까? 왜 사용 할까?

DB는 동시성과 일관성을 위해서 락을 사용하는데, 트랜잭션마다 락을 잡는 순서가 엇갈리면 순환 대기가 구조적으로 발생할 수 밖에 없습니다.

이론적으로는 데드락을 완전히 예방하려면 트랜잭션이 필요한 모든 락을 미리 알고 한 번에 잡거나 전역 락 순서를 강제해야 하는데, 비현실적이다.

그래서 대부분 DB는 일단 데드락이 생기게 된다면, 한쪽을 롤백해서 복구한다는 유연한 전략을 택한다고 한다.


어떻게 동작하나?

1. 대기 그래프 (wait-for Graph)

대기 그래프 (wait-for Graph)를 통해서 트랜잭션, 간선 별로 T1 → T2 형태도 각 트랜잭션마다 어느 트랜잭션에서 가지고 있는 락을 기다린다는 의미를 부여한다.

해당 그래프를 검사하는 트리거 방식은 DB 마다 다르다고 한다.

능동 감지 (MySQL InnoDB)

락 요청이 대기에 들어갈 때마다 대기 그래프에서 사이클을 검사한다. innodb_deadlock_detect가 기본이다.

타임아웃 트리거 감지 (PostgreSQL)

평소에 검사를 돌지 않다가, 락 대기가 deadlock_timeout(기본 1초)을 넘기면 그제서야 그래프를 만들어 검사한다. 대부분의 락 대기가 짧으면 감지 비용을 거의 안낸다.

순수 타임아웃

innodb_lock_wait_timeout(기본 50초) 같은 값을 넘기면 그냥 그 트랜잭션을 죽인다. 그래프 감지가 놓친 경우의 안전망 역할을 한다.

2. 희생자 선정 후 강제 롤백

데드락 사이클이 판단되면 DB는 한 트랜잭션을 골라 롤백해 매듭을 끊는다. InnoDB는 보통 수정한 행이 가장 적은 트랜잭션을 희생자로 삼는다.

MySQL: 1213 Deadlock found

PostgreSQL: ERROR: deadlock detected

3. 재시도는 애플리케이션에서

희생당한 트랜잭션이 롤백되어 처음부터 다시 시도해야 한다. 즉, 데드락은 운영 중 정상적으로 발생할 수 있는 이벤트이고, 앱은 이 에러를 잡아 재시도하게 한다.


언제 쓰고, 언제 안 쓰나?

쓸 때:

안 쓸 때:


남에게 설명한다면 어떻게 설명할 것인가?


추가 궁금한 질문들