카테고리 없음

[TIL] Lock

s00ng 2025. 3. 24. 07:27

MySQL 엔진의 잠금

  • MySQL에서 사용되는 잠금은 크게 스토리지 엔진 레벨MySQL 엔진 레벨로 나뉨
  • MySQL 엔진 레벨의 잠금은 모든 스토리지 엔진에 영향을 미침
  • 스토리지 엔진 레벨의 잠금은 스토리지 엔진 간 상호 영향을 미치진 않는다.

 

글로벌 락

  • 글로벌 락은 FLUSH TABLES WITH READ LOCK 명령으로 획득 가능
  • MySQL에서 제공하는 잠금 중 가장 범위가 크다.
  • 한 세션에서 글로벌 락을 획득하면 다른 세션에서 SELECT를 제외한 대부분의 DDL 문장이나 DML 문장을 실행하는 경우 해제될 때까지 해당 문장이 대기 상태로 남는다.
  • 글로벌 락이 영향을 미치는 범위는 MySQL 서버 전체
  • InnoDB 스토리지 엔진은 트랜잭션을 지원하기 때문에 모든 데이터 변경 작업을 멈출 필요가 없음
    • → 백업 락 도입

 

백업 락

  • 특정 세션에서 백업 락을 획득하면 모든 세션에서 테이블의 스키마나 사용자의 인증 관련 정보를 변경할 수 없게 된다.
  • 하지만 일반적인 테이블의 데이터 변경은 허용된다.

 

테이블 락

  • 개별 테이블 단위로 설정되는 잠금, 명시적 또는 묵시적으로 특정 테이블의 락을 획득할 수 있다.
  • 명시적으로 테이블을 잠그는 작업은 온라인 작업에 상당한 영향을 미치기 때문에 직접 사용하지는 않는다.
  • 묵시적 테이블 락은 MyISAM이나 MEMORY 테이블에 데이터를 변경하는 쿼리를 실행하면 발생
  • MySQL 서버가 데이터가 변경되는 테이블에 잠금을 설정하고 데이터 변경 후 즉시 잠금을 해제하는 형태
  • InnoDB 테이블의 경우 스토리지 엔진 차원에서 레코드 기반의 잠금을 제공하기 때문에 단순 데이터 변경으로 인해 묵시적 테이블 락이 설정되지는 않음

 

네임드 락

  • 임의의 문자열에 대해 잠금을 설정할 수 있음
  • 단순히 사용자가 지정한 문자열(String)에 대해 획득하고 반납하는 잠금
  • 동일 데이터를 변경하거나 참조하는 프로그램끼리 분류해서 네임드 락을 걸고 쿼리를 실행하면 배치 프로그램으로 인한 데드락 문제를 해결할 수 있음

 

메타데이터 락

  • 데이터베이스 객체의 이름이나 구조를 변경하는 경우에 획득하는 잠금
  • 명시적으로 획득 또는 해제가 불가능하고 예를 들어, 테이블의 이름을 변경하는 경우 자동으로 획득하는 잠금

 

InnoDB 스토리지 엔진 잠금

  • InnoDB는 레코드 기반의 잠금 방식 덕분에 MyISAM 보다는 훨씬 뛰어난 동시성 처리를 제공할 수 있다.

 

레코드 락

  • 레코드 자체만을 잠그는 것을 **레코드 락(Record lock, Record only lock)**이라고 함
  • 중요한 점은 InnoDB 스토리지 엔진은 레코드 자체가 아니라 인덱스의 레코드를 잠근다는 특징이 있음
  • 보조 인덱스를 이용한 변경 작업은 넥스트 키 락, 갭 락을 사용
  • 프라이머리 키 또는 유니크 인덱스에 의한 변경 작업에서는 레코드 자체에 대해서만 락을 건다.

 

갭 락

  • 레코드와 바로 인접한 레코드 사이의 간격만을 잠그는 것을 의미한다.
  • 갭 락의 역할은 레코드와 레코드 사이의 간격에 새로운 레코드가 생성 되는 것을 제어하는 것

 

넥스트 키 락

  • 레코드 락과 갭 락을 합쳐 놓은 형태의 잠금을 넥스트 키 락이라고 함
  • InnoDB의 갭 락이나 넥스트 키 락은 바이너리 로그에 기록되는 쿼리가 레플리카 서버에서 실행될 때 소스 서버에서 만들어 낸 결과와 동일한 결과를 만들어내도록 보장하는 것이 주 목적

 

자동 증가 락

  • MySQL에서는 AUTO_INCREMENT라는 컬럼 속성을 제공하는데, 이를 위해 내부적으로 Auto increment lock이라고 하는 테이블 수준의 잠금을 사용한다.
  • 트랜잭션과 상관 없이 INSERT나 REPLACE 문장에서 AUTO_INCREMENT 값을 가져오는 순간만 락이 걸렸다가 즉시 해제된다.

 

 

인덱스와 잠금

  • InnoDB의 잠금은 레코드를 잠그는 것이 아니라 인덱스를 잠그는 방식으로 처리된다.
  • 변경해야 할 레코드를 찾기 위해 검색한 인덱스의 레코드를 모두 락을 걸어야한다.
  • 예를 들어, 하나의 ROW를 변경하기 위해 UPDATE 쿼리를 인덱스 없이 수행한다면 전체 데이터에 LOCK이 걸리게 된다.

 

MySQL 의 격리 수준

  • 트랜잭션의 격리 수준이란 여러 트랜잭션이 동시에 처리될 때 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 말지를 결정하는 것
  • READ UNCOMMITED, READ COMMITED, REPEATABLE READ, SERIALIZABLE
  • 뒤로 갈수록 각 트랜잭션 간의 데이터 격리 정도가 높아짐
  • 동시 처리 성능은 떨어짐
  • DIRTY READ NON-REPEATABLE READ PHANTOM READ
READ UNCOMMITED O O O
READ COMMITED X O O
REPEATABLE READ X X O (InnoDB에서는 없음)
SERIALIZABLE X X X

 

READ UNCOMMITED

  • 각 트랜잭션의 변경 내용이 커밋이나 롤백과 상관없이 다른 트랜잭션에서 보임
  • 롤백 했을 때 잘못된 데이터에 대한 정보를 가질 수 있음
  • Dirty Read → 어떤 트랜잭션에서 처리한 작업이 완료되지 않았음에도 다른 트랜잭션에서 볼 수 있는 현상
  • 정합성에 문제가 많은 격리 수준임

 

READ COMMITED

  • 오라클 DBMS의 기본 격리 수준
  • 온라인 서비스에서 가장 많이 선택되는 격리 수준
  • 어떤 트랜잭션에서 변경한 내용이 커밋되기 전까지는 다른 트랜잭션에서 그러한 변경 내역을 조회할 수 없다.
  • Non-repeatable Read 가 발생
  • 동일 데이터를 여러 번 읽고 변경하는 작업이 금전적인 처리와 연결되면 문제가 될 수도 있다.

 

REPEATABLE READ

  • MySQL의 InnoDB 스토리지 엔진에서 기본으로 사용함
  • 트랜잭션이 ROLLBACK 될 가능성에 대비해 변경되기전 레코드를 Undo 공간에 백업해두고 실제 레코드 값을 변경한다. → MVCC → 잠금을 사용하지 않는 일관된 읽기
  • Undo 영역에 백업된 COMMIT 되기 전에 데이터를 보여주기 때문에 Non-repeatable Read가 발생하지 않는다.
  • 하지만 다른 트랜잭션에서 수행한 변경 작업에 의해 새로운 레코드가 생기거나 없어지는 현상인 Phantom Read 는 **SELECT FOR … UPDATE**에서는 발생한다.
    • 갭 락과 넥스트 키 락 덕분에 일반적인 SELECT에서는 발생하지 않음

 

SERIALIZABLE

  • 가장 단순한 격리 수준이면서 동시에 가장 엄격한 격리 수준이다.
  • 동시 처리 성능이 가장 떨어진다.
  • InnoDB 는 순수 SELECT 작업에 잠금을 사용하지 않는 일관된 읽기를 제공하는데, SERIALIZABLE 은 읽기 작업도 공유 잠금을 획득해야함