Transaction Isolation Level

HunkiKim·2022년 9월 22일
0

Transaction Isolation Level

문제점

Dirty Read

Dirty Read는 다른 트랜잭션에 의해 수정됐지만 아직 커밋되지 않은 데이터를 읽는 것을 말한다.

  • 예시
    1. A트랜잭션에서 10번 사원의 나이를 27살에서 28살로 바꾼다.
    2. 아직 커밋하지 않는다.
    3. B 트랜잭션에서 10번 사원의 나이를 조회한다.
    4. 그러면 아직 커밋하지 않은 28살이 조회된다. -> Dirty Read 발생
    5. A 트랜잭션에서 문제가 발생한 ROLLBACK한다.
    6. B 트랜잭션은 10번 사원이 여전히 28살이라고 생각하고 로직을 수행한다.
      이런식으로 데이터 정합성에 문제가 많으므로, RDBMS 표준에서는 격리수준으로 인정하지도 않는다. (정합성 : 데이터의 값이 서로 일치하는 상태) , (무결성 : 데이터의 값이 정확한 상태)

즉 Dirty Read는 모든 DB에서 허용하면 안된다. 롤백 문제가 있기 때문이다.

Non-Repeatable Read

  • Non-Repeatable Read는 한 트랜잭션 내에서 같은 Key를 가진 Row를 두 번 읽었는데 그 사이에 값이 변경되거나 삭제되어 결과가 다르게 나타나는 현상을 말한다.
  • 즉 같은 데이터를 한 트랜잭션 안에서 두 번 읽었는데 이 값이 다른 경우를 말한다. 이 경우 트랜잭션이 동시에 실행되어도 마치 각각 실행되는 것처럼 해야하는 Isolation의 규칙을 위배하게 된다.
  • 예시
    1. B 트랜잭션에서 10번 사원의 나이를 조회한다.
    2. 27살이 조회된다.
    3. A 트랜잭션에서 10번 사원의 나이를 27살에서 28살로 바꾸고 커밋한다.
    4. B 트랜잭션에서 10번 사원이 나이를 다시 조회한다.
    5. 28살이 조회된다. -> Non-Repeatable Read 발생

즉 쿼리를 2 번 이상하는 곳에서 중간에 데이터 값이 바뀌면 다른 데이터값을 쓰게 되는 데이러면 발생하는 현상이다. 이 친구도 업데이트를 읽어버린다면 두 곳에서 50,150만원을 넣었는데 150만원을 잃어서 50만원만 입금될 수 있다.

Phantom Read

  • 한 트랜잭션 내에서 같은 쿼리를 두 번 수행헀는데, 첫 번째 쿼리에서 없던 유령(Phantom) 레코드가 두 번째 쿼리에서 나타나는 현상을 말한다.
  • 즉 한 트랜잭션에서 2번 read를 할 때 갑자기 새로운 값이 추가되서 read가 되는 경우를 말한다.
  • 예를 들어 100 > id 인 쿼리를 날렸을 때 같은 트랜잭션 내에서 처음에넌 아이디가 101, 102, 103만 읽혔는데 두 번째에서 다른 트랜잭션에서 idrk 104인 데이터가 추가돼서 101, 102, 103, 104를 읽는 경우이다.
  • 어쨋든 쿼리를 2 번 이상 하는 중간에 데이터 값이 바뀌는 로직이 Non-Repeatable Read와 헷갈릴 수 있지만, Phantom Read는 다건을 요청하는 것에 대해서 데이터의 값이 변경되는 것이다.

위의 경우들이 모두 발생하지 않게 만들 수 있지만 그러면 제약사항이 많아져서 동시 처리 가능한 트랜잭션 수가 줄어들어 결국 DB의 전체 처리량(throughout)이 하락하게 된다. 그래서 일부 이상한 현상은 허용하는 몇 가지 level을 만들어서 사용자가 필요에 따라서 적절하게 선택할 수 있도록 Isolation Level을 만들게 되었다.

Transaction Isolation

  • 트랜잭션 격리수준(isolation level)이란 동시에 여러 트랜잭션이 처리될 때, 트랜잭션끼리 얼마나 서로 고립되어 있는지를 나타내는 것이다. 즉 격리성에서 처리하는 것이다.
  • 단계에는 Read uncommitted, Read committed, Repeatable read serializable이 있고 뒤로 갈수록 고립성과 무결성은 좋아지지만, 동시성이 떨어진다.

Read Uncommitted

  • 트랜잭션에서 처리 중인 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용한다.
  • Dirty read, Non-repatable read, Phantom read 문제점이 발생한다. 즉 다 허용한다.

Read committed

  • 트랜잭션이 커밋되어 확정된 데이터만 다른 트랜잭션이 읽도록 허용한다.
  • 커밋 되지 않은 데이터에 대해서는 실제 DB 데이터가 아닌 Undo 로그에 이전 데이터를 가져오는 방식이다.
  • Non-repeatable read, Phantom read 문제가 발생한다.
  • oracle에서 기본으로 사용하는 격리 수준이다.

Repeatable read

  • 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 읽도록 허용한다.
  • "반복가능한 읽기"라는 이름에서 알 수 있듯이 한 트랜잭션 내에서 읽기가 여러 번 발생해도 같은 값을 가져온다.
  • 즉 트랜잭션 수행중 다른 트랜잭션에 의해 데이터가 변경되어도 변경 전의 데이터로 읽는다.
  • 트랜잭셔내에서 삭제, 변경에 대해서 Undo 로그에 넣어두고 앞서 발생한 트랜잭션에 대해서는 실제 데이터가 아닌 Undo 로그에 있는 백업데이터를 읽게 한다.
  • Phantom read 문제만 발생한다.
  • mysql에서 기본으로 사용하는 격리 수준

Serializable read

  • 트랜잭션 내에서 쿼리를 두 번 이상 수행할 때, 첫 번째 쿼리에 있던 레코드가 사라지거나 값이 바뀌지 않음은 몰론 새로운 레코드가 나타나지도 않도록 하는 설정이다.
  • 읽기 작업에도 락을 걸어 다른 트랜잭션이 접근하지 못하게한다.
  • 어떤 문제도 발생하지 않지만 동시성이 떨어진다.

트랜잭션 병행제어(Concurrency Control)

병행제어란 여러개이 트랜잭션이 실행될 때 트랜잭션들이 데이터베이스의 일관성을 파괴하지 않고 다른 트랜잭션에 영향을 주지 않으면서 트랜잭션을 제어하는 것을 의미한다. 일관성(Consistency)란 제약을 지키는 것을 의미한다.

병행 제어를 하지 않으면 일어나는 현상

  1. 분실된 갱신 (Dirty Write) : 두 개의 트랜잭션이 같은 데이터에 대해서 동시에 갱신 작업을 하면 하나의 갱신 작업이 분실되는 경우이다.
  2. 모순성 (Non-repeatable Read) : 한 개의 트랜잭션 작업이 갱신 작업을 하고 있는 상태에서 또 하나의 트랜잭션이 같은 작업 구역에 침범하여 작업하게 되어 데이터베이스의 일관성을 해치는 경우이다.
  3. 연쇄복귀 (Cascade Rollback) : 같은 자원을 사용하는 두 개의 트랜잭션 중 한 개의 트랜잭션이 성공적으로 일을 수행하였다 하더라도 다른 트랜잭션이 처리하는 과정에서 실패하게 되면 두 개의 트랜잭션 모두가 복귀되는 현상이다.
  4. 비완료 의존성 (Dirty Read) : 한 개의 트랜잭션이 수행과정에 실패하였을 때 , 이 트랜잭션이 회복되기 전에 다른 트랜잭션이 수행 결과를 참조하는 현상이다.
  5. Phantom Read : 동일 트랜잭션에서 동일한 대상을 여러 번 읽을 때 그 사이에 새로운 값(Phantom Tuple)이 삽입되어 값이 변경된다.

병행제어 기법

  1. 로킹 (Locking)
    • 트랜잭션이 어떤 데이터에 접근하고자 할 때 로킹을 수행하며 로킹을 한 트랜잭션만이 로킹을 해제할 수 있다.
    • 로킹된 데이터에는 다른 트랜잭션이 접근 불가하다.
    • 로킹 단위 : 필드, 레코드, 파일, 데이터베이스 모두 로킹될 수 있다.
    • 로킹 단위가 클 경우 : 관리하기 용이하다.(로킹 오버헤드 감소), 하지만 동시성 수준이 낮아진다.
    • 로킹 단위가 작을 경우 : 동시성 수준이 높아지지만 관리가 까다롭다. (로킹 오버헤드 증가)
  2. 2단계 로킹 규약 (Two-Phase Locking Protocol)
    • Lock과 Unlock이 동시에 이루어지면 일관성이 보장되지 않으므로 Lcok만 가능한 단계와 Unlock만 가능한 단계를 구분해야 한다.
    • 확장 단계 : 새로운 Lock은 가능하고 Unlock은 불가능하다.
    • 축소 단계: Unlock은 가능하고 Lock은 불가능하다.
    • 직렬 가능성을 보장한다.
    • 교착상태가 발생할 수 있다.
  3. 타임스탬프(Time Stamp)
    • 데이터에 접근하는 시간을 미리 정하여 정해진 시간의 순서대로 데이터에 접근하며 수행한다.
    • 장점 : 직렬가능성을 보장하며 시간을 나눠 사용하기 때문에 교착상태가 발생하지 않는다.
    • 단점 : 연쇄복귀를 초래할 수 있다.
  4. 낙관전 병행제어 (Optimistic Concurrency Control)
    • 트랜잭션 수행 동안은 어떠한 검사도 하지 않고, 트랜잭션 종료시에 일괄적으로 검사한다.
    • 트랜잭션 수행 동안 그 트랜잭션을 위해 유지되는 데이터 항목들의 지역 사본에 대해서만 갱신한다.
    • 트랜잭션 종료 시에 동시성을 위한 트랜잭션 직렬화가 검증되면 일시에 DB로 반영한다.
  5. 다중 버전 병행제어(Multi-version Concurrency Control)
    • 여러 버전의 타임스탬프를 비교하여 스케줄상 직렬가능성이 보장되는 타임스탬프를 선택한다.
    • 충돌이 발생할 경우 복귀를 수행한다. 연쇄 복귀 발생 가능성이 있다.

next-key lock (mysql에서 Phantom Read를 방지하는 방법)

락의 종류

  • Record lock(레코드 락) : 단일 인덱스 레코드의 락.
  • Gap lock(갭 락) : 인덱스 레코드 사이의 갭의 락, 선두 인덱스 레코드의 앞이나 말미 인덱스 레코드의 뒤으 갭의 락이다.
  • Next-key lock(넥스트 키 락) : 레코드 락과 이 레코드 직전의 갭 락의 조합이다.

원리

즉 next Key lock이란 gap lock을 걸어 해결하는 것인데 예를 들어 92, 102가 있다고 할 때 100이상의 쿼리를 한다고 해보자. 그러면 92~102사이에 락을 걸어 들어와도 추가되지 않고 102번 이후 범위도 몰론 전체 락을 한다. 그 사이에 108이라는 숫자가 있으면 102~108사이만 갭락을 한다. 이런식으로 gap lock을 잠금하여 팬텀리드가 발생하지 않도록 한다.

SNAPSHOT ISOLATION

우리는 여태까지 위의 문제들을 바탕으로 ISOLATION LEVEL을 정의 했지만 얘는 Conccurency Control이 어떻게 동작할지를 바탕으로 정의된 Isolation이다.

즉 스냅샷을 두고 데이터를 가져온다. 즉 데이터를 읽는 시간을 기준으로 데이터를 관리를 한다. 그리고 한 트랜잭션이 작업을 하던 도중에 다른 트랜잭션이 종료가 되어도 시작했던 시점에 기반한 정보들로 계산을 하게 된다. 그리고 같은 데이터에 대해서 write를 할 때 원래라면 lost update가 발생하겠지만 먼저 커밋된 트랜잭션만 인정해주기 때문에 롤백된다. 그러면 스냅샷의 내용들이 폐기된다.

이런 방식은 MVCC(multi version concurrency control)라고 한다.

0개의 댓글