Backend/Mysql
[MySQL] Deadlock(교착 상태) 원인
제이동 개발자
2024. 10. 27. 18:04
728x90
Deadlock(교착 상태) 원인
MySQL에서 Deadlock(교착 상태)는 두 개 이상의 트랜잭션이 서로가 필요로 하는 자원을 서로 잠금하고 있어 두 개 트랜잭션이 모두 완료하지 못하고 Rollback(롤백)이 되는 상태를 말한다. 일반적으로 Deadlock은 여러 트랜잭션이 동시에 데이터베이스 자원(행, 테이블 등)을 접근할 때 발생할 수 있으며 발생되는 원인에 대해 알아보자.
1. 교차 락(Cross Locking)
두 개 이상의 트랜잭션이 서로의 필요로 하는 자원을 잠그고, 상대방이 소유한 락을 기다리며 발생하는 상황이다.
- 트랜잭션 A가
id = 1
인 행을 배타적 락을 건다. - 트랜잭션 B가
id = 2
인 행을 배타적 락을 건다. - 트랜잭션 A가
id = 2
인 행을 배타적 락을 걸기 위해 트랜잭션 B가 걸었던id = 2
인 행의 배타적 락이 끝날 때까지 기다린다. - 트랜잭션 B가
id = 1
인 행을 배타적 락을 걸기 위해 트랜잭션 A가 걸었던id = 1
인 행의 배타적 락이 끝날 때까지 기다린다.
-- 트랜잭션 A
BEGIN;
UPDATE orders SET status = 'processed' WHERE id = 1; -- 행 1 잠금
-- 트랜잭션 B가 실행되기 전까지 기다림
UPDATE orders SET status = 'processed' WHERE id = 2; -- 행 2 요청
-- 트랜잭션 B
BEGIN;
UPDATE orders SET status = 'processed' WHERE id = 2; -- 행 2 잠금
-- 트랜잭션 A가 실행되기 전까지 기다림
UPDATE orders SET status = 'processed' WHERE id = 1; -- 행 1 요청
2. 다중 트랜잭션에서 동일한 순서가 아닌 자원 잠금
여러 트랜잭션이 동일한 테이블이나 행을 접근할 때 접근 순서가 다를 경우 발생할 수 있다.
- 트랜잭션 A가
accounts
테이블의user_id = 1
인 행을 배타적 락을 건다. - 트랜잭션 B가
transactions
테이블의transaction_id= 123
인 행을 배타적 락을 건다. - 트랜잭션 A가 transactions 테이블의
transaction_id= 123
인 행을 배타적 락을 걸기 위해 트랜잭션 B가 걸었던transaction_id= 123
인 행의 배타적 락이 끝날 때까지 기다린다. - 트랜잭션 B가
accounts
테이블의user_id = 1
인 행을 배타적 락을 걸기 위해 트랜잭션 A가 걸었던user_id = 1
인 행의 배타적 락이 끝날 때까지 기다린다.
-- 트랜잭션 A
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
-- 트랜잭션 B가 실행되기 전까지 기다림
UPDATE transactions SET status = 'completed' WHERE transaction_id = 123;
-- 트랜잭션 B
BEGIN;
UPDATE transactions SET status = 'processing' WHERE transaction_id = 123;
-- 트랜잭션 A가 실행되기 전까지 기다림
UPDATE accounts SET balance = balance + 100 WHERE user_id = 1;
3. 다중 업데이트 하는 경우
다중 업데이트를 하는 경우 MySQL은 테이블을 풀 스캔하며 레코드를 잠그게 되는데 동시에 여러 트랜잭션이 테이블의 잠금 요청을 하면 Deadlock이 발생하게 된다.
아래는 두 트랜잭션이 인덱스 없이 같은 테이블에서 범위 업데이트를 수행할 때 발생하는 케이스이다.
-- 트랜잭션 A
BEGIN;
UPDATE products SET stock = stock - 1 WHERE category = 'electronics'; -- 인덱스 없는 카테고리 업데이트
-- 트랜잭션 B가 실행되기 전까지 기다림
-- 트랜잭션 B
BEGIN;
UPDATE products SET stock = stock + 1 WHERE category = 'electronics'; -- 동일한 조건의 인덱스 없는 업데이트
4. 외래 키 제약 조건
외래 키로 연결된 테이블에서 트랜잭션이 서로 연관된 데이터를 업데이트하거나 삭제할 때 Deadlock이 발생할 수 있다.
-- 트랜잭션 A
BEGIN;
DELETE FROM customers WHERE id = 1; -- 부모 테이블에서 삭제
-- 트랜잭션 B가 실행되기 전까지 기다림
-- 트랜잭션 B
BEGIN;
INSERT INTO orders (customer_id, amount) VALUES (1, 100); -- 자식 테이블에 외래 키로 연결된 데이터 삽입
728x90