MySQL InnoDB의 자동 데드락 감지

@lim · August 18, 2024

개요

데드락(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

참고 내용

@lim
기억은 기록기록