DBMS

[DBMS] DB Locking

도전하는 린치핀 2024. 8. 6. 15:19

1. DB Locking 이란?

  • DB Locking은 데이터베이스 내 동시성과 데이터의 일관성을 보장하기 위해 사용되는 데이터 관리 메커니즘이다.
  • 보통 데이터베이스에 여러 사용자가 동시에 데이터에 접근하거나 수정할 때 충돌이 일어날 수 있다.
  • 이러한 충돌을 제어하기 위해 트랜잭션의 격리 수준과 비즈니스 로직에 따라 데이터에 접근을 막는 Locking이 필요하다.

1-1. Lock의 설정 범위

데이터베이스

  • 데이터베이스 범위의 Lock은 1개의 세션만이 데이터베이스 내 데이터에 접근 가능하게 하는 Lock의 범위이다.
  • 보통 데이터베이스 전체 범위로 Lock을 설정하면 동시성과 효율이 매우 떨어지기 때문에 사용하지 않는다.
  • 하지만 데이터베이스의 소프트웨어 버전을 변경하거나 중요한 데이터베이스의 업데이트를 진행할 때 설정한다.

파일

  • 데이터베이스의 파일을 기준으로 Lock을 설정하는 것이다.
  • 여기서 파일은 테이블, row 등 실제 데이터가 쓰이는 물리적인 장소로 해당 범위의 Lock도 잘 사용하지 않는다.

테이블

  • 테이블을 기준으로 Lock을 설정하여 해당 테이블에 대한 접근을 막는 것을 의미한다.
  • 보통 테이블의 모든 행을 업데이트 하는 등의 전체 테이블에 영향을 주는 작업을 진행할 때 사용한다.
  • 즉, DDL(CREATE, ALTER, DROP) 쿼리가 수행될 때 테이블 단위의 Lock을 진행하여 DDL Lock이라고 한다.

페이지와 블록

  • 파일의 일부인 페이지와 블록을 기준으로 Lock을 설정하여 잘 사용하지 않는다.

컬럼

  • 테이블 내 컬럼을 기준으로 Lock을 설정하는 것으로 이 방식은 Lock의 설정과 해제에 많은 리소스가 들어 일반적으로 사용하지 않고 지원하는 DBMS도 많이 없다.

  • 1개의 행(row)을 기준으로 데이터의 접근을 관리하는 방식으로 보통 제일 많이 사용하는 데이터 Lock 방식이다.

 

2. Optimistic Lock

특징

  • 낙관적인: 기본적으로 데이터 갱신 시 충돌이 발생하지 않을 것이라고 낙관적으로 보는 락
  • 비선점적인: 데이터 갱신 시 충돌이 발생하지 않을 것이라고 예상하기 때문에, 우선적으로 락을 걸지 않는다.

설명

  • DB가 제공하는 락 기능을 사용하지 않고, Application Level(JPA 등)에서 잡아주는 락이다.
  • version 등의 컬럼을 추가해 여러 트랜잭션 내 하나의 데이터에 중복 업데이트를 확인한다.
  • DB 트랜잭션을 걸지 않기 때문에, 여러 트랜잭션이 동일 데이터에 업데이트를 시도할 수 있다.
  • 데이터베이스 수준의 Roll-back이 없기에, 충돌시 대처 방안을 구현해야 한다.

 

사용자 1과 사용자 2가 모두 동일한 레코드에 대한 트랜잭션 요청을 동시에 보내는 것을 관찰한다.

그러나 사용자 1의 트랜잭션이 다른 쪽에서 성공적으로 업데이트 되는 동안 사용자 2의 커밋된 트랜잭션은 거부된다.

결과적으로 트랜잭션을 재시도하기 위해 사용자 2는 먼저 현재 데이터를 읽은 다음 해당 정보를 기반으로 새 트랜잭션을 만들어야 한다.

JPA에서의 Optimistic Lock

JPA에서 Optimistic Lock을 사용하기 위해서는 Entity 내부에 @Version Annotation이 붙은 Long, Integer, Short, Timestamp Type의 변수를 구현해줌으로써 간단하게 구현이 가능하다.

여러 업데이트가 서로 간섭하지 않도록 방지하는 version 이라는 구분 속성을 확인하여 Entity의 변경사항을 감지하는 메커니즘이다.

@Entity
public class Board {
@Id
private String id;
private String title;

@Version
private Integer version;
}

엔티티를 수정하고 트랜잭션을 커밋할 때, 영속성 컨텍스트를 플러시하면서 UPDATE 쿼리를 실행한다.

UPDATE BOARD
SET
	TITLE=?,
    VERSION=? (버전 +1 증가)
WHERE
	ID=?
    AND VERSION=? (버전 비교)

데이터베이스의 버전과 엔티티의 버전이 같으면 데이터를 수정하면서 동시에 버전도 하나 증가시킨다.

그러나 이미 데이터베이스에 수정이 이루어져 두 버전이 다르면, WHERE문에서 조건이 달라지므로 수정할 대상이 없어져 이 경우 JPA가 예외를 발생시킨다.

3. Pessimistic Lock

특징

  • 비관적인: 기본적으로 데이터 갱신 시 충돌이 발생할 것이라고 비관적으로 보고 미리 잠금을 거는 락
  • 선점적인: 데이터 갱신 시 충돌이 발생할 것이라고 예상하기 때문에, 우선적으로 락을 건다.

설명

  • 트랜잭션이 시작될 때 Shared Lock 또는 Exclusive Lock을 걸고 시작하는 방법으로 DB가 제공하는 락 기능을 사용한다.
  • DB Transaction을 이용해 충돌을 예방하는 것이 바로 비관적 락(Pessimistic Lock)이다.
  • 충돌이 발생하면 Transaction이 실패한 것이기 때문에 트랜잭션 전체에 자동으로 Rollback이 일어난다.

4. Shared(공유) Lock / Exclusive(베타) Lock

Shared(공유) Lock

  • 공유 락은 데이터를 읽을 때 사용되는 Lock이다. 이런 공유 락은 공유 락 끼리는 동시에 접근이 가능하다.
  • 즉, 하나의 데이터를 읽는 것은 여러 사용자가 동시에 할 수 있다라는 것이다.
  • 하지만 공유 락이 설정된 데이터에 배타 락(Exclusive Lock)을 사용할 수는 없다.

Exclusive(배타) Lock

  • 배타 락은 데이터를 변경하고자 할 때 사용되며, 트랜잭션이 완료될 때까지 유지된다.
  • 배타락은 락이 해제될 때까지 다른 트랜잭션(읽기 포함)은 해당 리소스에 접근할 수 없다.
  • 또한 해당 락은 다른 트랜잭션이 수행되고 있는 데이터에 대해서는 접근하여 함께 락을 설정할 수 없다.

 

5. 적절한 Lock 선택의 전략

  • 비관적 락과 낙관적 락 중 어떤 전략을 선택할지는 애플리케이션의 특성과 요구 사항에 따라 달라진다.
  • 비관적 락은 데이터의 일관성과 무결성을 보장하는 것이 매우 중요하기 때문에, 충돌이 자주 발생할 것으로 예상되는 경우에 적합하다.
  • 반면, 낙관적 락은 충돌이 드믈게 발생하고 동시성이 높은 환경에서 시스템의 성능을 최적화하고자 할 때 적합하다.
  • 이처럼, 다양한 애플리케이션의 환경과 요구 사항을 면밀히 분석하여, 가장 효율적이고 적합한 동시성 제어 전략을 선택해야 한다.
  • 올바른 전략 선택은 데이터의 일관성을 보장하고, 시스템의 성능을 최적화하는 데 결정적인 역할을 하기 때문이다.

 

생각해볼 수 있는 질문
1. 비관적 락을 사용하는 경우
 - 데이터의 일관성이 매우 중요하고, 데이터의 충돌이 자주 일어날 것이 예상 될 때 사용한다.
2. 공유 락과 배타 락의 차이
 - 공유 락은 읽기 전용이며 공유 락끼리는 동시에 접근이 가능하고, 배타 락은 쓰기와 읽기 모두 가능하며 동시에 접근이 불가능하다.
3. 낙관적 락을 사용하는 경우
 - 동시성이 높은 환경에서 성능 최적화 할 때 사용하고, 데이터의 충돌이 일어나지 않을 것이 예상될 때 사용한다.
4. 데이터 사용 시, 충돌이 일어나는 상태를 뭐라고 하나요?
 - 경쟁 상태(Race Condition)라고 하고 트랜잭션의 격리 수준에 따라 발생할 수 있는 Dirty Read, Phantom Read, Non-repeatable read 등이 있다.