개발메모/간단정리

[간단정리] 트랜잭션 격리수준(Isolation Level)

99C0RN 2022. 8. 13. 19:34

개요

트랜잭션 및 트랜잭션 격리수준에 대해 알아보기


요약

트랜잭션 격리 수준
0-LEVEL: READ UNCOMMITTED: 트랜잭션내에서 커밋하지 않은 데이터에 다른 트랜잭션의 접근이 가능
1-LEVEL: READ COMMITTED: 트랜잭션내에서 커밋된 데이터만 다른 트랜잭션이 읽는 것을 허용
2-LEVEL: REPEATABLE READ: 트랜잭션 내에서 한 번 조회한 데이터를 반복해서 조회해도 결과는 동일
3-LEVEL: SERIALIZABLE: 가장 엄격한 격리 수준으로 완벽한 읽기 일관성 모드 제공

부정합 문제
DIRTY READ: 한 트랜잭션에서 처리한 작업이 완료되지 않았음에도 불구하고 다른 트랜잭션에서 볼 수 있게 되는 현상
NON-REPEATABLE READ: 동일한 SELECT 쿼리를 실행했을 때 항상 같은 결과를 보장해야 한다는 "REPEATABLE READ" 정합성에 어긋나는 현상
PHANTOM READ: 한 트랜잭션내에서 동일한 쿼리를 두 번 수행했는데, 첫 번째 쿼리에서 존재하지 않던 유령(Phantom) 레코드가 두 번째 쿼리에서 나타나는 현상


랜잭션(Transaction)?

데이터베이스 트랜잭션(Database Transaction)은 데이터베이스 관리 시스템 또는 유사한 시스템에서 상호작용의 단위이다. 여기서 유사한 시스템이란 트랜잭션이 성공과 실패가 분명하고 상호 독립적이며, 일관되고 믿을 수 있는 시스템을 의미한다.

정의

  • 데이터베이스 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위
  • 데이터베이스 시스템에서 복구 및 병행 수행 시 처리되는 작업의 논리적 단위
  • 한꺼번에 수행되어야 할 일련의 연산


특성(ACID)

  • 원자성(Atomicity): 트랜잭션이 데이터베이스에 모두 반영되던가, 아니면 전혀 반영되지 않아야 한다.
  • 일관성(Consistency): 트랜잭션의 작업 처리 결과가 항상 일관성이 있어야 한다.
  • 독립성(Isolation): 둘 이상의 트랜잭션이 동시에 실행되고 있을 경우, 어떤 하나의 트랜잭션이라도 다른 트랜잭션의 연산에 끼어 들수 없다.
  • 영속성(Durability): 트랜잭션이 성공적으로 완료되었을 경우에 결과는 영구적으로 반영되어야 한다.


트랜잭션은 원자성, 일관성, 지속성을 보장하는데 문제는 격리성입니다. 트랜잭션간에 격리성을 완벽히 보장하려면 동시에 처리되는 트랜잭션을 거의 차례대로 실행을 해야합니다. 하지만 이렇게 처리를 하면 처리 성능이 매우 나빠지게 됩니다. 이러한 문제로 인해 ANSI 표준은 트랜잭션의 격리 수준을 4단계로 나누어 정의하고 있습니다.


트랜잭션 격리 수준(Transaction Isolation Level)

  • Read Uncommitted (레벨 0)
    SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리지 않는 계층
    트랜잭션에 처리중이거나, 아직 Commit되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용합니다.

    발생 가능한 부정합 문제: Dirty Read, Non-Repeatable Read, Phantom Read

    Dirty Read 예시
    A 트랜잭션에서 10번 사원의 나이를 27에서 28로 바꿈. 아직 커밋하지 않음
    B 트랜잭션에서 10번 사원의 나이를 조회 : 결과 28 → 더티 리드(Dirty Read)

    이후, A 트랜잭션에서 문제가 발생해 Rollback 진행(10번 사원의 나이 27)
    B 트랜잭션은 10번 사원이 여전히 28살이라 생각하고 로직을 수행
    이런식으로 데이터 정합성에 문제가 발생하게 됩니다.

  • Read Committed (레벨 1)
    SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리는 계층
    트랜잭션이 수행되는 동안 다른 트랜잭션이 접근할 수 없어 대기하게 됩니다.
    Commit 이 이루어진 트랜잭션만 조회 가능(Dirty Read 부정합 문제 방지)

    발생 가능한 부정합 문제: Non-Repeatable Read, Phantom Read

    Non-Repeatable Read 예시
    B 트랜잭션에서 10번 사원의 나이를 조회 : 결과 27
    A 트랜잭션에서 10번 사원의 나이를 27에서 28로 바꾸고 커밋
    B 트랜잭션에서 10번 사원의 나이를 조회 : 결과 28

    한 트랜잭션에서 동일한 SELECT를 수행했을 때 항상 간튼결과를 반환해야 한다는 Repeatable Read 정합성에 어긋나는 문제가 발생
  • Repeatable Read (레벨 2)
    트랜잭션이 완료될 때까지 SELECT 문장이 사용되는 모든 데이터에 Shared Lock이 걸리는 계층
    트랜잭션이 범위 내에서 조회한 데이터 내용이 항상 동일함을 보장합니다.(Non-Repeatable Read 부정합 문제 방지)
    다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 불가능

    10번 트랜잭션이 500번 사원을 조회
    12번 트랜잭션이 500번 사원의 이름을 변경하고 커밋
    10번 트랜잭션이 500번 사원을 다시 조회 : undo 영역에 백업된 데이터 반환

    즉, 자신의 트랜잭션 번호보다 낮은 트랜잭션 번호에서 변경된(커밋된) 것만 보게 된다.
    모든 InnoDB의 트랜잭션은 순차적으로 증가하는 고유한 트랜잭션 번호를 갖고 있으며, undo 영역에 백업된 모든 레코드는 변경을 발생시킨 트랜잭션의 번호를 포함하고 있다.

    발생 가능한 부정합 문제: Phantom Read

  • Serializable (레벨 3)
    트랜잭션이 완료될 때까지 SELECT 문장이 사용되는 모든 데이터에 Shared Lock이 걸리는 계층
    가장 엄격한 격리 수준으로 완벽한 읽기 일관성 모드를 제공합니다.
    다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 및 입력 불가능

부정합 문제 정리

  • Dirty Read
    - 어떤 트랜잭션에서 아직 실행이 끝나지 않은 다른 트랜잭션에 의한 변경사항을 보게되는 문제
    - 커밋되지 않은 수정중인 데이터를 다른 트랜잭션에서 읽을 수 있도록 허용할 때 발생하는 현상
  • Non-Repeatable Read
    - 한 트랜잭션에서 동일한 SELECT 쿼리를  두 번 수행할 때, 그 사이에 다른 트랜잭션이 값을 수정 or 삭제하면서 동일한 트랜잭션에서 실행된 두 쿼리의 결과가 다르게 나타나는 일관성이 깨지는 문제
    - 한 트랜잭션에서 똑같은 SELECT를 수행했을 때 항상 같은 결과를 반환해야 한다는 Repeatable Read 정합성이 깨짐
  • Phantom Read
    - 한 트랜잭션 안에서 일정 범위의 레코드를 두 번 이상 읽었을 때, 첫번째 쿼리에서는 없던 레코드가 두번째 쿼리에서 나타나는 문제
    - 트랜잭션 중 새로운 레코드 삽입을 허용하기 때문에 발생

격리수준 선택 고려사항

트랜잭션 격리수준에 대한 변경은 동시성/데이터 무결성과 연관되어 있다.

동시성을 증가시키면 데이터 무결성에 문제가 발생하고, 데이터 무결성을 유지하면 동시성이 떨어지게 된다.

트랜잭션 격리수준이 높을 수록 데이터 무결성 및 정합성이 높아지나, 동시성(성능)은 낮아지게 된다.
반대로 격리수준이 낮을 수록 동시성(성능)은 높아지나, 데이터 정합성이 깨지는 여러 부정합문제가 발생할 수 있다.
각 서비스에 특성에 맞게 적절한 격리수준을 선택하여 사용하여야 한다.