반응형

꾸준히 공부한 것에 다시 정리하면서 보니 이해 했던 부분은 더 쉽게 머리에 남고..

헷갈렸고 몰랐던 부분에 대해서는 정리가 되는 것 같다.


오늘은 Transaction 에 대한 isolation 정리다.



※ isolation level (Transaction 격리 수준)

- 동시에 여러 트랜잭션이 처리될 때, 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있도록 허용할지 말지를 결정

- 격리 수준 :  " Read Uncommitted", "Read Committed", "Repeatable Read", "Serializable"

- 격리 수준이 높아질수록 동시성도 떨어지는 것이 일반적이라고 볼 수 있다.


  1. Read Uncommitted (Dirty Read)
    • 일반적으로 거의 사용하지 않음
    • 변경 내용이 Commit이나 Rollback 여부에 상관 없이 다른 트랜잭션에서 보여짐
    • 어떤 트랜잭션에서 처리한 작업이 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있게 되는 현상
    • Dirty Read를 유발하는 Read Uncommitted는 RDBMS 표준에서는 트랜잭션의 격리 수준으로 인정하지 않을 정도로 정합성에 문제가 많은 격리 수준
    • Dirty read, Non-repeatable read, Phantom read 현상 발생
  2. Read Committed
    • Oracle DBMS에서 기본적으로 사용되고 있는 격리 수준(Shared Lock을 사용)
    • 온라인 서비스에서 가장 많이 선택되는 격리 수준으로 데이터를 변경했더라도 Commit이 완료된 데이터만 다른 트랜잭션에서 조회할 수 있음
    • 어떤 트랜잭션에서 처리한 작업이 commit 이 안되어 있다면 다른 트랜잭션은  undo 영역에 있는 기존 값을 참고하여 보여 주게 됨
    • Read Committed 격리 수준에서도 "Non-Repeatable Read"("Repeatable Read" 가 불가능) 라는 부정합 문제 발생 (Phantom read 현상 발생)
※ Repeatable Read : 하나의 트랜잭션 내에서 동일 select 쿼리를 실행했을 때는 항상 같은 결과를 가져와야 한다는 정합성 정의 (select를 한 후 재차 하는 사이에 데이터 변경이 있어서 동일 select 했을 때 다른 결과가 나오는 것을 뜻함)
이것이 문제될 수 있는 상황은 하나의 트랜잭션에서 동일 데이터를 여러 번 읽고 변경하는 작업이 금전적인 처리와 연결된다면 문제가 발생할 수 있음.(ex-돈을 인출하는 과정에서 돈이 있어서 인출하려는 사이에 금액에 변경이 생겼(다른 곳에서 돈이 인출됨)는데 인출이 가능한 경우 문제가 발생)

 3. Repeatable Read

      • MySQL InnoDB의 기본적으로 사용되는 격리 수준(모든 데이터에 shared lock 이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정이 불가능)
      • Binary Log를 가진 MySQL 의 장비에서는 최소 Repeatable read 격리 수준 이상을 사용해야 함
      • Non-Repeatable Read 부정합이 발생하지 않음
      • InnoDB Storage Engine은 트랜잭션이 Rollback 될 가능성에 대비해 변경되기 전 레코드를 언두(Undo) 공간에 백업해두고 실제 레코드 값을 변경(MVCC-Multi Version Concurrency Control)
      • MVCC를 위해 언두 영역에 백업된 이전 데이터를 이용해 동일 Transaction 내에서는 동일한 결과를 보여줄 수 있도록 보장(Read committed 도 commit 되기 전 데이터를 보여줌)
      • Repeatable Read 와 Read Committed 의 차이는 언두 영역에 백업된 레코드의 여러 버전 가운데 몇 번째 이전 버전까지 찾아 들어가야 하는지에 있음. -> 언두영역에서 특정 트랜잭션 번호의 구간 내에서 백업된 데이터를 보여 줌, 하지만 트랜직션을 종료하지 않으면 무한정으로 언두 영역이 커질 수 있으며 이로 인해 MySQL 성능이 떨어질 수 있음
      • select .. for update 쿼리의 경우 다른 트랜잭션에서 수행한 변경 작업에 의해 레코드가 보였다가 안보였다가 할 수 있다. 이것을 Phantom Read(Phantom row)라고 표현 -> Undo 영역을 lock 할 수 없기 때문에 변경 전 데이터가 아닌 현재 변경된 레코드를 표현 

※ MVCC(Multi Version Concurrency Control)

: 잠금을 사용하지 않는 일관된 읽기를 제공하는 것이 목적


이해를 하기 위해 다시 정리

- Read Uncommitted : 변경되었거나 안된 데이터의 값을 읽음  

- Read Committed(그 이상의 경리 수준 - Repeatable_Read, Serializable) : 변경 전 Undo에 있는 값을 읽음 


-> 이러한 과정을 MVCC라고 표현


 4. Serializable

      • 동시성이 중요한 DB에서는 거의 사용하지 않음
      • 읽기 작업도 공유 잠금(읽기 잠금)을 획득해야만 하며, 동시에 다른 트랜잭션은 그러한 레코드를 변경하지 못하게 됨
      • 한 트랜잭션에서 읽고 쓰는 레코드를 다른 트랜잭션에서는 절대 접근할 수 없음
      • 일반적 DBMS에서 일어나는 "Phantom Read" 라는 문제가 발생하지 않지만 InnoDB 스토리지 엔진에서는 Repeatable Read 격리 수준에서도 이미 Phantom Read가 발생하지 않으므로 굳이 Serializable를 사용할 필요성 없음


 5. Repeatable Read 격리 수준과 Read Committed 격리 수준의 성능 비교

      • Repeatable Read가 Transaction 을 열어 해당 Transaction 에서 모든 테이블의 데이터를 Select 를 한 후 그대로 놔두면 InnoDB의 Undo 영역이 계속 커져서 시스템 테이블스페이스 I/O가 유발되는 경우가 대표적인 예..(성능을 떨어트리는 이유)
      • 해당 문제를 일으키지 않으면 성능상 차이가 거의 없음. Binary log가 활성화된 MySQL 서버에서는 Read Committed 격리 수준을 사용할 수 없음



사실 이해하기 위해서는 Transaction 이 일어나는 현상을 이미지로 설명한 것을 읽으면 빠를 듯 싶다.


또한 MySQL(Repeatable Read) 과 Oracle(Read Committed) 은 격리수준이 다르다.

반응형

+ Recent posts