CS/💾 DB

💾 MVCC, 트랜잭션 ( 5 ) (feat. MySQL과 PostgreSQL 비교)

늦은산책 2024. 4. 27. 01:05
해당 내용은 쉬운코드님의 영상을 기반으로 작성되었습니다

🔌 들어가기 앞서

트랜잭션(4)의 마지막 내용에서 read-read 의 상황에서만 데이터가 교류되는 것을 확인하고 그 이외의 상황은 모두 lock으로 인해 접근 할 수 없다는 것을 알았다. 이는 좋지 않은 성능을 나타내기 때문에 해결할 방법으로 MVCC가 있다고 했다.

그에 대해 알아보자

 

🔌 MVCC (Multi Version Concurrency Control)

지금까지 봐왔던것과 달리 훨씬 더 개방적인 모습을 볼 수 있다. 근데 이렇게 그림만 보면 그냥 좀 포용력이 좋아졌다 생각될 뿐 어떻게 작동할지 정확히 어떤 이점이 존재할지 바로 떠오르지 않는다 예시로 가보자

 

♬ 예시

이번예시는 이해하기 힘들겠지만 말로 설명해보고자 한다 ( 나의 이해도 같이 도울겸... )

  • 상황
    • 트랜잭션 1 : x를 읽는다
    • 트랜잭션 2 : x를 50으로 바꾼다.
    • x = 10
  • 진행
    1. 2번이 write_lock을 받고 x를 50으로 전환한다. 이때 write 한 값을 DB에 반영하는 것이 아니라 snapshot에 저장한다. 그리고 commit 하지 않는다.
    2. 1번이 read를 하려고 하는데 기존에는 2번이 write_lock을 갖고 있기 때문에 들어올 수 없었지만 읽을 수 있게 된다. 그리고 1번은 x를 읽는데 이때 DB에 적혀있는 10을 읽는 것이다 2번이 x의 값을 50으로 변경했다는 것은 1번 입장에서는 알수 없다
    3. 2번이 이때 commit 을 진행한다 그로인해 DB의 x는 50이 된다. 그리고 unlock을 한다
    4. 1번이 다시 DB의 x값을 읽는데 이때 그 결과가 Isolation Level에 따라 다르다. 
      • read committed : read 하는 시간을 기준으로 그전에 commit 된 데이터를 읽는다 ▶ x = 50
      • repeatable read : 해당 트랜잭션 시작 시간을 기준으로 그전에 commit 된 데이터를 읽는다. ▶ x = 10
      • serializable
        MySql - MVCC보단 lock으로 동작한다
        Postgre - SSI(Serializable Snapshot Osolation)기법이 적용된 MVCC로 동작한다
      • read uncommitted : MVCC는 committed된 데이터를 읽기 때문에 이 level에서는 보통 MVCC가 적용되지 않는다.

♬ 특징

  • 데이터를 읽을 때 특정 시점을 기준으로 가장 최근에 commit된 데이터를 읽는다
    MySql 에서는 이를 Consistent read 라고 한다
  • 데이터 변화(write) 이력을 관리한다 때문에 추가적인 저장 장치를 사용하게 된다. 
  • read 와 write는 서로를 block 하지 않는다.

 

🔌 Postgre 와 MySql 의 데이터 처리방법의 차이

♬ 1. Lost Update 문제

  • 상황
    • 트랜잭션 1 : x가 y에 40을 이체한다
    • 트랜잭션 2 : x에 30을 입금한다
    • x = 50, y = 10

PostgreSQL ( first - update - win )

  • 두개의 트랜잭션 level이 read committed라면 진행이 이런방식으로 되는데 이는 잘못된 업데이트가 된다. 
  • 이를 해결하기 위해 Postgre는 Isolation Level을 repeatable read 로 변경한다. 

  • 그러면 먼저 commite 된 내용은 입력되고 나중에 실행된 2번은 rollback이 되고 다시 실행된다
  • 이렇게 트랜잭션끼리의 레벨이 달라도 진행이 가능하고 정상적인 결과가 나온다
  • 그렇다면 1번은 read committed이여도 괜찮은가?

  • 보면 똑같은 오류가 발생했다는 것을 볼 수 있다. 그렇다면 역시 Level을 변경해주면 된다.

  • 그러면 이렇게 똑같이 먼저 commit 이 되어버린 2번때문에 1번은 rollback이 되고 이후에 다시 실행하게 되면서 데이터의 일관성이 유지되는 것이다

 

MySQL(Locking Read)

 

  • x를 읽을때 추가적인 lock인 Locking read 라는 기능을 추가해준다. 쿼리문또한 더 진행을 해주어야하는데 예를 들어 Select balance FROM account WHERE id = 'x' FOR UPDATE 이런식으로 작성하게 되는데 여기서 for update 가 중요하다 이로인해 read 에서도 lock을 취득할 수 있게 된다.
  • 또한 독특한 방법이 MySQL은 repeatable이라고 할지라도 commit 된 시점에 데이터를 읽는다. 
  • 즉, 데이터를 read하려고 할때마다 Locking read가 발생하는 것이다.
    • for update 는 read와 write를 locking 한다
    • for share 은 write만 locking 한다.

♬ 2. write skrew 문제

  • 상황
    • 트랜잭션 1 : x와 y를 더해서 x에 쓴다
    • 트랜잭션 2 : x와 y를 더해서 y에 쓴다
    • x = 10, y = 10

  • 정상적으로 작동을 했다면 x=20,y=30 or x=30,y=20이 되어야 하지만 이렇게 값이 변경되어 버린다.

 

MySQL(Locking Read)

  • 똑같이 Locking Read를 사용하면 이 문제를 해결 할 수 있다.

 

 

PostgreSQL ( first - update - win )

  • MySQL에서 1번 트랜잭션이 commit 하는 시점까지는 굉장히 똑같다. 그 뒤부터가 조금 다르다.

  • Postgre는 보다시피 똑같이 for update를 제공하지만 first-update-win의 기능을 사용하기 때문에 위와 같은 결과를 보여주게 된다