DB Lock
DBMS마다 Lock를 구현하는 방식과 세부 적용 방법은 다르지만,
데이터의 접근을 제한함으로써 일관성을 보장하기 위한 방법으로 기본적인 개념은 유사합니다.
Lock 종류
DB Lock은 적용 대상과 상황에 따라 분류할 수 있습니다.
적용 대상에 따른 분류
- Row lock : 변경하려는 row에 대해 lock을 설정
- Record lock : index record에 대한 lock을 설정
- Gap lock : index record의 gap에 대한 lock 설정(gap은 index 중 실제 record가 없는 부분)
- Table lock : Table과 index에 모드 lock을 설정
- Database lock : 데이터베이스를 복구하거나 스키마를 변경할 때 설정
적용 상황에 따른 분류
- Shared Lock : 원하는 데이터에 lock을 걸었지만, 다른 세션에서 읽을 수 있습니다. 보통 데이터를 읽을 때 사용합니다.
- Exclusive Lock : 데이터에 lock을 걸면, 다른 세션에서 읽거나 변경 할 수 없습니다. 보통 데이터를 변경 할 때 사용합니다.
- Intention Lock : 요청한 범위에 대한 lock를 수행 할 수 있는지 빠르게 확인하기 위해 사용됩니다.
(예를 들어, Transaction A가 하나의 Row에 Exclusive lock을 걸어 놓은 상태에서 Transaction B가 해당 테이블 전체에 대한 lock을 걸기 위해선 모든 테이블 Row에 대한 lock 유무를 확인해야 합니다. 이 때, Transaction A가Intention Lock 테이블에 걸어두면 Transaction B는 좀 더 빠르게 Lock 적용 유무를 확인 할 수 있습니다.)
Blocking
Transaction 간의 lock 경합이 발생하여, 작업이 진행되지 않고 멈춰선 상태를 말합니다.
Shared Lock 간에는 발생하지 않지만, Exclusive Lock에선 경합을 하여 우선 순위에 따라 Transaction이 수행됩니다.
이렇게 Blocking 된 Transaction은 lock이 해제 될 때까지 대기하게 되며, 이는 성능에 좋지 않는 영향을 미칩니다.
경합을 최소화하기 위해선 아래의 사항을 준수합니다.
- Transaction은 길지 않게 작성합니다.
- 동일한 데이터를 갱신하는 Transaction은 동시에 수행되지 않도록 설계합니다.
- Transaction 격리 수준을 불필요하게 상향 조정하지 않습니다
- 한번에 수행되는 작업 단위(쿼리)를 너무 무겁게 작성하지 않습니다.
Dead Lock
Dead lock(교착 상태)은 두 개 이상의 작업이 서로 상대방의 작업이 끝나길 기다리고 있기 때문에, 결과적으로 아무것도 완료되지 못하는 상태를 말합니다.
Database에서 dead lock은 서로 다른 Transaction 간의 교착 상태를 의미합니다.
해결 방법
- 예방 기법 : Dead Lock이 발생하지 않도록 미리 예방하는 방법입니다.
- Transaction이 실행되기 전에 필요한 모든 자원을 Lock 한다.
- 일정 시간이 지나면 쿼리가 취소도록 설정한다.
- 회피 기법 : 자원을 할당할 때 Time Stamp를 활용하여 Dead lock이 발생하지 않도록 회픠하는 방법입니다.
- Wait-Die 방식 : 먼저 들어온 Transaction은 대기(Wait)하고 나중에 들어온 Transaction은 포기(Die)하고 나중에 다시 요청한다.
- Wound-Wait 방식 : 먼저 들어온 Transaction은 데이터를 선점(Wound)하고, 나중에 들어온 Transaction은 대기(Wait)한다.
- 낙관적 병행 제어 기법 : Transaction이 커밋을 수행할 때, 데이터에 문제가 있다면 Roll-back 하는 방법입니다.
- 빈도 줄이기 기법 : Dead lock 발생 확률을 줄이는 방법입니다.
- Transaction 진행 방향을 같은 방향으로 처리
- Trahsaction 처리 속도를 최소화
- Lock 해제 시간을 조절
확인 방법
DBMS마다 Dead Lock을 관리하는 방법이 상이합니다.
MySQL-innodb 기준으로 아래의 쿼리를 통해 확인 할 수 있습니다.
mysql> show engine innodb status
위 쿼리를 수행하면 현재 innodb의 상태 정보를 표출되며, 최근 발생한 Dead lock 정보를 확인 할 수 있습니다.
만약 모든 deadlock에 대해 확인 하고 싶은 경우, 아래의 설정을 변경합니다.
[my.cnf]
[mysqld]
innodb_print_all_deadlocks = 1
또는
mysql> SET GLOBAL innodb_print_all_deadlocks = 1;