개념적으로만 알고 있던 Deadlock을 실제 연출해보고자 합니다.
PostgreSQL에서는 Deadlock이 발생하지 않도록 관리해주는 기능이 있는 것으로 알고있는데 직접 확인해봅니다.
시나리오는 다음과 같습니다.
-- 트랜잭션 A
BEGIN;
LOCK TABLE table_x;
-- 여기서 일시정지되고 트랜잭션 B가 시작됨
-- 트랜잭션 B
BEGIN;
LOCK TABLE table_y;
-- 여기서 일시정지되고 트랜잭션 A가 table_y에 Lock을 요청함
-- 트랜잭션 A
LOCK TABLE table_y;
-- 여기서 트랜잭션 A는 table_y의 Lock을 기다리며 블록됨
-- 트랜잭션 B
LOCK TABLE table_x;
-- 여기서 트랜잭션 B는 table_x의 Lock을 기다리며 블록됨
직접 테스트해 본 결과는 다음과 같습니다.
1번 세션 콘솔 창입니다.
# session 1
postgres=# begin;
BEGIN
postgres=*# lock table table_x ;
LOCK TABLE
postgres=*# lock table table_y;
LOCK TABLE
2번 세션 콘솔 창입니다.
# session 2
postgres=# begin;
BEGIN
postgres=*# lock table table_y;
LOCK TABLE
postgres=*# lock table table_x;
ERROR: deadlock detected
DETAIL: Process 2524587 waits for AccessExclusiveLock on relation 24592 of database 15961; blocked by process 2518493.
Process 2518493 waits for AccessExclusiveLock on relation 24601 of database 15961; blocked by process 2524587.
HINT: See server log for query details.
위와 같이 deadlock을 감지하고 서로의 프로세스가 데드락에 의해 대기 상태임을 알립니다. 이 에러가 콘솔창에 뜨고나서 곧바로 Session1 의 table_y에 대한 Lock을 정상적으로 수행합니다.
로그를 확인해봅니다.
2024-06-08 18:33:28.236 KST [2524587] ERROR: LOCK TABLE can only be used in transaction blocks
2024-06-08 18:33:28.236 KST [2524587] STATEMENT: lock table table_y;
2024-06-08 18:34:11.938 KST [2524587] ERROR: deadlock detected
2024-06-08 18:34:11.938 KST [2524587] DETAIL: Process 2524587 waits for AccessExclusiveLock on relation 24592 of database 15961; blocked by process 2518493.
Process 2518493 waits for AccessExclusiveLock on relation 24601 of database 15961; blocked by process 2524587.
Process 2524587: lock table table_x;
Process 2518493: lock table table_y;
session2에서 점유중인 Lock을 해제하면서 deadlock 상황을 해지하는 것을 확인할 수 있습니다.