Database/RDS

InnoDB - Locking

류큐큐 2024. 8. 12. 12:17

 

Lock의 종류

Shared Lock, S Lock

 shared lock은 특정 트랜잭션이 행을 읽을 수 있게 한다. 이 잠금을 획득한 트랜잭션은 행의 데이터를 읽을 수 있지만, 수정하거나 삭제할 수는 없다.

 

글자 그대로  Shared 공유한다. 여러 트랜잭션이 동일한 행에 대해 shared lock을 동시에 획득 할 수 있다. 

 

Exclusive Lock, X Lock

Exclusive lock은 특정 트랜잭션이 행을 수정하거나 삭제할 수 있게 한다. 배타적 잠금을 획득한 트랜잭션은 행의 데이터를 수정하거나 삭제할 수 있으며, 이 잠금이 해제될 때까지 다른 트랜잭션이 그 행을 수정하거나 읽을 수 없다.

 

글자 그대로 Exclusive 배타적이다. 특정 트랜잭션이 특정 행에 대해 먼저 Exclusive Lock을 가지고 있는경우 다른 트랜잭션은 Shared Lock, Exclusive Lock을 요청할 수 있지만 먼저 Exclusive Lock을 선점한 트랜잭션에서 잠금을 해제할 때까지 대기 상태로 남게 된다.

 

 

 

잠금의 범위/적용 대상

Intension Locks

InnoDB supports multiple granularity locking which permits coexistence of row locks and table locks 

다중 수준의 잠금을 지원하는 데 사용한다. 그런데 테이블에 Lock을 걸 일은 없을거같아 그만 알아보겠다.

Record Locks

인덱스 레코드에 대한 잠금이다. 이 잠금은 특정 행에 대한 삽입, 업데이트 또는 삭제 작업을 다른 트랜잭션이 수행하지 못하도록 막는다.

 

예를 들어,

 

SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;

 

라는 쿼리가 실행되면,

 

t 테이블의 c1 값이 10인 모든 행에 대해 레코드 잠금이 설정된다.

이 잠금이 해제될 때까지 다른 트랜잭션은 해당 행에 대한 수정 작업을 수행할 수 없다.

 

 

레코드 잠금은 항상 인덱스 레코드를 잠군다. 이는 테이블이 인덱스를 정의하지 않았더라도 똑같다.

만약 테이블에 명시적으로 정의된 인덱스가 없다면, InnoDB는 내부적으로 숨겨진 클러스터된 인덱스(hidden clustered index)를 생성하여 레코드 잠금을 수행. 이 숨겨진 인덱스는 각 행을 고유하게 식별할 수 있는 내부 ID를 기반.

 

Gap Locks

인덱스 레코드 사이의 갭을 잠군다. 트랜잭션이 인덱스의 특정 범위를 스캔할 때, 해당 범위 내의 갭에 다른 트랜잭션이 새로운 레코드를 삽입하지 못하도록 한다.

 

갭은 인덱스 레코드 사이의 영역 또는 첫 번째 인덱스 레코드 이전이나 마지막 인덱스 레코드 이후의 영역을 의미.

 

예를 들어,

 

SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;

 

라는 쿼리가 실행되면,

 

c1 값이 10과 20 사이에 있는 모든 값들에 대해 갭 잠금을 설정하며, 이 범위 내의 갭에 새로운 값을 삽입하는 것을 방지.

 

갭 잠금은 성능과 동시성 사이의 절충안으로, 일부 트랜잭션 격리 수준(예: REPEATABLE READ)에서만 사용.

READ COMMITTED 격리 수준에서는 갭 잠금이 비활성화될 수 있다.

 

갭 잠금은 주로 팬텀 행(Phantom Row) 문제를 방지하기 위해 사용. 팬텀 행 문제는 REPEATABLE READ 격리 수준에서 중요한 문제.

갭 잠금을 통해 이러한 문제를 예방하여, 트랜잭션 내에서 데이터를 반복적으로 읽을 때 동일한 결과를 보장할 수 있다.

 

Next-Key Locks

Record Lock과 Gap Lock을 결합한 형태, 이 잠금은 특정 인덱스 레코드뿐만 아니라 해당 레코드 앞의 "갭"도 함께 잠그는 방식으로 작동.

 

 

Next-Key Lock은 인덱스 레코드에 대한 잠금을 설정하는 동시에, 그 인덱스 레코드 바로 앞에 있는 "갭"도 잠군다.

예를 들어, 인덱스 레코드가 13인 경우, Next-Key Lock은 이 레코드뿐만 아니라 13 이전의 값(예: 11과 13 사이의 간격)도 잠군다.

 

만약 하나의 세션이 인덱스 레코드 R에 대해 공유 잠금(S Lock)이나 배타적 잠금(X Lock)을 설정하면, 다른 세션은 R 바로 앞의 갭에 새로운 인덱스 레코드를 삽입할 수 없다.

 

 

인덱스에 값 10, 11, 13, 20이 있다고 가정할 때, 가능한 Next-Key Lock은 다음과 같은 간격을 잠급니다:

  • (-∞, 10]
  • (10, 11]
  • (11, 13]
  • (13, 20]
  • (20, ∞)

마지막 간격 (20, ∞)의 경우, Next-Key Lock은 인덱스에서 가장 큰 값 20 이후의 갭과, 실제로 존재하지 않는 supremum이라는 가상의 레코드까지 잠급니다.

 

기본적으로 InnoDB는 REPEATABLE READ 트랜잭션 격리 수준에서 동작하며, 이 경우 Next-Key Lock이 검색 및 인덱스 스캔 시 사용됩니다. 이는 팬텀 행(Phantom Rows) 문제를 방지하기 위함.

 

 

 

Gap Lock은 인덱스 레코드 사이의 "갭"을 잠금으로써 팬텀 리드를 방지합. 그러나 Gap Lock만으로는 특정 인덱스 레코드 자체를 보호하지 않는다. 즉, 다른 트랜잭션이 해당 레코드를 읽거나 수정할 수 있다.

 

Record Lock은 특정 인덱스 레코드에 대한 잠금을 설정하여 다른 트랜잭션이 그 레코드를 수정하거나 삭제하지 못하게 한다. 하지만 Record Lock만으로는 그 레코드 주변의 "갭"에 새로운 레코드가 삽입되는 것을 막지 못한다.

 

 

따라서 Record Lock과 Gap Lock을 결합하여

특정 인덱스 레코드와 그 레코드 앞의 갭을 함께 잠금으로써, 트랜잭션이 검색하거나 수정하는 범위 내에서 다른 트랜잭션이 새로운 레코드를 삽입하거나 기존 레코드를 수정하는 것을 모두 방지.

 

이렇게 함으로써, 단일 트랜잭션 내에서 보다 일관된 데이터를 유지한다.

 

AUTO-INC Lock

 

AUTO_INCREMENT 컬럼이 있는 테이블에 새 행을 삽입할 때, InnoDB는 이 컬럼에 고유한 값을 자동으로 할당.

이 과정에서 여러 트랜잭션이 동시에 같은 테이블에 삽입 작업을 시도할 경우, 연속적인 AUTO_INCREMENT 값이 아닌, 중복되거나 비연속적인 값이 할당될 수 있다.

 

이를 방지하기 위해 InnoDB는 AUTO-INC Lock이라는 테이블 수준의 잠금을 사용. 이 잠금은 하나의 트랜잭션이 AUTO_INCREMENT 값을 할당받는 동안 다른 트랜잭션이 삽입 작업을 시작하지 못하게 하여, 삽입된 행들이 연속적인 AUTO_INCREMENT 값을 가질 수 있도록 보장.

 

 

innodb_autoinc_lock_mode 변수는 AUTO_INCREMENT 잠금의 동작 방식을 제어하는 설정입. 이 변수는 AUTO-INC Lock이 적용되는 방식을 결정하며, 동시성(여러 트랜잭션이 동시에 삽입할 수 있는 능력)과 AUTO_INCREMENT 값의 예측 가능성 사이의 균형을 맞추는 데 사용.

 

 

innodb_autoinc_lock_mode는 다음과 같은 값들로 설정할 수 있다

 

0 (Traditional Mode): 가장 강력한 AUTO-INC Lock. 하나의 트랜잭션이 삽입 작업을 수행하는 동안 다른 트랜잭션은 대기 상태에 있게 되며, 삽입된 행들은 항상 연속적인 AUTO_INCREMENT 값을 가진다. 그러나 이로 인해 동시성은 낮아진다.

 

1 (Consecutive Mode, Default): 기본 모드로, 연속된 AUTO_INCREMENT 값이 부여되도록 노력하지만, 동시성도 어느 정도 허용합니다. 이 모드에서는 배치 삽입 작업의 경우 첫 번째 트랜잭션이 삽입 작업을 완료한 후 다른 트랜잭션이 삽입을 시작할 수 있다.

 

2 (Interleaved Mode): 가장 동시성이 높은 모드로, 삽입된 행들의 AUTO_INCREMENT 값이 비연속적일 수 있습니다. 이 모드는 동시성을 최대화하면서도 AUTO_INCREMENT 값이 비연속적일 수 있는 상황을 허용.