[데이터베이스] 잠금이란?
cs-study에서 스터디를 진행하고 있습니다.
잠금의 개념
데이터베이스는 데이터를 영속적으로 저장하고 있는 시스템이다. 이런 시스템은 같은 자원(데이터)에 대해서 동시에 접근하는 경우가 생길 수 밖에 없는데, 이때 데이터의 일관성과 무결성을 유지해야 한다.
예를 들어, 수강 신청 시스템에서 1명 만이 정원으로 남게 되었는데 여기서 2명의 사람이 동시에 수강 신청 버튼을 누르는 경우 성공은 1명만 되어야 한다. 이런 상황에서 DBMS가 사용하는 공통적인 방법이 잠금(lock)이다.
정리하자면, 잠금은 트랜잭션 처리의 순차성을 보장하기 위한 방법이다.
영속성이 뭘까?
영속성(persistence)은 데이터를 생성한 프로그램의 실행이 종료되더라도 사라지지 않는 데이터의 특성을 의미한다.
잠금의 종류
잠금은 상황에 따라 크게 두 가지로 나뉜다.
- 공유 잠금 (Shared Lock)
- 공유 잠금은 다른 말로 읽기 잠금이라고 부른다.
- 배타 잠금 (Exclusive Lock)
- 배타 잠금은 다른 말로 쓰기 잠금이라고 부른다.
공유 잠금
공유 잠금은 데이터를 읽을 때 사용되는 잠금이다. 공유 잠금은 공유 잠금끼리 동시에 접근이 가능하지만, 공유 잠금이 설정된 데이터에 배타 잠금은 사용할 수 없다. 쉽게 말하면, 공유 잠금을 설정한 경우 다른 세션이 동일한 데이터를 읽을 수 있지만, 변경할 수는 없다는 의미이다.
배타 잠금
배타 잠금은 데이터를 변경할 때 사용하며 트랜잭션이 완료될 때까지 유지된다. 배타 잠금은 잠금이 해제될 때까지 다른 트랜잭션(공유, 배타 잠금 포함)은 해당 데이터에 접근할 수 없다. 쉽게 말하면, 배타 잠금을 설정한 경우 다른 세션이 동일한 데이터에 읽기와 쓰기 작업을 할 수 없다는 의미이다.
블로킹 (Blocking)
블로킹은 잠금들의 경합(Race Condition)이 발생하여 특정 세션이 작업을 진행하지 못하고 멈춰 선 상태를 의미한다. 블로킹은 공유 잠금 - 배타 잠금
, 배타 잠금 - 배타 잠금
끼리 발생할 수 있다. 이를 해결하기 위해서는 이전의 트랜잭션이 완료(commit 또는 rollback)되어야 한다.
블로킹이 발생하면 먼저 잠금을 설정한 트랜잭션을 기다려야하므로, 이런 현상이 반복되면 성능에 좋지 않는 영향을 미친다. 따라서 블로킹을 최소화하는 것이 좋다.
블로킹을 최소화할 수 있는 방법은 다음과 같다.
- SQL문이 가장 빠르게 실행되도록 리팩터링하는 것이 가장 기본적이고 효과적인 방법이다.
- 트랜잭션을 가능한 짧게 정의하면 블로킹을 줄일 수 있다.
- 동일한 데이터를 변경하는 트랜잭션이 동시에 수행되지 않도록 해야 한다.
- 트랜잭션이 활발한 주간에는 대용량 갱신 작업을 수행하면 안 된다.
- 대용량 작업이 불가피한 경우, 작업 단위를 쪼개거나
lock_timeout
을 설정하여 해당 잠금의 치대 시간을 설정해야 한다.
교착 상태 (Deadlock)
교착 상태는 두 트랜잭션이 각각 잠금을 설정하고 서로의 잠금에 접근하려고 할 때, 이미 각각의 트랜잭션에 의해 잠금이 설정되어 있기 때문에 양쪽 트랜잭션 모두 처리가 되지 않는 상태를 말한다.
예를 들어, game_master
, game_detail
테이블이 있다고 가정하자. 트랜잭션 A가 game_master
테이블의 5번 row를 수정하고, game_detail
테이블의 5번 row를 이어서 수정하려고 한다. 트랜잭션 B는 game_detail
테이블의 5번 row를 수정하고 game_master
테이블의 5번 row를 수정하려고 한다.
이 경우 트랜잭션 A는 game_master
테이블의 5번 row에 배타 잠금을 설정했고, 트랜잭션 B는 game_detail
테이블의 5번 row에 배타 잠금을 설정했다. 그리고 교차로 트랜잭션 A는 game_tail
의 5번 row의 잠금 설정을 하려고 하고, 트랜잭션 B는 game_master
의 5번 row에 잠금 설정을 하려고 한다.
하지만 이미 각 row는 서로 다른 트랜잭션에 의해서 배타 잠금이 설정되어 있다. 따라서 서로 잠금이 해제되기를 기다리면서 잠금을 갖고 있기 때문에 영원히 잠금이 풀리지 않는다.
해결 방법
- 트랜잭션 진행 방향을 같은 방향으로 설계한다.
- 트랜잭션 A의 테이블 접근 순서를
game_master
→game_detail
, 트랜잭션의 B의 테이블 접근 순서도game_master
→game_detail
로 설정해서 교착 상태 발생 가능성을 줄인다. 이 방식은 블로킹을 발생하지만 교착 상태만큼의 큰 문제는 아니다.
- 트랜잭션 A의 테이블 접근 순서를
- 트랜잭션 처리 속도를 최소화한다.
- update문이 빠르게 처리되면, 교착 상태가 발생할 가능성이 줄어든다.
set_lock_timeout
문을 사용하여 잠금 해제 시간을 조절한다.- 잠금 시간을 설정하면 교착 상태가 발생했을 때 무기한 대기하지 않고 중간에 잠금이 풀리게 된다.
참고
예상 면접 질문 및 답변
잠금이란?
잠금은 트랜잭션 처리의 순차성을 보장하기 위한 방법이다.
블로킹이란?
블로킹은 잠금들의 경합(Race Condition)이 발생하여 특정 세션이 작업을 진행하지 못하고 멈춰 선 상태를 의미한다. 블로킹은 공유 잠금 - 배타 잠금
, 배타 잠금 - 배타 잠금
끼리 발생할 수 있다.
블로킹을 최소화할 수 있는 방법은?
- SQL문이 가장 빠르게 실행되도록 리팩터링하는 것이 가장 기본적이고 효과적인 방법이다.
- 트랜잭션을 가능한 짧게 정의하면 블로킹을 줄일 수 있다.
- 동일한 데이터를 변경하는 트랜잭션이 동시에 수행되지 않도록 해야 한다.
- 트랜잭션이 활발한 주간에는 대용량 갱신 작업을 수행하면 안 된다.
- 대용량 작업이 불가피한 경우, 작업 단위를 쪼개거나
lock_timeout
을 설정하여 해당 잠금의 치대 시간을 설정해야 한다.
교착 상태(데드락)란?
교착 상태는 두 트랜잭션이 각각 잠금을 설정하고 서로의 잠금에 접근하려고 할 때, 이미 각각의 트랜잭션에 의해 잠금이 설정되어 있기 때문에 양쪽 트랜잭션 모두 처리가 되지 않는 상태를 말한다.
교착 상태(데드락)을 해결할 수 있는 방법은?
- 트랜잭션 진행 방향을 같은 방향으로 설계한다.
- 트랜잭션 A의 테이블 접근 순서를
game_master
→game_detail
, 트랜잭션의 B의 테이블 접근 순서도game_master
→game_detail
로 설정해서 교착 상태 발생 가능성을 줄인다. 이 방식은 블로킹을 발생하지만 교착 상태만큼의 큰 문제는 아니다.
- 트랜잭션 A의 테이블 접근 순서를
- 트랜잭션 처리 속도를 최소화한다.
- update문이 빠르게 처리되면, 교착 상태가 발생할 가능성이 줄어든다.
set_lock_timeout
문을 사용하여 잠금 해제 시간을 조절한다.- 잠금 시간을 설정하면 교착 상태가 발생했을 때 무기한 대기하지 않고 중간에 잠금이 풀리게 된다.
'스터디 > CS 스터디' 카테고리의 다른 글
[데이터베이스] MySQL 스토리지 엔진의 잠금 (0) | 2021.12.27 |
---|---|
[데이터베이스] NoSQL - What is NoSQL (0) | 2021.12.26 |
[데이터베이스] B-Tree 인덱스와 다중 컬럼 인덱스 (0) | 2021.12.21 |
[데이터베이스] MySQL 엔진의 잠금 (0) | 2021.12.19 |
[데이터베이스] 트랜잭션 기초 (0) | 2021.12.19 |
댓글