[DB] Lock

박재희·2024년 1월 11일

LOCK 이란?

Lock이란 데이터베이스에서 동시성과 데이터 일관성을 보장하기 위해 사용되는 메커니즘이다

  • 예를 들어, 여러 사용자(트랜잭션)들이 동시에 같은 데이터에 접근하려고 할 때, 데이터베이스는 Lock을 사용하여 해당 데이터를 사용하고 있는 사용자(트랜잭션)와 다른 사용자(트랜잭션)들 간의 접근을 제어하여 충돌을 방지한다

  • DBMS마다 Lock을 구현하는 방식과 세부적인 기능이 많이 다르므로 각 DBMS마다 Lock을 구현하는 방식에 대한 공부가 필요하다

LOCK 의 필요성

낙관적 잠금 (Optimistic Lock)

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

  • Version을 사용해 관리
  • version이라는 정보(컬럼) 하나를 통해 관리 하기 때문에 어플리케이션 레이어를 통해 거는 락

비관적 잠금 (Pessimistic Lock)

  • 기본적으로 데이터 갱신시 충돌이 발생할 것이라고 비관적으로 보고 미리 잠근을 거는 것
  • 데이터 갱신시 충돌이 발생할 것이라고 예상하기 때문에, 우선적으로 락을 건다(조회할 때 부터)

  • 가져올때 DB에 락을 건다
  • 데이터베이스 락
  • 무결성의 장점이 있지만 데드락의 위험성이 있다

공유 락 (Shared Lock)

  • 공유 락은 데이터를 조회(SELECT) 할 경우 사용되며 Read Lock이라고도 불리며 Shared의 앞 글자를 따서 주로 S로 표기한다
  • 여러 사용자가 동시에 데이터를 읽어도 데이터의 일관성에는 아무런 영향을 주지 않기 때문에, 공유 락끼리는 동시에 접근이 가능하다
  • 즉, 내가 보고 있는 데이터는 다른 사용자가 볼 수 있지만, 변경할 수는 없다
    하지만 공유 락이 설정된 데이터에 베타 락을 사용할 수 없다

베타 락 (Exclusive Lock)

  • 베타 락은 데이터에 변경할 때 사용하는 Lock으로 Write Lock으로도 불리며, X로 표기한다
  • 베타 락은 이름처럼 다른 세션이 해당 자원에 접근(ex, SELECT, INSERT..) 하는 것을 막고 트랜잭션이 완료 될 때까지 유지된다
  • 베타 락은 해제될 때 까지 다른 트랜잭션은 해당 리소스에 접근할 수 없으며, 변경 및 읽기가 불가능하다

Lock의 설정 범위

  • 데이터베이스

    • 전체 데이터베이스를 기준으로 Lock을 설정한
    • 즉, 1개의 세션만이 DB의 데이터에 접근이 가능하며 일반적으로 잘 사용하지 않습니다.
    • DB의 소프트웨어 버전을 업그레이드하거나 DB 업데이트를 진행할 경우 사용
  • 파일

    • 데이터베이스 파일을 기준으로 Lock을 설정여기서 파일이란 테이블, row등과 같은 실제 데이터가 쓰여지는 물리적인 저장소를 의미 잘 사용되지는 않는다
  • 테이블

    • 테이블을 기준으로 Lock을 설정
    • 이는 테이블의 모든 행을 업데이트 하는 등의 전체 테이블에 영향을 주는 변경을 수행할 때 유용
    • DDL(create, alter, drop 등) 구문과 함꼐 사용되며 DDL Lock이라고도 합니다.
  • 페이지와 블럭

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

    • 컬럼을 기준으로 Lock을 설정
    • 하지만 이 범위는 Lock 설정 및 해제의 리소스가 많이 들기 때문에 잘 사용하지 않고, 지원하는 DBMS도 많지 않다
    • 1개의 행을 기준으로 Lock을 설정
    • DML에 대한 Lock으로 가장 기본으로 사용하는 Lock

블로킹 (Blocking)

LOCK 들의 경합이 발생하여 특정 세션이 작업을 진행하지 못하고 멈춰 선 상태

  • 데이터에 대해서 하나의 트랜잭션이 베타 lock을 걸면 다른 트랙잭션들은 어떠한 lock도 걸지 못하고 대기해야하기 때문
  • 블로킹이 풀리는 시점은 트랜잭션이 commit 또는 Rollback 할때
  • 공유 락<-> 배타적 락 또는, 배타적 락 <->  배타적 락 끼리 블로킹이 발생할 수 있다
    ex) 공유략<->베타락 동시에 여러 트랜잭션이 데이터를 읽을 수 있도록 하는데, 한 트랜잭션이 읽는 동안 다른 트랜잭션이 수정을 시도하면 블로킹이 발생
    ex) 배타락 <-> 배타락 한 트랜잭션이 데이터를 수정하고 있는 동안 다른 트랜잭션이 동일한 데이터를 수정하려고 하면 블로킹이 발생

해결 방안

  • SQL 문장에 가장 빠르게 실행되도록 리펙토링하는 것이 가장 기본이며 효과적인 방법이다
  • 트랙잭션을 짧게 정의
  • 동일한 데이터를 동시에 변경하는 작업을 하지 않도록 설계하는 것이 좋다 또한 트랜젝션이 활발한 주간에는 대용량 갱신 작업을 수행하면 안된다
  • 대용량작업이 불가피할 경우, 작업단위를 쪼개거나 LOCK_TIMEOUT을 설정하여 해당 Lock의 최대시간을 설정한다

교착상태(DeadLock)

두 트랜잭션이 각각 Lock을 설정하고 서로의 Lock에 접근하여 값을 얻어오려고 할 때,
이미 각각의 트랜잭션에 의해 Lock이 설정되어 있기 때문에 양쪽 트랜잭션 모두 영원히 처리가 되지않게 되는 상태를 말한다

기본적으로 lock은 기다리면 내 차례가 돌아오지만 데드락은 기다려도 풀리지가 않는다
쉽게 말해서 두개의 세션이 머리 끄댕이를 잡고 니가 놔라 하는 상황이다
예를 들어 뉴진스와 아이브의 데이터를 UPDATE 하려는 상황이다 A세션은 장원영을 안유진으로 변경하기 위해 lock을 걸었고 B세션은 뉴진스 민지를 하니로 변경하기 위해 lock을 걸었다 이 상황에서 A세션이 뉴진스를 하니로 변경하려고 하고 B세션이 아이브를 레이로 변경하려고 한다면 서로가 서로를 기다리는 상황이된다
이럴 경우에는 둘 중에 하나가 rollback을 하면서 머리 끄댕이를 먼저 놔야 작업이 진행된다

해결 방안

  • Dead Lock이 감지되면 둘 중 하나의 트랜잭션을 강제 종료한다
  • Dead Lock 방지를 위해 접근 순서를 동일하게 하는 것이 중요하다

참고

0개의 댓글