데이터베이스에서 여러 사용자나 프로세스가 동시에 공유 자원에 접근할 때, 데이터의 일관성과 무결성을 보장하기 위해 동시성 제어가 필수적입니다. 그중 락(Lock)은 대표적인 동시성 제어기법으로, 특정 자원에 대한 접근을 제한하여 동시에 여러 작업이 데이터를 수정하지 못하도록 합니다.
1. 동시성 제어 개념
여러 사용자, 프로세스가 동시에 공유 자원에 접근할 때 데이터의 일관성과 무결성을 유지하기 위한 메커니즘
📌 비관적 동시성 제어 (Pessimistic Concurrency Control)
사용자들이 같은 데이터를 동시에 수정할 것이라고 가정하여, 미리 락을 걸어 충돌을 방지
동작 방식
- Lock 또는 트랜잭션 타임스탬프를 사용하여 데이터를 보호합니다.
사용 사례
SELECT balance FROM account WHERE id = 'Alice' FOR UPDATE;
위 쿼리는 `FOR UPDATE` 로 해당 계좌 데이터를 배타 락(Exclusive Lock)으로 잠가, 다른 트랜잭션이 수정하지 못하도록 합니다.
💡 은행 계좌 이체와 같이 데이터 충돌이 치명적인 경우 비관적 동시성 제어가 유리합니다.
📌 낙관적 동시성 제어 (Optimistic Concurrency Control)
사용자가 동시에 같은 데이터를 수정하지 않을 것이라고 가정하여, 잠금 없이 트랜잭션을 진행
동작 방식
- Commit 전, 다른 트랜잭션에 의해 데이터가 변경되었는지 확인한 후 변경사항을 반영합니다.
사용 사례
- 경쟁이 적은 환경이나, 수정 빈도가 낮은 시스템에서 주로 사용됩니다.
💡 충돌이 거의 발생하지 않는 상황에서는 잠금 비용을 줄일 수 있어 효율적입니다.
2. 락(Lock)이란? 그리고 락의 종류
여러 트랜잭션이 동시에 공유 자원에 접근할 때, 데이터의 일관성과 무결성을 유지하기 위해 접근을 제한하는 역할
📌 공유 락 (Shared Lock)
특징
- 여러 트랜잭션이 동시에 읽기 작업을 수행할 수 있도록 허용합니다.
- 단, 쓰기 작업은 불가능합니다.
예시
- 여러 사람이 화장실에서 세수나 양치를 할 수 있지만, 동시에 변기를 사용하지 못하는 상황과 비슷합니다.
구현 방식 (MySQL)
-- 공유 락 설정
SELECT * FROM table_name WHERE id = 1 LOCK IN SHARE MODE;
- `LOCK IN SHARE MODE`를 사용하면 다른 트랜잭션이 동일한 데이터를 읽을 수 있지만, 변경(쓰기)은 불가능합니다.
📌 배타 락 (Exclusive Lock)
특징
- 한 트랜잭션이 자원을 독점적으로 사용할 수 있도록 하여, 다른 트랜잭션은 읽기와 쓰기 모두 수행할 수 없습니다.
예시
- 화장실의 변기를 단 한 사람이 사용하듯, 특정 자원을 단독으로 사용할 때 적용됩니다.
구현 방식 (MySQL)
-- 배타 락 설정
SELECT * FROM table_name WHERE id = 1 FOR UPDATE;
- `FOR UPDATE`를 사용하면 해당 데이터에 대해 다른 트랜잭션이 읽기와 쓰기 모두 차단됩니다.
💡 공유 락과 배타 락은 동시에 설정될 수 없으며, 하나의 자원에 대해 동시에 한 종류의 락만 적용됩니다.
분산 락 (Distributed Lock)
특징
- 여러 서버(분산 환경)에서 동일한 자원에 대한 동시 접근을 방지하기 위해 사용됩니다.
- DB 단일 인스턴스에서 동작하는 기존 락( 공유락, 배타락)과는 달리 다중 서버 환경에서 동시성을 제어합니다.
분산락이 필요한 이유는?
- 단일 서버에서는 `SELECT ... FOR UPDATE` 같은 락을 사용하면 되지만, 여러 개의 서버(A, B, C)가 동일한 데이터에 접근하는 경우 데이터베이스 락만으로는 문제를 해결할 수 없습니다
- DB 단일 인스턴스에서 동작하는 기존 락( 공유락, 배타락)과는 달리 다중 서버 환경에서 동시성을 제어합니다.
- 예시 : 여러 개의 서버가 동시에 재고 감소 연산을 수행하면, 하나의 서버에서 락을 걸어도, 다른 서버에서는 이를 인지 하지 못해, 데이터 정합성이 깨져 버릴 수 있습니다.
3. 블록킹(Blocking)과 교착상태(Deadlock)
블록킹 (Blocking)
락 경합으로 인해 선행된 트랜잭션이 완료되기를 대기하는 상태
- `트랜잭션1`이 SELECT ... FOR UPDATE (혹은 일반 SELECT 후 UPDATE 시도)로 인해 Shared Lock 혹은 Exclusive Lock을 획득한다.
- `트랜잭션1`이 아직 커밋하지 않은 상태에서 `트랜잭션2`가 같은 자원(예: 같은 account 행)에 대해 Exclusive Lock을 요청한다.
- `트랜잭션1`이 락을 보유 중이므로, `트랜잭션2`는` 트랜잭션1`이 커밋 또는 롤백으로 락을 해제할 때까지 대기(Blocking) 한다.
- `트랜잭션1`이 완료되면 락이 해제되고, 이후 `트랜잭션2`가 락을 획득하여 작업을 마친다.
해결 방법
- 블로킹은 일시적인 대기 상태로, 결국 선행 트랜잭션이 커밋하거나 롤백하면 문제가 해소됩니다.
- 대기 시간이 길어지면 응답 지연이 발생하므로, 락이 필요한 트랜잭션은 최소한의 구간만 유지하도록 설계하는 것이 중요!
교착상태 (Deadlock)
두 개 이상의 트랜잭션이 서로가 가진 락을 기다리며 무한 대기하는 상황
- 트랜잭션1이 account 테이블(혹은 행)에 대해 Exclusive Lock을 획득한다.
- 트랜잭션2는 다른 테이블(account_hst)에 대해 Exclusive Lock을 획득한다.
- 트랜잭션1은 추가 작업을 위해 account_hst에 대한 Exclusive Lock이 필요하지만, 이미 트랜잭션2가 보유 중이므로 대기한다.
- 트랜잭션2도 account에 대한 락이 필요해 대기 상태에 들어간다.
- 두 트랜잭션 모두 서로가 보유 중인 락을 기다리며 무한정 대기하며, 교착상태(Deadlock)가 발생.
해결 방법
- DBMS는 교착상태를 감지하면 보통 한 쪽 트랜잭션을 강제 롤백하여 데드락을 해소합니다.
- 애플리케이션 차원에서도 트랜잭션 순서를 정하거나, 락 획득 순서를 일관되게 유지하는 등 데드락 회피 전략이 필요
'데이터베이스' 카테고리의 다른 글
📌인덱스를 활용한 쿼리 개선해보기 (0) | 2025.03.03 |
---|---|
데이터베이스 인덱스 (1) | 2025.02.19 |
데이터베이스 트랙잭션 (0) | 2025.02.17 |
데이터베이스 기본 개념 📚 (0) | 2025.02.16 |