트랜잭션

‘데이터 중심 애플리케이션 설계’를 읽고 정리하고자함


정리

트랜잭션

  • 애플리케이션이 어떤 동시성 문제와 어떤 종류의 하드웨어와 소프트웨어 결함이 존재하지 않는 것처럼 동작할 수 있게 도와주는 추상층
  • 많은 종류의 오류가 간단한 트랜잭션 어버트로 줄어들고 애플리케이션은 재시도만 하면 됨

트랜잭션은 접근 패턴이 복잡할 때에 상상할 수 있는 잠재적인 오류 상황의 수를 줄일 수 있음

트랜잭션없으면 다양한 오류(프로세스가 죽거나, 네트워크가 끊기거나, 디스크가 꽉 차던가, 예측할 수 없는 동시성 등)에서 다양한 방법으로 일관성이 깨질 수 있음

  • 비정규화된 데이터는 원천 데이터와의 동기화가 깨지기 쉬움

트랜잭션이 없다면 복잡한 상호작용이 데이터베이스에 미치는 영향을 따져보기가 매우 어려워짐

동시성 제어에 대한 내용을 깊게 다루었고, 그 중 널리사용하는 격리 수준 등에 대해 살펴보았음

  • 커밋 후 읽기 ( 또는 반복 읽기 )
  • 스냅숏 격리
  • 직렬성 격리

경쟁 조건의 다양한 예시를 살펴보면서 이 격리 수준들의 특징을 설명함

이상현상과 해결할 수 있는 격리 수준

  • 더티 읽기
    • 한 클라이언트가 다른 클라이언트가 썼지만 아직 커밋되지 않은 데이터를 읽는다.
    • 커밋 후 읽기 또는 그보다 강한 격리 수준은 더티 읽기를 방지함
  • 더티 쓰기
    • 한 클라이언트가 다른 클라이언트가 썻지만 아직 커밋되지 않은 데이터를 덮어쓴다
    • 거의 모든 트랜잭션 구현은 더티 쓰기를 방지함
  • 읽기 스큐(비반복 읽기)
    • 클라이언트는 다른 시점에 데이터베이스의 다른 부분을 본다
    • 이 문제를 막기 위한 해결책으로 트랜잭션이 어느 시점의 일관된 스냅숏으로부터 읽는 스냅숏 격리를 가장 흔히 사용
    • 스냅숏 격리는 보통 다중 버전 동시성 제어(MVCC)를 써서 구현함
  • 갱신 손실
    • 두 클라이언트가 동시에 read-modify-write를 실행
    • 한 트랜잭션이 다른 트랜잭션의 변경을 포함하지 않은 채로 다른 트랜잭션이 쓴 내용을 덮어써서 데이터가 손실
    • 스냅숏 격리 구현 중 어떤 것은 이런 이상 현상을 자동으로 막아주지만, 그렇지 않을 시, 수동 잠금(SELECT FOR UPDATE)이 필요함
  • 쓰기 스큐
    • 트랜잭션이 무언가를 읽고, 읽은 값을 기반으로 어떤 결정을 하고 그 결정을 데이터베이스 쓴다
    • 쓰기를 실행하는 시점에는 결정의 전제가 더 이상 참이 아님
    • 직렬성 격리만 이런 이상현상을 막을 수 있음
  • 팬텀 읽기
    • 트랜잭션이 어떤 검색 조건에 부합하는 객체를 읽는다
    • 다른 클라이언트가 그 검색 결과에 영향을 주는 쓰기를 실행함
    • 스냅숏 격리는 간단한 팬텀 읽기는 막아주지만, 쓰기 스큐 맥락에서 발생하는 팬텀은 색인 범위 잠금처럼 특별한 처리가 필요함

직렬성 격리

완화된 격리 수준은 위의 이상 현상 중 일부만 막아주지만, 나머지는 개발자가 수동으로 처리해야함

그래서 직렬성 격리만 이 모든 문제로부터 보호해줄 수 있음

  • 말 그대로 트랜잭션을 순서대로 실행하기
    • 트랜잭션의 실행 시간이 아주 짧고, 트랜잭션 처리량이 단일 CPU코어에서 처리할 수 있을 정도로 트랜잭션 처리량이 낮다면 아주 간단하고 효과적
  • 2단계 잠금
    • 수십년 동안 직렬성을 구현하는 표준적인 방법이지만, 성능 특성 때문에 사용을 피하는 애플리케이션이 많음
  • 직렬성 스냅숏 격리(SSI)
    • 앞의 방법들의 결점 중 대부분을 피하는 상당히 새로운 알고리즘
    • 낙관적 방법으로 사용해서 트랜잭션을 차된되지 않고 진핼할 수 있게 함
    • 트랜잭션이 커밋을 원할 때, 트랜잭션을 확인해서 실행이 직렬적이지 않다면 어보트시킴

이 챕터는 단일 장비에서의 트랜잭션에 대한 설명이고** 다음 블로그에 분산환경에서의 트랜잭션**을 다룰 예정..


트랜잭션이란?

  • 애플리케이션에서 몇 개의 읽기와 쓰기를 하나의 논리적 단위로 묶는 방법
  • 개념적으로 한 트랜잭션 내 모든 읽기,쓰기는 한 연산으로 실행
  • 트랜잭션은 전체가 성공(커밋)하거나 실패(어보트,롤백)함
  • 실패하면 안전하게 재시도할 수 있어, 오류 처리가 휠씬 단순해짐 = 부분 실패에 대한 고민을 할 필요없음

트랜잭션은 데이터베이스에 접속하는 애플리케이션에서 프로그래밍 모델을 단순화 목적으로 만든 것

  • 이를 통해, 애플리케이션에서 어느 정도의 잠재적인 오류 시나리오와 동시성 문제를 무시할 수 있음
  • 데이터베이스에서 대신 이런 일을 도맡아주기 때문
  • 이를 안전성 보장, safety guarantee라고 함

애매모호한 트랜잭션의 개념

ACID의 의미

트랜잭션이 제공하는 안정성 보장은 흔히 ACID로 알려짐

  • Atomicity(원자성)
  • Consistency(일관성)
  • Isolation(격리성)
  • Durability(지속성)
    • 현실에서는 데이터베이스마다 ACID 구현이 제각각

ACID 표준을 따르지 않는 시스템은 때로 BASE라고 함

  • Basically Available (기본적으로 가용성을 제공하고)
  • Soft state (유연한 상태를 가지며)
  • Eventual consistency (최종적 일관성)

Atomicity(원자성)

원자적이란?

  • 더 작은 부분으로 쪼갤 수 없는 뭔가를 가르킴

멀티 쓰레드 환경에서 한 쓰레드가 원자적 연산을 수행한다면, 다른 쓰레드는 절반만 완료된 연산은 볼 수 없고, 시스템은 연산이 실행 전이나 후의 상태만 있음

  • 즉, 중간 상태에는 머물 수 없음
  • ACID의 맥락에서 볼 때, 원자성은 동시성과 관련이 없음
    • 원자성은 여러 프로세스가 동시에 같은 데이터에 접근하려 할 때 무슨일이 생기는 지 설명하지 않음
    • 이 것은 Isolation(격리성)에서 처리함

ACID의 원자성은 클라이언트가 쓰기 작업 몇개를 실행하려고 할 때, 그 중 일부만 처리된 후 결함이 생기면 무슨일이 생기지는에 대한 설명을 함

  • 즉, 여러 쓰기 작업이 하나의 원자적인 트랜잭션으로 묶여 있어 결함때문에 커밋할 수 없다면, 전체가 어브트 됨

원자성없이 여러 변경을 적용하는 도중에 오류가 발생하면, 어디까지 처리되었고, 어디서부터 시작해야할지 모름

  • 그래서, 원자성은 이런 복잡한 상황을 단순화 시킴!

오류가 생겼을 때, 트랜잭션을 어보트하고, 해당 트랜잭션에서 기록한 모든 내용을 취소하는 능력이 ACID의 원자성의 결정적인 특성

  • 아마도 abortability이 원자성보다 나은 단어겠지만, 원자성이 자주 쓰이긴함

Consistency(일관성)

일관성이라는 단어는 많은 의미로 사용중

  • 복제 일관성(replica consistency)
  • 최종적 일관성(eventual consistency)
    • 비동기식으로 복제되는 시스템에서 발생하는 일관성
  • 일관성 해싱
    • 어떤 시스템들에서 재균현황을 위해 사용하는 파티셔닝 방법
  • CAP정리
    • 일관성이라는 단어는 선형성(linearizability)을 의미
  • ACID
    • 데이터베이스가 “좋은 상태”에 있어야 한다는 것의 애플리케이션에 특화된 개념을 가리킴

ACID 일관성의 아이디어는 항상 진실이어야 하는, 데이터에 대한 어떤 선언, 불변식이 있다는 것

  • 회계 시스템에서 모든 계좌에 걸친 대변과 차변은 항상 맞아떨어져야함
  • 이런 불변식이 유효한 데이터베이스에서 시작하고 트랜잭션에서 실행되는 모든 쓰기가 유효성을 보존한다면 불변식이 항상 만족한다고 확신

일관성의 아이디어는 애플리케이션의 불변식 개념에 의존

  • 일관성을 유지하도록 트랜잭션을 올바르게 정의하는 것이 애플리케이션의 책임
  • 즉, ACID에서의 일관성은 데이터베이스가 아닌, 애플리케이션의 책임
  • 데이터베이스는 불변식을 반하는 데이터를 쓰지 못하게 할 수 없음(외래키나, primary key 조건 제외)

즉,ACID에서 AID는 데이터베이스의 속성인 반면, C는 애플리케이션의 속성

  • 애플리케이션에서 일관성을 달성하기 위해, 데이터베이스의 원자성과 격리성 속성에 기댈 수 있지만, 데이터베이스만으로 되는 것이 아님
  • Joe Hellerstein은 하더와 류터의 논문에서 ACID에서 C는 ‘약어를 만들기 위해 끼어넣’었고, 당시에는 일관성이 중요하게 생각되지 않았다고 함

Isolation(격리성)

동시성 문제를 해결하고자 함

image 데이터베이스에 저장된 카우터를 동시에 증가시키는 두 클라이언트가 있음

  • 증가 연산이 두번 실행되어서 카운터는 42에서 44로 증가해야하지만, 경쟁 조건을 43이 된 상황

ACID에서 격리성은 동시에 실행되는 트랜잭션은 서로 격리된다는 것을 의미

  • 트랜잭션은 다른 트랜잭션을 방해할 수 없음
  • 고전적인 데이터베이스의 교과서에서는 격리성을 직렬성이라는 용어로 공식화함
  • 직렬성은 각 트랜잭션이 전체 데이터베이스에서 실행되는 유일한 트랜잭션인 것처럼 동작할 수 있다는 것을 의미함
  • 즉, 여러 트랜잭션이 동시에 실행됐더라도 트랜잭션이 커밋됐을 때의 결과가 트랜잭션이 순차적으로 실행됐을 때의 결과와 동일하다는 것을 보장

직렬성 격리(serializable isolation)은 성능 손해를 동반함

  • 오라클 11g는 아예 구현조차하지 않음
  • 직렬성이라는 격리 수준이 있지만, 실제로는 직렬성보다 보장이 약한 스냅숏 격리를 구현함

Durability(지속성)

데이터베이스 시스템의 목적은 ‘데이터를 읽어버릴 염려가 없는 안전한 저장소를 제공’하는 것

  • 즉, 지속성은 트랜잭션이 성공적으로 커밋됐다면 하드웨어 결함이나, 데이터베이스가 죽더라도 트랜잭션에서 기록한 모든 데이터는 손실되지 않음을 보장함
  • 단일 노드 데이터베이스의 지속성은 데이터가 하드나 ssd에 저장되었다는 뜻
    • 디스크에 저장된 데이터 구조가 문제가 생길 수 있기 때문에 WAL을 동반함
  • 복제 기능이 있는 데이터베이스의 지속성은 데이터가 다른 노드에 복사됬다는 것을 의미

지속성을 보장하려면, 데이터베이스는 트랜잭션이 성공적으로 커밋됐다고 보고하기 전에 쓰기나 복제가 완료될 때까지 기다려야함