Postgresql의 vacuum를 학습히며 정리한 내용 중, 다중 사용자 환경에서의 Database 관리 기법 중 하나인 MVCC에 대하여 정리해본다.
MVCC 관리 기법은 DB Engine의 종류에 따라 다르기 떄문에, Oracle, MySQL, Postgresql의 MVCC 동작을 이해하기 위한 간단한 포스팅이다.

Concurrency Control, 동시성 제어란?

MVCC를 이해하기 전, 왜 Database에서 동시성 제어를 필요로 하는지 간단하게 알아보자.

Concurrency Control : 다중 사용자 환경에서 여러 트랜잭션(Transaction)이 순차적으로 실행되기 위해, 트랜잭션을 직렬화해 수행하는 것

mvcc1

동시성 제어의 목적

  • 트랜잭션의 직렬성 보장(순차적 트랜잭션 수행)
  • 공유도 최대, 응답 시간 최소, 시스템 활동의 최대 보장
  • 데이터의 무결성 및 일관성 보장

동시성 vs 일관성(Consistency)

트랜잭션의 4가지 속성(ACID) 중 일관성(Consistency)은 트랜잭션이 실행, 완료가 되면 일관성이 Database 상태로 유지하는 것을 의미한다.
다르게 말하면, Database를 구성하는 규칙들이 트랜잭션이 수행되어도 유지가 되어야 한다는 것.

동시성과 일관성은 트레이드 오프(Trade-Off)의 관계에 있는데, 관계는 다음과 같다. 동시성↑, Lock↓ → 일관성↓
일관성↑, Lock↑ → 동시성↓

결국, 동시성 제어의 궁극적인 목표는 동시에 실행되는 트랜잭션의 갯수를 최대화(동시성↑)하면서 입력, 수정, 삭제, 검색 시 데이터 무결성이 유지되도록(일관성↑) 하는 것.

mvcc2

동시성 제어가 불량(?)할 때

트랜잭션의 동시성 제어가 불량해 DBMS가 정상적으로 동작하지 않을 경우에 갱신 손실, 현황파악오류, 모순성, 연쇄복귀의 문제가 발생할 수 있다.

구분 내용
갱신 손실
(Lost Update)
•트랜잭션들이 동일 데이터를 동시에 갱신할 경우 발생
•이전 트랜잭션이 데이터를 갱신한 후 트랜잭션을 종료하기전에 나중 트랜잭션이 갱신 값을 덮어쓰는 경우 발생
현황파악오류
(Dirty Read)
•트랜잭션의 중간 수행결과를 다른 트랜잭션이 참조함으로써 발생하는 오류
모순성
(Inconsistency)
•두 트랙잭션이 동시에 실행할 때 DB가 일관성이 없는 상태로 남는 문제
연쇄복귀
(Cascading Rollback)
•복수의 트랜잭션이 데이터 공유시 특정 트랜잭션이 처리를 취소할 경우 다른 트랜잭션이 처리한 부분에 대해 취소 불가능

동시성 제어 기법

  1. Locking (락킹) -> 트랜잭션이 데이터에 잠금(lock)을 설정하면 다른 트랜잭션은 해당 데이터에 대해 잠금이 해제(unlock)될 때까지 접근/수정/삭제가 불가
  2. Timestamp Ordering Protocol (TSO) -> 트랜잭션마다 고유한 타임스탬프를 부여하여 실행 순서를 관리
  3. Optimistic Concurrency Control (OCC) -> 트랜잭션 수행 도중에는 잠금을 사용하지 않고, 커밋 시에 충돌을 감지하고 처리
  4. Multi-Version Concurrency Control (MVCC)

Multi-Version Concurrency Control(MVCC), 다중 버전 동시성 제어

Multi-Version Concurrency Control은 DBMS가 다중 사용자 환경에서 여러 트랜잭션들을 동시에 실행할 수 있도록 하는 기법이다.
Oracle, Mysql, Postgresql, 다른 DB엔진의 MVCC 동작 방식이 모두 다르지만, 기존 데이터 항목을 새로운 데이터가 덮어쓰는 대신, 데이터 항목의 새로운 버전을 생성한다는 유사한 점이 있다.

mvcc3

Oracle의 MVCC Workflow 예시

mvcc4

Oracle의 MVCC의 핵심은, CR블록을 생성한 후, UNDO(Rollback) 블록의 Transaction을 불러와 CR블록을 UNDO한 뒤, Transaction이 진행된다.

  1. 쿼리 SCN 90
    • Transaction SCN 90이 발행
  2. CR Cloning
    • Consistent-Read블록(SCN100)을 Copy한다.
  3. UNDO적용
    • UNDO블록에 적용된 SCN 90까지의 Log를 추적해, CR블록의 상태 UNDO(Rollback)
  4. UNDO 적용 후 블록 SCN
    • CR블록의 SCN을 100에서 90으로 변경

참고 : 트랜잭션(Transaction)를 식별하기 위한 XID가 있으며, Oracle에서는 System Change Number(SCN)을 사용한다. Isolation 레벨에 따른 트랜잭션 제어 방법에 트랜잭션 ID(XID)가 사용되며, 트랜잭션 시간 순서대로 할당되는 유일 값, 고유번호의 역할을 한다.

MySQL의 MVCC Workflow

MySQL(여기에서는 InnoDB)에서 데이터의 변경이 발생하면, 변경전의 Row 정보는 별도의 공간(Undo segment or Rollback Segment)에 저장 된다. 이러한 Undo Log들은 Rollback 처리, 트랜잭션 Isolation Level에 따른 Consistency 제어에 사용된다.

mvcc5

  1. [transaction 100], [transaction 101], [transaction 102] 는 Oracle의 SCN과 동일한 transaction XID를 의미
  2. UNDO(Rollback) Segment를 사용해 Transaction에 의한 Data 변경분이 저장된다.(undo insert undo update)
  3. Rollback Pointer를 사용해 현재의 transaction XID로부터 UNDO지점까지 Pointer를 따라 transaction rollback한다.

mvcc6

위 그림을 통한 예시는, Mysql(InnoDB)의 Default Isolation Level인 Repeatable Read Isolation Level예시의 적용 예시이다.
Repeatable Read : 자신이 Read를 시작한 시점에서, 마지막 Commit된 데이터 Read.

transaction XID=330 : UPDATE tbl SET age=10 WHERE id=20; COMMIT;
transaction XID=350 : UPDATE tbl SET age=8 WHERE id=20; 
  1. transaction XID가 330 미만인 SELECT쿼리가 XID330 COMMIT문 실행전에 완료 > XID330 UPDATE이전의 age=88 읽음
  2. transaction XID가 330 초과인 SELECT쿼리가 XID330 COMMIT문 실행후에 완료 > XID330 UPDATE이후의 age=8읽음
  3. transaction XID가 350 초과인 SELECT쿼리가 XID350 완료 후 실행 > 머자먹 COMMIT; XID330의 age=8읽음

PostgreSQL의 MVCC

PostgreSQL MVCC의 특징을 간단히 정리하면 다음과 같다.

  • 원본 Tuple(Record) 과 변경된 Tuple을 같은 페이지에 저장 > Record별 transaction XID관리
  • Tuple별로 생성된 시점과 변경된 시점을 기록 및 비교
  • Tuple 내 xmin, xmax라는 메타데이터 field에 기록, 버전 관리
  • xmin > INSERT or UPDATE 시점의 Transaction ID를 가지는 메타데이터
  • xmax > DELETE 시점의 Transaction ID를 가지는 메타데이터

mvcc7

xmin – 
- Insert의 경우 insert된 신규 Tuple의 xmin에 해당 시점의 Transaction ID가 할당되고 
- UPDATE의 경우 update된 신규 Tuple의 xmin에 해당 시점의 Transaction ID가 할당됩니다.

xmax –
- Delete의 경우 변경되기 이전 tuple의 xmax에 해당 시점의 Transaction ID가 할당됩니다. 
- UPDATE의 경우 변경되기 이전 Tuple의 xmax와 update된 신규 Tuple의 xmin에는 해당 시점의 Transaction ID가 할당되고, update된 신규 Tuple의 xmax에는 NULL이 할당됩니다.

PostgreSQL_MVCC

xmin xmax value
2010 2020 AAA
2012 0 BBB
2014 2030 CCC
2020 0 ZZZ

[Transaction 2015]> ‘AAA’, ‘BBB’, ‘CCC’를 조회 > ‘ZZZ’는 xmin이 2020으로 조회 불가능 [Transaction 2021]> ‘BBB’, ‘CCC’, ‘ZZZ’를 조회 > ‘AAA’는 xmax가 2020, DELETE가 된 시점 2020값이 xmax [Transaction 2031]> ‘BBB’, ‘ZZZ’를 조회 > ‘AAA’, ‘CCC’는 Transaction 2020, Transaction 2030에서 DELETE, 조회 불가능

Reference