해당 내용은 쉬운코드님의 영상을 기반으로 작성되었습니다
🔌 들어가기 앞서
전 트랜잭션(4)의 마지막 내용에서 read-read 의 상황에서만 데이터가 교류되는 것을 확인하고 그 이외의 상황은 모두 lock으로 인해 접근 할 수 없다는 것을 알았다. 이는 좋지 않은 성능을 나타내기 때문에 해결할 방법으로 MVCC가 있다고 했다.
그에 대해 알아보자
🔌 MVCC (Multi Version Concurrency Control)
지금까지 봐왔던것과 달리 훨씬 더 개방적인 모습을 볼 수 있다. 근데 이렇게 그림만 보면 그냥 좀 포용력이 좋아졌다 생각될 뿐 어떻게 작동할지 정확히 어떤 이점이 존재할지 바로 떠오르지 않는다 예시로 가보자
♬ 예시
이번예시는 이해하기 힘들겠지만 말로 설명해보고자 한다 ( 나의 이해도 같이 도울겸... )
- 상황
- 트랜잭션 1 : x를 읽는다
- 트랜잭션 2 : x를 50으로 바꾼다.
- x = 10
- 진행
- 2번이 write_lock을 받고 x를 50으로 전환한다. 이때 write 한 값을 DB에 반영하는 것이 아니라 snapshot에 저장한다. 그리고 commit 하지 않는다.
- 1번이 read를 하려고 하는데 기존에는 2번이 write_lock을 갖고 있기 때문에 들어올 수 없었지만 읽을 수 있게 된다. 그리고 1번은 x를 읽는데 이때 DB에 적혀있는 10을 읽는 것이다 2번이 x의 값을 50으로 변경했다는 것은 1번 입장에서는 알수 없다
- 2번이 이때 commit 을 진행한다 그로인해 DB의 x는 50이 된다. 그리고 unlock을 한다
- 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의 기능을 사용하기 때문에 위와 같은 결과를 보여주게 된다
'CS > 💾 DB' 카테고리의 다른 글
💾 동시성 문제를 해결하는 방법 (0) | 2024.04.27 |
---|---|
💾 낙관적 락(Optimistic) 과 비관적 락(Pessimisitic) (1) | 2024.04.27 |
💾 LOCK을 활용한 트랜잭션( 4 ) (1) | 2024.04.26 |
💾 Isolation Level, 트랜잭션 ( 3 ) (1) | 2024.04.23 |
💾 Concurrency control의 기초, 트랜잭션 ( 2 ) (0) | 2024.04.23 |