본문 바로가기
datasource/데이터베이스

[데이터베이스] Lock에 대해서 알아보자 - 기본편

by 사바라다 2020. 10. 29.

안녕하세요. 오늘은 DataBase의 Lock에 대해서 알아보고 정리해보는 시간을 가져보도록 하겠습니다.

DataBase는 데이터를 영속적으로 저장하고 있는 시스템입니다. 이런 시스템은 같은 자원(데이터)에 대해서 동시에 접근하는 경우가 생길 수 밖에 없습니다. 이럴 경우 데이터가 오염 될 수 있는데 그렇게 되지 않도록 데이터의 일관성과 무결성을 유지해야할 필요가 있습니다. 예를 들어 수강신청 시스템에서 1명만이 정원으로 남게되었습니다. 여기서 2사람이 거의 동시에 버튼을 눌렀습니다. 성공은 1명만 되야합니다. 이런 상황에서 DBMS(DataBase Management System)가 사용하는 공통적인 방법이 Lock이라는 것입니다.

Lock

Lock이란 트랜잭션 처리의 순차성을 보장하기 위한 방법입니다. 트랜잭션이란 DB의 나누어지지 않는 최소한의 처리 단위입니다. 트랜잭션에 대해서 모호하시거나 개념의 정립이 필요하시다면 제가 이전에 포스팅한 [데이터베이스] 트랜잭션과 격리성을 먼저 참조하시기바랍니다.

그리고 중요한 것은 DBMS마다 Lock을 구현하는 방식과 세부적인 방법이 다릅니다. 따라서 DBMS를 효과적으로 이용하기 위해서는 해당 DB의 Lock에 대한 이해가 요구됩니다.

Lock의 종류

Lock의 종류로는 공유(Shared) Lock과 베타(Exclusive) Lock이 있습니다. 공유락은 다른 말로 Read Lock이라고 불리며 베타락은 Write Lock이라고도 불립니다.

공유(Shared) Lock

공유 Lock은 데이터를 읽을 때 사용되어지는 Lock입니다. 이런 공유 Lock은 공유 Lock 끼리는 동시에 접근이 가능합니다. 즉, 하나의 데이터를 읽는 것은 여러 사용자가 동시에 할 수 있다라는 것입니다. 하지만 공유 Lock이 설정된 데이터에 베타 Lock을 사용할 수는 없습니다.

베타(Exclusive) Lock

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

Lock의 설정 범위(Level)

Lock의 설정 범위(Level)에 대해서 알아보도록 하겠습니다.

  • 데이터베이스
    • 데이터베이스 범위의 lock은 전체 데이터베이스를 기준으로 lock 하는 것입니다. 즉, 1개의 세션만이 DB의 데이터에 접근이 가능합니다. 해당 기능은 일반적으로는 사용하지 않습니다. 사용하는 때가 있다면 DB의 소프트웨어 버전을 올린다던지 주요한 DB의 업데이트에 사용합니다.
  •  파일
    • 데이터베이스 파일을 기준으로 lock을 설정합니다. 파일 이란 테이블, row 등과 같은 실제 데이터가 쓰여지는 물리적인 저장소 입니다. 해당 범위의 Lock은 잘 사용되지는 않습니다.
  • 테이블
    • 테이블 수준의 Lock은 테이블을 기준으로 Lock을 설정합니다. 이는 테이블의 모든 행을 업데이트 하는 등의 전체 테이블에 영향을 주는 변경을 수행할 때 유용합니다. 즉, DDL(create, alter, drop 등) 구문과 함께 사용되며 DDL Lock이라고도 합니다.
  • 페이지와 블럭
    • 파일의 일부인 페이지와 블록을 기준으로 Lock을 설정합니다. 잘 사용되지는 않습니다.
  •  컬럼
    • 컬럼 기준의 Lock은 컬럼을 기준으로 Lock을 설정할 수 있습니다. 하지만 이 형식은 Lock 설정 및 해제의 리소스가 많이 들기 때문에 일반적으로 사용되지는 않습니다. 지원하는 DBMS도 많지 않습니다.
  • 행(Row)
    • 행 수준의 Lock은 1개의 행(Row)를 기준으로 Lock 설정을 합니다. DML에 대한 Lock으로 가장 일반적으로 사용하는 Lock입니다.

블로킹(Blocking)

블로킹은 Lock간(베타 - 베타, 베타 - 공유)의 경합이 발생하여 특정 Transaction이 작업을 진행하지 못하고 멈춰선 상태를 말합니다. 위에 설명했듯이 공유락 끼리는 블로킹이 발생하지 않지만 베타락은 블로킹을 발생시킵니다. 블로킹을 해소하기 위해서는 이전의 트랜잭션이 완료(커밋 OR 롤백)되어야 합니다. 뒤에 들어온 트랜잭션은 이전 트랜잭션이 마무리되어야 이후 진행이 가능합니다. 이런 경합은 성능에 좋지 않은 영향을 미칩니다. 따라서 경합을 최소화 할 필요가 있습니다.

blocking

DB를 사용하는 프로그래밍을 진행하면서 몇가지 주의사항을 알아보도록 하겠습니다.

  1. 한 트랜잭션의 길이를 너무 길게하는 것은 경합의 확률을 올립니다.
  2. 처음부터 설계할 때 같은 데이터를 갱신하는 트랜잭션이 동시에 수행되지 않도록 해야합니다.
  3. 트랜잭션 격리성 수준을 불필요하게 상향 조정하지 않습니다. (참고 : 트랜잭션 격리성 수준)
  4. 쿼리를 오랜시간 잡아두지 않도록 적절한 튜닝을 진행합니다.

이외에 DBMS에 따라서 lock 대기 시간 등을 설정할 수 있습니다.

교착상태(DeadLock)

교착상태는 두 트랜잭션이 각각 Lock을 설정하고 다음 서로의 Lock에 접근하여 값을 얻어오려고 할 때 이미 각각의 트랜잭션에 의해 Lock이 설정되어 있기 때문에 양쪽 트랜잭션 모두 영원히 처리가 되지않게 되는 상태를 말합니다. 예를 들어 보면, game_master, game_detail 테이블이 있습니다. 트랜잭션 A가 game_master 테이블에 5번 Row를 수정했고 이제 game_detail 테이블에 5번 Row를 이어서 수정하려고 합니다. 동시에 트랜잭션 B는 game_detail 테이블의 5번 Row를 수정하고 이어서 game_master 테이블의 5번 Row를 수정하려고 합니다. 이 경우 트랜잭션 A는 game_master 테이블의 5번 Row에 배타 락을 설정했고 트랜잭션 B는 game_detail 테이블의 5번 Row에 배타 락을 설정하였습니다. 그리고 교차로 트랜잭션 A는 game_detail의 5번 row의 Lock 설정을 하려고 하고 트랜잭션 B는 game_master의 5번 row에 Lock 설정을 하려고 합니다. 하지만 이미 각 row들은 서로다른 트랜잭션에 의해서 배타락 설정이 되어있습니다. 따라서 Lock이 해제되기를 서로 기다립니다. 하지만 이 Lock은 풀리지 않을 서로의 트랜잭션 기다리므로 영원히 풀리지 않을것입니다.

이미지로 나타내면 아래와 같습니다.

deadlock

그래서 교착상태가 발생하면 DBMS가 둘 중 한 트랜잭션에 에러를 발생시킴으로써 문제를 해결합니다. 교착상태가 발생할 가능성을 줄이기 위해서는 접근 순서를 동일하게 하는것이 중요합니다. 즉, 위의 예제라면 프로그래밍을 할 때 game_master를 업데이트 한 후 game_detail을 업데이트 한다와 같은 규칙을 정해 테이블 접근의 교차가 일어나지 않도록 하는것이 중요할 것입니다.

마무리

오늘은 이렇게 DataBase의 Lock에 대해서 알아보는 시간을 가졌습니다.

다음 시간에는 이어서 MySql의 Lock과 Oracle의 Lock을 비교해보는 시간을 가져보겠습니다.

감사합니다.

참조

DBGuide_net+Lock

programmerinterview

stackoverflow_whats-the-difference-between-an-exclusive-lock-and-a-shared-lock

댓글