Skip to content

Latest commit

 

History

History
237 lines (161 loc) · 7.79 KB

File metadata and controls

237 lines (161 loc) · 7.79 KB
Title Category Author
트랜잭션 격리수준(Transaction Isolation Level)
DB
Jung

트랜잭션 격리수준은 동시에 여러 트랜잭션이처리 될 때, 트랜잭션끼리 얼마나 서로 고립되어 있는지를 나타내는 척도.


Dirty Read


commit 되지 않은 변화를 읽음

  • 트랜잭션1은 x에 y를 더하는 로직
  • 트랜잭션2는 y에 70을 쓰는 로직
  • x = 10, y= 20일때
  • 트랜잭션1이 x를 읽어오고
  • 트랜잭션2가 y에 70을 썼다.
  • 그 후 트랜잭션 1이 x에 y를 더하면 x = 80이 되고, y = 70이 된다.
  • 트랜잭션1이 커밋을 마쳤는데, 트랜잭션2가 aborting이 떠서 rollback하면
  • x = 80이되고, y = 20이 되는 무의미한 상태가 된다.

Non - Repeatable Read


같은 데이터의 값이 달라지는 현상

  • 트랜잭션 1은 x를 두 번 읽는 로직
  • 트랜잭션 2는 x에 40을 더하는 로직
  • 현재 x = 10
  • 트랜잭션 1이 x(10)을 읽는다
  • 그 후 트랜잭션 2가 x(10)을 읽고 40을 더한 후 커밋한다 -> x=50
  • 이때 트랜잭션 1이 x를 다시 읽는다 50
  • 그후 트랜잭션 1이 커밋

Phantom Read


없던 데이터가 생기는 경우

  • 트랜잭션1은 v가 10인 데이터를 두 번 읽는 로직
  • 트랜잭션2는 t2의 v를 10으로 바꾸는 로직
현재 DB 상황
t1(..., v= 10)
t2(..., v= 50)
  • 트랜잭션1이 v가 10인 데이터를 읽는다 -> t1
  • 트랜잭션2가 t2의 v를 10으로 변경하고 커밋
  • 다시 트랜잭션1이 v가 10인 데이터를 읽고 커밋 -> t1, t2

이러한 이상 현상들을 모두 막는다면?


이런 이상 현상들을 모두 발생하지 않게 만들 수 있지만
그러면 제약사항이 만아져서 동시 처리 가능한 트랜잭션 수가 줄어들어
결국 DB 전체 처리량(throughput)이 하락하게 된다


Transaction Isolation Level

트랜잭션 격리 수준
transaction isolation

  • Read Uncoimmitted

    • 트랜잭션에서 처리중인 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용
  • Read Committed

    • 트랜잭션이 커밋되어 확정된 데이터만 다른 트랜잭션이 읽도록 허용
    • 커밋 되지 않은 데이터에 대해서 실제 DB 데이터가 아닌 Undo 로그에 있는 이전 데이터를 가져오는 방식
    • Oracle에서 기본적으로 사용하는 격리 수준
  • Repeatable read

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

    • 트랜잭션 내에서 쿼리를 두 번 이상 수행 할 때, 첫 번째 쿼리에 있던 레코드가 사라지거나 값이 바뀌지 않음은 물론 새로운 레코드가 나타나지 않도록 설정
    • 읽기 작업에도 락이 걸려 동시성이 떨어진다.

Isolation Level을 사용하는 이유

애플리케이션 설계자는 isolation level을 통해 전체 처리량과 데이터 일관성 사이에서
특정 상황에 맞게 격리 수준을 고려하여 작성할 수 있다.


또다른 이상현상


Dirty Write


commit 되지 않은 데이터를 write 한다.

  • 트랜잭션1은 x를 10으로 바꾸는 로직
  • 트랜잭션2는 x를 100으로 바꾸는 로직
  • 현재 x는 0
  • 먼저 트랜잭션1은 x를 0에서 10으로 바꾼다 -> x = 10
  • 먼저 트랜잭션2은 x를 10에서 100으로 바꾼다 -> x = 100
  • 이후 트랜잭션1이 aborting이 나서 x를 0으로 rollback 한다 -> x = 0
  • 이후 트랜잭션2에서 aborting이 나서 x를 10으로 rollback 한다 -> x = 10??

rollback시 정상적인 Recovery는 매우 중요하기 때문에 모든 isolation level에서
dirty write를 허용하면 안된다.


Lost Update


  • 트랜잭션1은 x에 50을 더하는 로직
  • 트랜잭션2는 x에 150을 더하는 로직
  • 현재 x = 50
  • 트랜잭션1이 x를 읽는다 -> 50
  • 트랜잭션2가 x를 읽는다 -> 50
  • 트랜잭션2가 x에 150을 더하고 커밋한다 -> x = 200
  • 트랜잭션 1이 읽어온 x(50)에 50을 더하고 커밋한다 -> x = 100

트랜잭션 2번의 업데이트를 트랜잭션 1번이 덮어써버리는 경우이다.


Dirty Read(aborting이 없어도 발생)


  • 트랜잭션1이 x가 y에 40을 이체한다
  • 트랜잭션2가 x와 y를 읽는다
  • 현재 x = 50, y = 50
  • 트랜잭션1이 x를 읽는다 -> x = 50
  • 트랜잭션1이 x를 10으로 변경한다 -> x = 10
  • 이 타이밍에 트랜잭션 2번이 x와 y를 읽고 커밋한다, x = 10, y = 50
  • 트랜잭션1은 y를 읽는다 -> y = 50
  • 트랜잭션1은 y를 90으로 변경하고 커밋한다 -> x = 10, y = 90

트랜잭션 2에서 데이터 정합성이 깨진다


Read Skew


불일치하는 데이터를 읽기

  • 트랜잭션1이 x가 y에 40을 이체한다
  • 트랜잭션2가 x와 y를 읽는다
  • 현재 x = 50, y = 50
  • 트랜잭션2가 x를 읽는다 -> x = 50
  • 트랜잭션1이 x를 10으로, y를 90으로 쭈욱 변경하고 커밋 -> x = 10, y = 90
  • 그 후 트랜잭션2가 y를 읽으면 -> y = 90이 된다.

트랜잭션 2에서 x와 y의 합이 140이 된다...


Write Skew

불일치하는 데이터 쓰기


  • 트랜잭션1은 x에서 80을 인출한다
  • 트랜잭션2는 y에서 90을 인출한다
  • x = 50, y = 50이며 x + y >= 0을 항상 만족해야 한다
  • 트랜잭션1은 x를 읽는다 -> x = 50
  • 트랜잭션1은 y를 읽는다 -> y = 50
  • 트랜잭션2가 x를 읽는다 -> x = 50
  • 트랜잭션2가 y를 읽는다 -> y = 50
  • 트랜잭션1에서 x에서 80을 인출한다 -> x = -30, y = 50
  • 트랜잭션2에서 y에서 90을 인출한다 -> x = 50, y = -40
  • 그후 트랜잭션1과 트랜잭션2가 커밋이 된다.

결과적으로 제약사항을 어기게 되는 상황이 발생한다.



Snapshot Isolation


트랜잭션 진입때 버전을 관리하고 먼저 커밋된 트랜잭션에 대해 인정한다.
이후 커밋된 상태에서 다른 트랜잭션이 쓰기 작업이 발생하게되면 스냅샷이 달라
aborting이 발생하여 rollback 한다.


  • 트랜잭션1은 x가 y에 40을 이체한다
  • 트랜잭션2는 y에 100을 입금한다
  • 현재 x = 50, y = 50
  • 트랜잭션1이 x를 읽는다 -> 스냅샷1 x = 50, y = 50
  • 트랜잭션1이 x에 10을 쓴다 -> 스냅샷1 x = 10, y = 50
  • 이후 트랜잭션2는 y를 읽는다 -> 스냅샷2 x = 50, y = 50
  • 트랜잭션2는 y에 150을 쓴다 -> 스냅샷2 x = 50, y = 150
  • 트랜잭션 2가 커밋하면서 스냅샷2를 반영한다 -> 실제 x = 50, y = 150
  • 트랜잭션1이 y를 읽는다 이때 트랜잭션2가 반영된 것이 아니라 앞서 스냅샷을 읽는다 -> 스냅샷1 x = 10, y = 50
  • 트랜잭션1이 y를 90으로 변경한다 -> 스냅샷 1은 x = 10, y = 90
  • 트랜잭션1이 커밋을 할 때 먼저 커밋된 트랜잭션만 인정해준다.
    • 즉 이때 트랜잭션1에서 abort가 발생된다.
    • 그래서 이때 스냅샷1은 사라진다

MVCC

각 트랜잭션마다 특정 시점에서 스냅샷의 버전을 컨트롤하여 동시성을 제어하는 것