[DB] 데이터베이스 Lock에 대해

데이터베이스(Database)는 구조화된 정보 또는 데이터의 조직화된 모음을 의미한다. 데이터베이스(Database)를 사용하다보면 종종 같은 데이터에 동시에 접근하는 경우가 발생한다. 동시 접근이 발생하는 경우, 예를 들어 선착순 100개의 한정판을 판매하는데 99개가 판매되었고, 잔여 수량이 1 개인데 구매하려는 유저는 20명이면 실제 구매 성공이 되야하는 유저는 1명인데 만약 20명의 유저 전부에게 정상적으로 구매가 진행되었다고 출력된다면 해당 데이터가 오염될 수 있다. 이러한 상황에서 데이터베이스를 관리(제어)하는 DBMS는 데이터의 무결성과 일관성을 지키기위해 Lock을 사용한다.

 

Lock의 정의

Lock은 데이터베이스(Database)에서 트랜잭션(Transaction) 처리의 순차성을 보장하기 위해 데이터 변경을 일시적으로 중지하는 것을 의미한다. 트랜잭션은 더 이상 쪼갤 수 없는 작업처리의 최소 단위를 의미한다. 트랜잭션에 대해서는 다음번에 더 자세히 다뤄보겠다.

Lock의 크기 및 종류는 DBMS마다 차이가 있으므로 사용하려는 DB의 문서를 확인해보는 것이 좋다.

 

Lock의 크기(적용 범위)

Lock의 크기는 Lock이 적용될 범위를 의미한다. DBMS마다 차이는 발생할 수 있지만, 대체로 로우(Row) 락, 페이지(Page) 락, 테이블(Table) 락이 존재한다.

  • 로우 락은 데이터베이스 테이블의 행 수준에 거는 락을 의미한다. 일반적으로 가장 많이 사용하는 락이다.
  • 페이지 락은 페이지(테이블의 일부분을 500개 또는 특정 단위로 paging해둔 것)에 거는 락을 의미한다.
  • 테이블 락은 말 그대로 데이터베이스 테이블 수준에 거는 락을 의미한다. 테이블 모든 행 업데이트와 같이 테이블 전체에 영향을 미치는 동작을 할 때 사용되는 락이다. 

 

Lock을 걸 때 잠금 비용(Lock cost, 락을 거는 과정에서 발생하는 데이터베이스 성능 손실 비용)가 발생한다. 예를 들어 하나의 페이지에 락을 거는 비용은 테이블에 락을 거는 비용보다 적지만, 여러 페이지에 락을 거는 경우에는 거꾸로 테이블 전체에 락을 거는 것이 비용의 손실을 줄일 수 있다. 대신 테이블 전체에 락을 걸 경우, 잠금 비용은 감소하지만, 동시성 비용(Concurrency cost, 락을 걸면서 락이 걸린 리소스(데이터)에 접근해야 하는 쿼리의 대기 시간으로 인해 발생하는 데이터베이스 성능 손실 비용)이 증가하게 된다.

 

Lock의 종류

Lock의 종류에는 공유락(Shared Lock, 읽기 락), 배타락(Exclusive Lock, 쓰기 락)이 있다. 

 

공유 락(Shared Lock)

공유 락(Shared Lock)은 가장 낮은 중요도의 Lock으로 데이터를 읽을 때 사용되는 Lock이다. 일반적으로 SELECT 쿼리가 동작할 때, 공유 락이 발생하며, SELECT 쿼리가 완료되면 해제된다. 공유 락은 공유 락끼리는 같은 데이터에 동시 접근이 가능하다. 

  • Row 레벨에 걸리는 Lock
  • SELECT 동작을 위한 읽기 락
  • 단일 row에 여러 트랜잭션이 공유 락을 동시에 적용가능 

 

배타 락(Exclusive Lock)

배타 락(Exclusive Lock)은 가장 높은 중요도의 Lock으로 데이터를 변경할 때 사용되는 Lock으로 트랜잭션이 완료될 때 까지 유지된다. 일반적으로 UPDATE, DELETE 쿼리가 동작할 때 사용되는 락이다. 배타 락은 Lock이 해제될 때까지 다른 트랜잭션에서 Lock이 걸린 리소스에 접근이 불가하다. 배타 락은 다른 락들과 호환되지 않아 다른 트랜잭션에서 수행되고 있는 데이터에 대해 접근해 함께 Lock을 설정할 수 없다. 

  •  Lock이 걸려있는 데이터에 대해 Update가 불가능
  • Update가 진행 중인 데이터에 SELECT를 포함한 어떠한 작업 또한 불가능

 

블로킹(Blocking)

블로킹(Blocking)은 Lock 간 경합의 발생으로 특정 작업이 진행되지 못하고 정지한 상태를 의미한다. 공유 락과 배타 락, 배타 락과 배타 락 사이에 경합이 있을 때 블로킹이 발생할 수 있다. 블로킹 상황이 해결되기 위해서는 경합이 걸린 트랜잭션을 롤백(rollback)하거나 commit(완료)되어야한다. 블로킹을 해결할 방안은 아래와 같은 방법이 있다.

  • SQL 튜닝
  • 트랜잭션의 길이를 길게 정의 X
  • 동일 데이터를 동시에 변경하는 로직을 지양하는 설계
  • lock_timeout을 통해 Lock의 최대 유지 시간 설정

 

참조

https://stackoverflow.com/questions/11837428/whats-the-difference-between-an-exclusive-lock-and-a-shared-lock

http://wiki.hash.kr/index.php/%EB%9D%BD