crossorigin="anonymous"> $(function(){ $('.article_view').find('table').each(function (idx, el) { $(el).wrap('
') }); $('img[alt="N"]').each(function(){ $(this).replaceWith('

N

') }); });

새소식

고수만/필드에서 써먹은 것들

Entity Framework 동시성 충돌의 해결에 대하여 - 트랜잭션의 격리 수준(Isolation Level) (1) -어려움

  • -

https://dogfootsleep.tistory.com/33

 

트랜잭션과 ACID에 대하여

우리는 IT에 대해 공부할 때 트랜잭션이라는 단어를 정말 많이 보게 된다. DB에서도 보고 객체지향언어에서도 보고 그럼 도대체 트랙잭션이란 무엇인가? Transaction 이라는 단어는 ATM이나 데이터

dogfootsleep.tistory.com

 

기본적으로 트랜잭션이란 뜻을 모르겠다면 먼저 해당 글을 읽고 개념을 잡기를 바란다.

 

그리고 DB 락에 대해서 모른다면 https://dogfootsleep.tistory.com/37를 읽고 오길 바란다.

 

우리는 트랜잭션과 DB Lock에 대해서 알게 되었다.

그러면 충돌이 날 수도 있는 트랙잰션들이 있다면 해당 DB에 모두 Lock을 걸면 될까?

 

그렇지 않다. 공유 자원을 공유할 수 있어야 공유 자원으로서의 의미가 있다.

만약 모든 데이터가 하나의 트랜잭션이 접근할 때마다 락이 걸리고 다른 트랜잭션이 아예 

접근 조차 못한다면 우리의 데이터 처리 수준은 기하 급수적으로 떨어질 것이며

트랜잭션이 중요하다고 생각하여 데이터를 처리하는 모든 구간에 걸어버린다면

더더욱 시스템의 처리 능률은 떨어질 것이며 트랜잭션에서 예외가 발생할 경우

복구해야될 데이터의 리소스도 많아질 것이다.

 

따라서 트랜잭션은 가능한 짧을 수록 좋고 필요한 수준의 락을 걸어야한다.

여기서 트랜잭션의 격리수준(Isolation Level)이 나온다.  

 

트랜잭션의 격리 수준(Isolation Level)이란?

동시에 여러 트랜잭션이 처리될 때 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수

있도록 허용할지 말지를 결정하는 것.

 

하나의 트랜잭션이 공유자원에 접근하는 동안 다른 트랜잭션이 아예 접근을 못하게 하는 것이 아니라 Level을

나누어 접근 허용도를 조절하는 것이다.

 

트랜잭션 격리 수준은 어떤게 있을까?

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE

 

MySQL과 Microsoft SQL Server(MSSQL)는 ANSI/ISO SQL 표준에 정의된 4가지 격리 수준을 기본적으로 지원한다.

추가적으로 데이터베이스에 따라 지원하는 다른 레벨이 존재할 수 있으나

보편적으론 이 4가지를 기본으로 지원한다.

 

READ UNCOMMITTED

  • 각 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관 없이 다른 트랜잭션에서 값을 읽을 수 있다.
  • 정합성에 문제가 많은 격리 수준이기 때문에 사용하지 않는 것을 권장한다.
  • 아래의 그림과 같이 Commit이 되지 않는 상태지만 Update된 값을 다른 트랜잭션에서 읽을 수 있다.

 

그렇다면 READ UNCOMMITTED는 문제가 없을까?

  • DIRTY READ현상 발생
    • 트랜잭션이 작업이 완료되지 않았는데도 다른 트랜잭션에서 볼 수 있게 되는 현상
    • ex) A가 데이터 3을 업데이트하는 트랜잭션이 있다.
    • 처음에 3을 더하고 그다음 3을 곱하는 로직이 있다고 가정한다.
    • 그럼 트랜잭션이 끝나면 18로 데이터가 변해있어야 한다.
    • 그러나 Read Uncommitted 레벨로 지정하면 트랜잭션이 끝나기 전(Committed)에 조회가 가능하다
    • 즉 3을 더한 시점 조회를 한다면 데이터가 6나올 것이고 다시 조회하면 18이 나올 것이다.
    • 무결한 데이터 18이 나오지 않으니 결함 있는 데이터를 읽어서 DIRTY READ
    • 그런데 트랜잭션이 중간에 예외가 발생하여 롤백 된다면??!!
  • mssql에는 전체 트랜잭션 레벨을 설정하는 것이 아닌 특정 쿼리의 실행을 도와주는 방법인 "힌트"로써 
    withnolock이 존재한다.

 

READ COMMITTED

  • RDB에서 대부분 기본적으로 사용되고 있는 격리 수준이다.
  • Dirty Read와 같은 현상은 발생하지 않는다.(Committed 된 데이터만 읽을 수 있음으로)
  • 실제 테이블 값을 가져오는 것이 아니라 Undo 영역에 백업된 레코드에서 값을 가져온다.
  • Read Committed는 Committed 되기 전에는 조회가 불가능 한 것이 아니다. Committed 되기 전의 원본 데이터는
    Undo 영역에서 읽어오고 Committed  된 이후에는 바뀐 실제 데이터를 조회할 수 있도록 하는 것이다.

그렇다면 Undo는 무엇인가?

 

GPT A: Undo는 데이터베이스 시스템에서 데이터의 원래 상태로 롤백하는 메커니즘입니다. 트랜잭션 중에 변경된 데이터에 대한 원래의 값이 Undo 로그 또는 버퍼에 저장되며, 트랜잭션이 실패하거나 롤백될 경우 이 Undo 정보를 사용하여 데이터를 원래 상태로 복원합니다.

 

데이터가 실제 DB에 반영되기 전에 원본 데이터를 Undo 영역에 넣고 바뀔 데이터는 쓸 준비를 한다. 트랜잭션 특성상

트랜잭션에서 예외가 발생하면 모든 데이터를 순차적으로 되돌려야하기 때문에 Undo 로그에 원본데이터를 저장하여

다른 트랜잭션이 읽기를 원할 경우 Undo 영역의 데이터를 제공할 수 있다.

 

이는 MVCC(Multi-Version Concurrency Control)과도 연관되어 있지만 나중에 이야기 하기로 하자.

 

그렇다면 READ COMMITTED는 문제가 없을까?

 

  • 트랜잭션1이 Commit한 이후 아직 끝나지 않는 트랜잭션2가 다시 테이블 값을 읽으면 값이 변경됨을 알 수 있다.
  • 하나의 트랜잭션내에서 똑같은 SELECT 쿼리를 실행했을 때는 항상 같은 결과를 가져와야 하는 REPEATABLE READ의 정합성에 어긋난다.
  • UNREPEATABLE READ는 Read Committed에서 나올 수 있는 문제인데, 쉽게 말해 한 트랜잭션 안에서 연속적으로 읽었을 때, 같은 값이 안 나온다는 문제이다. 읽기 성능을 향상 시키기 위해 특정 트랜잭션이 읽고 있는 도중에 Update가 가능하기에 생기는 문제이다. 왜냐하면 Comitted된 값만 읽겠다는 규제만 존재하기 때문 
  • 이러한 문제는 주로 입금, 출금 처리가 진행되는 금전적인 처리에서 주로 발생한다.
    • 데이터의 정합성은 깨지고, 버그는 찾기 어려워 진다.

 

REPEATABLE READ

 

 

따라서 한층 더 엄격한 룰을 추가한다. 특정 트랜잰션이 공유자원을 점유 시, 조회만 가능하다!

 

간단하게 말하자면 위의 UNREPEATABLE READ의 문제를 해결하기 위해 같은 트랜잭션 안에서 재차 반복적으로

읽어도 같은 값이 나올 수 있도록 SharedLock(공유 락)을 거는 것이다. 

 

다른 트랜잭션이 공유자원일 읽는 와중에 Update가 가능하여 문제가 난 것이기에 이를 해결 하기 위해 조회를 할 경우

다른 트랜잭션이 Update를 못하게 하는 것 바로 Repeatable Read이다. 

 

Repeatable Read는 mysql과 mssql 둘 다 있지만 매커니즘이 조금씩 다르다.

 

둘 다 먼저 들어온 트랜잭션이 공유자원을 점유하면 Select는 가능하지만 Update는 불가능 하게 하기에 같은 값을

제공하지만 Mysql은 특정 트랜잭션이 공유자원을 점유 시 버전을 다르게 관리하여 (MVCC) 한 데이터의 변경이

일어나더라도 해당 버전 외부(트랜잭션 밖)에는 보여지지 않는다.

 

그러나 Mssql은 단순히 Update만 블로킹 하고 Insert와 Delete는 블로킹 하지 않는다. 따라서 트랜잭션 안에서 데이터가

추가되거나 삭제되는 데이터가 보일 수 있다.

 

MySQL에서는 트랜잭션마다 트랜잭션 ID를 부여하여 트랜잭션 ID보다 작은 트랜잭션 번호에서 변경한 것만 읽게 된다.

Undo 공간에 백업해두고 실제 레코드 값을 변경한다.

백업된 데이터는 불필요하다고 판단하는 시점에 주기적으로 삭제한다.

Undo에 백업된 레코드가 많아지면 MySQL 서버의 처리 성능이 떨어질 수 있다.

이러한 변경방식은 MVCC(Multi Version Concurrency Control)라고 부른다.

 

MSsql은 MVCC를 지원하지 않고 락 기반으로 격리수준을 유지해준다. 물론 2005 부턴 Snapshot이라는 격리 수준을 사

용하여 MVCC와 유사한 특성을 지원한다고 한다.

 

그렇다면 REPEATABLE READ는 문제가 없을까?

 

  • PHANTOM READ
    • 다른 트랜잭션에서 수행한 변경 작업에 의해 레코드가 보였다가 안 보였다가 하는 현상
    • 이를 방지하기 위해서는 쓰기 잠금을 걸어야 한다.

 

 

SERIALIZABLE

가장 단순한 격리 수준이지만 가장 엄격한 격리 수준

특정 트랜잭션이 점유하는 순간 읽기 및 추가,변경, 삭제가 모두 불가능 하다.

성능 측면에서는 동시 처리성능이 가장 낮다.

 

SERIALIZABLE에서는 PHANTOM READ가 발생하지 않는다.

하지만.. 데이터베이스에서 거의 사용되지 않는다.

너무 엄격하기에 시스템이 데이터를 처리하는데 성능저하가 있을 수 있다.

 

그러나 동시성 충돌 문제를 예방할 수 있기에 중요한 재화관리 신뢰성을 보장할 수 있다.

mysql 과 mssql 모두 지원하며 수정뿐만 아니라 다른 트랜잭션의 읽기까지 잠금하는 것이다.

mysql은 쿼리가 접근하는 특정 행에 대해 잠금이 걸린다. mssql은 인덱스 키를 범위로 잠가버린다.

 

이렇게 SQL에는 4가지의 트랜잭션을 격리하는 레벨이 존재하며

적절하게 고립도를 사용하여 데이터의 신뢰성과 시스템의 처리능력을 끌어올린다.

 

다음 동시성 처리에서 계속...

https://dogfootsleep.tistory.com/40

 

Entity Framework 동시성 충돌의 해결에 대하여

드디어 동시성 해결에 대한 내용이다!이 이야기를 하기 위해서 앞서 많은 내용들을 이야기 하였다.https://dogfootsleep.tistory.com/38 트랜잭션 격리 수준 (Isolation level)https://dog-foot-sleep.tistory.com/34 트랜

dogfootsleep.tistory.com

 

 

트랜잭션의 격리 수준(isolation Level)이란?

트랜잭션과 잠금

Contents