
여러 트랜잭션이 동시에 동일한 데이터를 엑세스할 때 데이터 무결성을 유지하고 충돌을 방지하는 매커니즘
백엔드 개발을 하면서 여러 트랜잭션이 동시에 처리되는 경우가 많습니다. 이러한 동시성은 시스템의 성능을 높이지만, 동시에 데이터 무결성을 위협하는 잠재적인 문제를 동반합니다. 이때 중요한 역할을 하는 것이 바로 DB Lock입니다.
LS-Shared Lock : 공유락
LX-Exclusive Lock: 배타락
--Transaction 1: 공유 락 설정
SELECT * FROM member WHERE last_name = 'Kim' LOCK IN SHARE MODE;
--Transaction 2: 공유 락 설정
SELECT * FROM member WHERE last_name = 'Lee' LOCK IN SHARE MODE;
-- Transaction 1: 배타 락 설정
START TRANSACTION;
UPDATE member SET first_name = 'Ga Eun' WHERE first_name = 'gagle';
-- Transaction 2: 동일 리소스에 대해 배타 락 시도(대기 상태)
START TRANSACTION;
UPDATE member SET first_name = '가은' WHERE first_name = 'gagle';
두 개 이상의 트랜잭션이 서로의 락을 기다리며 무한 대기 상태에 빠지는 상황,
이는 시스템의 성능을 저하시킬 뿐만 아니라 트랜잭션 처리에 치명적인 영향을 미칠 수 있음
MySQL 로컬 db로 간단한 데드락 상황을 만들어봤습니다.
원래 테이블
첫번 째 세션에서 트랜잭션을 시작하고 1번 row에 update를 해줍니다.
(선점 시작, id = 1 인 행에 대한 배타 락 획득)
두번 째 세션에서 트랜잭션을 시작하고 2번 row에 update를 해줍니다(선점 시작, id = 12 인 행에 대한 배타 락을 획득)
첫번 째 트랜잭션에서 2번 row에 접근합니다(id = 2인 행에 대한 배타 락 요청, 대기 시작)
두 번째 트랜잭션에서 1번 행에 접근합니다 ( id = 1인 행에 대한 배타 락 요청, 대기 시작)
4. 데드락 해결 방법
사실 이거는 GPT한테 물어봤습니다...데드락 발생 시 어떻게 처리하는게 좋을지가 궁금해서...
예방, 감지, 그리고 복구의 세 가지 접근 방식으로 나눌 수 있습니다
1. 예방 (Prevention)
데드락을 예방하는 방법은 문제 발생 자체를 줄이는 것입니다.
a. 트랜잭션 범위 최소화: 트랜잭션을 짧고 간단하게 유지하여 자원 점유 시간을 최소화합니다.
b. 일관된 잠금 순서(순서 규칙 설정): 여러 트랜잭션이 동일한 자원을 잠글 때, 모든 트랜잭션이 동일한 순서로 자원을 잠그도록 합니다.
c. 적절한 인덱스 사용: 인덱스를 사용하여 쿼리 성능을 향상시키고, 자원 점유 시간을 줄입니다.
d. 트랜잭션 격리 수준 조정: 적절한 격리 수준을 선택하여 데이터의 일관성을 유지하면서 데드락 가능성을 줄입니다.
2. 감지 (Detection)
데드락 감지는 시스템에서 데드락이 발생했는지 확인하는 것 입니다.
a. 데드락 감지 알고리즘: 일반적으로는 Wait-For 그래프(Wait-For Graph)(위에서 간단히 설명함)
b. 데드락 로그 분석: 데이터베이스 로그를 분석하여 데드락 발생 시점을 파악합니다.
3. 복구 (Recovery)
데드락이 발생한 경우, 이를 해결하기 위한 복구 방법은 다음과 같습니다.
a. 트랜잭션 롤백: MySQL의 InnoDB 스토리지 엔진은 내부적으로 데드락 탐지 기능을 포함하고 있으며, 자동으로 교착 상태를 감지하고 트랜잭션 중 하나를 롤백합니다. (위의 예제에서는 트랜잭션2가 자동 롤백됨)
b. 재시도 로직 구현: 애플리케이션에서 데드락이 발생했을 때 자동으로 트랜잭션을 롤백하고 재시도하는 로직을 구현해야 합니다.
+)