개요
데드락(Deadlock, 교착 상태) : (Database에서는) 두 개 이상의 트랜잭션이 동시 진행될 때 특정 자원에 잠금을 획득한 채 다른 트랜잭션이 소유하고 있는 잠금을 요구하면서 서로 무한정 기다리는 상태를 의미한다.
- InnoDB는 기본적으로 데드락 감지 기능이 활성화되어 있다.
- 자동으로 데드락을 감지하여 트랜잭션을 강제 종료(롤백) 한다.
- 작은 트랜잭션(삽입, 업데이트, 삭제된 행 수가 적은)을 우선적으로 롤백 한다.
데드락 감지 기준
- 내부적으로 잠금이 데드락에 빠지지 않았는지 체크하기 위해 잠금 대기 목록을 그래프(Wait-for List, 대기 그래프) 형태로 관리한다.
- MySQL에서는 Wait-for Graph을 리스트 형태로 구현한다.
- 주기적으로 그래프를 검사하여 순환(cycle) 이 발생하였는지 확인한다.
- 대기 목록의 트랜잭션이 200개를 초과하거나, 확인해야 할 잠금이 100만개를 초과하면 데드락으로 감지하고 롤백 한다.
잠금 인식 조건
InnoDB 에서는 아래의 조건을 충족할 때 테이블 잠금을 인식할 수 있다.
-
innodb_table_locks = 1
(기본값)이고autocommit = 0
일 때innodb_table_locks
: InnoDB 테이블 락 감지 시스템 변수- 레코드뿐만 아니라 테이블 레벨의 잠금도 감지 가능
autocommit
: SQL 문을 자동으로 커밋 할 것인지 결정하는 시스템 변수
-
행 수준의 잠금(Row-Level Lock)이 활성화 되어 있는 경우
- 행 수준의 잠금 : 한 테이블의 하나의 행을 읽고 수정할 때 다른 행들에 대한 액세스는 허용될 수 있는 잠금
-
잠금 인식 조건에 충족하지 않은 경우, LOCK TABLES 로 얻은 잠금과 InnoDB 이외 스토리지 엔진의 잠금은 감지하지 못한다.
- 이 경우에는
innodb_lock_wait_timeout
을 이용하여 해결할 수 있다. - 책에서는
innodb_lock_wait_timeout
을 50초 이하로 설정하는 것을 권장하고 있다.
- 이 경우에는
작동 방식
- 데드락이 감지되면 희생양(victim) 트랜잭션을 선택하여 롤백 한다.
- 주로 작은 트랜잭션을 우선적으로 선택한다. (강제 롤백으로 인한 부하가 줄기 때문)
- 트랜잭션의 크기는 주로 Undo log의 양으로 판단한다.
- Undo log 레코드가 적을수록 우선적인 롤백 대상이 된다.
동시 처리 쓰레드가 많아지거나 트랜잭션 당 잠금 수가 증가하면 데드락 감지 스레드의 성능이 저하될 수 있다.
자동 데드락 감지 비활성화
innodb_deadlock_detect
를 OFF로 설정하여 데드락 감지 스레드를 비활성화할 수 있다.- 비활성화 시 실제 데드락 발생 시 시스템이 자동으로 해결하지 못하고 타임아웃에 의존하게 되어 주의해야 한다.
데드락에 빠진 마지막 트랜잭션 확인 쿼리
SHOW ENGINE INNODB STATUS