본문으로 바로가기
반응형

그동안 단순히 “데드락이 발생했다” 정도로만 알고 있던 내용에 대해 좀 더 상세하게 이해하기위해 아래 내용을 정리하려고 합니다.
현재 운영중인 이커머스 시스템에서 상품 정보를 Engine Page 형태로 제공하기 위한 여러 배치 작업들을 운영하고 있습니다.
필요한 상품 데이터를 새벽에 한 번 배치로 생성하고, 그 데이터를 기반으로 여러 Engine Page별 후속 배치가 순차적으로 실행되는 흐름이었습니다. 초기에는 상품 데이터 배치가 빠르게 끝났기 때문에 후속 배치와 충돌 없이 문제 없이 돌아갔습니다. 
하지만 시간이 지나면서 요구 사항이 추가되고, 상품 데이터량도 증가하면서 가장 앞단에서 실행되는 기본 데이터 생성 배치가 점점 더 오래 걸리는 상황이 발생했습니다.

기본 데이터 배치의 동작 방식은 다음과 같습니다.
- 기존 테이블 DROP
- 새로운 상품 기본 데이터를 CREATE / INSERT

이 작업이 길어지자, 아직 배치가 실행되는 와중에 그 다음 단계에서 실행되는 다른 Engine Page용 배치가 해당 테이블을 참조하기 시작했고, 기본 데이터 배치는 배타 락(Exclusive Lock) 을 장시간 점유 후속 배치는 같은 테이블을 조회하거나 갱신하려고 하면서 공유 락을 요청 하였고 양쪽이 서로의 락을 기다리는 상황이 되며 데드락 발생했습니다.

 

"선행 배치가 끝나지 않았는데 후속 배치가 테이블에 접근하면서 락 충돌 → 데드락"


락의 종류와 전략은 DBMS 벤더사마다 조금씩 다르다. 본 포스팅은 MySQL 8.0 InnoDB 기준으로 설명한다.

 

DBMS에서 여러 트랜잭션이 동시에 실행되면 서로 간섭하며 데이터 일관성이 깨질 위험이 생깁니다. 
이를 방지하기 위해 데이터베이스는 락(Lock)을 사용하여 트랜잭션 간 접근을 제어합니다.  대표적으로 공유 락(Shared Lock)과 배타 락(Exclusive Lock)이 있으며, 각각의 특성을 이해하면 병행 처리 구조를 더 명확하게 이해할 수 있습니다.

락의 종류

공유 락 (Shared Lock)
- 공유 락(Shared Lock)은 Read Lock이라고도 불린다.
- 공유 락이 걸린 데이터에 대해서는 읽기 연산만 가능하며, 쓰기 연산은 불가능하다.

배타 락 (Exclusive Lock)
- 배타 락 (Exclusive Lock)은 Write Lock이라고도 불린다.
- 배타 락을 획득한 트랜잭션은 읽기 연산, 쓰기 연산 모두 실행 가능하다.
- 다른 트랜잭션은 배타 락이 걸린 데이터에 대해 읽기 작업도, 쓰기 작업도 수행할 수 없다.

 

락의 범위

테이블 락(Table Lock)
- 테이블 전체를 잠그는 락.
- DROP, CREATE, TRUNCATE, ALTER 등 DDL 작업 시 강한 배타 락이 걸린다.
- 테이블 전체가 잠기므로 다른 트랜잭션은 읽기조차 대기 상태가 된다.

레코드 락(Record Lock / Row Lock)
- 특정 레코드(ROW)에 대해 걸리는 락.
- UPDATE ... WHERE id=1, SELECT ... FOR UPDATE 등에서 사용.
- 이 레벨에서는 같은 테이블이라도 다른 레코드는 정상적으로 조회 및 수정 가능.

갭 락(Gap Lock)
- 존재하지 않는 index 사이 “갭”에 걸리는 락.
- Repeatable Read 수준에서 범위 조회 시 사용.
- 다른 트랜잭션이 해당 구간에 새로운 레코드를 INSERT 하는 것을 막는다.

넥스트키 락(Next-Key Lock)
- 레코드 락 + 갭 락의 결합.
- 즉, “해당 레코드”와 “그 앞의 갭”을 동시에 잠근다.
- RR 격리 수준에서 SELECT ... FOR UPDATE / LOCK IN SHARE MODE 호출 시 흔히 발생.

 


데드 락(Dead Lock)
- 교착 상태로, 두개 이상의 트랜잭션이 서로 필요로 하는 데이터의 락을 점유하고 있어서 무한히 대기하는 상황을 말한다.
- 트랜잭션은 락을 획득하지 못하는 경우, 다른 트랜잭션이 점유하고 있는 락이 해제될 때까지 대기합니다.

반응형