분산 데이터
07장: 트랜잭션
트렌젝션은 데이터베이스의 여러문제를 단순화하는 메커니즘으로 채택돼 왔다
트랜젝션은 애플리케이션에서 몇개의 읽기와 쓰기를 하나의 논리적 단위로 묶는 방법이다.
데이터베이스에 접속하는 애플리케이션에서 프로그래밍 모델을 단순화하려는 목적으로 만든것이다
트랜잭션 격리 수준(isolation level)
- READ UNCOMMITTED : 다른 트랜잭션이 커밋하지 않은 데이터를 읽을 수 있다.
- READ COMMITTED : 커밋된 데이터만 읽을 수 있다.
- snapshot isolation : 트랜잭션 시작 시점의 데이터를 읽을 수 있다.
- MVCC(Multi Version Concurrency Control) : 트랜잭션 시작 시점의 데이터를 읽을 수 있다.
- serializable : 트랜잭션을 순차적으로 실행한다.
애매모호한 트랜잭션의 개념
현대의 거의 모든 관계형 데이터베이스와 일부 비관계형 데이터베이스는 트랜젝션을 지원한다
- ACID의 의미
- 원자성(atomicity) : 트랜잭션은 성공하거나 실패하거나 둘 중 하나다.
- 원자성은 동시성과 관련이 없다
- abortablility : 트랜잭션을 중단하고 처음부터 다시 시작할 수 있는가?
- 일관성(consistency) : 트랜잭션은 일관성 있는 상태를 유지한다. 트랜잭션 실행 전후에도 데이터베이스는 일관성 있는 상태를 유지해야 한다.
- 복제일관성(replication consistency)
- 최종일관성(eventual consistency)
- 일관성 해싱(consistency hashing)
- 선형일관성(linearizability)
- 데이터베이스가 좋은 상태에 있어야 된다
- 격리성(isolation) : 트랜잭션은 다른 트랜잭션의 연산에 끼어들 수 없다. 트랜잭션 실행 중에 다른 트랜잭션의 연산이 끼어들 수 없다.
- 동시에 실행되는 트랜잭션은 서로 격리된다
- 직렬성(serializability)
- 지속성(durability) : 트랜잭션을 성공적으로 완료했으면 그 결과가 항상 기록되어야 한다. 시스템에 문제가 발생하더라도 트랜잭션의 결과는 보존되어야 한다.
- BASE(Basically Available, Soft state, Eventual consistency) : 일관성을 희생하고 유연성을 확보하는 방법이다. 데이터베이스가 항상 일관된 상태를 유지하지 않아도 되기 때문에 데이터베이스에 장애가 발생하더라도 가용성을 높일 수 있다.
- 원자성(atomicity) : 트랜잭션은 성공하거나 실패하거나 둘 중 하나다.
- 단일 객체 연산과 다중 객체 연산
- 단일 객체 연산 : 트랜잭션은 하나의 객체만 변경한다.
- 경량 트렌젝션(lightweight transaction) : 단일 객체 연산을 지원하는 트랜잭션
- 다중 객체 연산 : 트랜잭션은 여러 객체를 변경한다.
- 다중객체 트랜잭션의 필요성
- 외래키 사용
- 비정규화된 정보를 갱신
- 색인 갱신
- 오류와 어보트 처리
- 오류가 생기면 어보트되고 안전하게 재시도할 수 있어야 된다
- 다중객체 트랜잭션의 필요성
- 단일 객체 연산 : 트랜잭션은 하나의 객체만 변경한다.
완화된 격리 수준
트랜잭션 격리를 제공하여 동시성 문제를 감추려고 함
직렬성 격리(serializable isolation) : 트랜잭션을 순차적으로 실행하는 것처럼 보이게 하는 격리 수준
- 커밋 후 읽기(Read Committed) : 트랜잭션이 커밋한 데이터만 읽을 수 있다.
- 더티 읽기(dirty read) 방지
- 더티 쓰기(dirty write) 방지
- 여러 데이터 베이스의 기본설정
- 스냅숏 격리와 반복 읽기
- 비반복 읽기(nonrepeatable read),읽기 스큐(read skew) : 트랜잭션 안에서 같은 쿼리를 두 번 실행했을 때 결과가 다른 현상
- 스냅숏 격리(snapshot isolation) : 각 트랜잭션은 데이터베이스의 일관된 스냅숏으로부터 읽는다
- 읽는 쪽에서 쓰는 쪽을 차단하지 않고 쓰는쪽에서 읽는 쪽을 차단하지 않는다
- MVCC(Multi Version Concurrency Control) : 트랜잭션 시작 시점의 데이터를 읽을 수 있다.
- 일관된 스냅숏을 보는 가시성 규칙
- 읽기를 실행하는 트랜잭션이 시작한 시점에 읽기 대상 객체를 생성한 트랜젝션이 이미 커밋 상태
- 읽기 대상 객체가 삭제된것으로 표시되지 않음, 삭제 되었지만 읽기 트랜젝션이 시작된 시점에 커밋 되지 않음
- 색인과 스냅숏 격리
- 색인이 객체의 모든 버전을 가리키게 하고 색인 질의가 현재 트랜잭션에서 볼수 없는 버전을 걸러내게 한다
- 가비지 컬렉션이 어떤 트랜잭션에게도 더이상 보이지 않은 오래된 객체 버전을 삭제할때 대응되는 색인도 삭제
- 반복읽기와 혼란스러운 이름
- 반복읽기(repeatable read) : 트랜잭션 안에서 같은 쿼리를 두 번 실행했을 때 결과가 같다
- 오라클에서는 직렬성(serializable)라고 부른다
- sql 표준에서는 스냅숏 격리(snapshot isolation)개념이 없어서 다른이름으로 부른다
- 갱신 손실 방지
- 갱신 손실(loss of updates) : 두 트랜잭션이 동일한 객체를 갱신할 때 마지막에 커밋한 트랜잭션만 반영되고 첫번째 트랜잭션의 갱신 결과는 사라지는 현상
- 갱신 손실 방지
- 원자적 쓰기 연산
- 명시적 잠금
- 갱신 손실 자동 감지
- compare-and-set
- 충돌해소와 복제
- 최종 쓰기 승리(last write wins) : 갱신 손실이 발생하면 마지막에 갱신한 트랜잭션의 결과를 사용한다.
- 쓰기 스큐와 팬텀
- 쓰기 스큐(write skew) : 트랜잭션 안에서 두 객체를 갱신할 때 다른 트랜잭션이 그 사이에 객체를 갱신했을 때 발생하는 현상
- 팬텀(phantom) : 트랜잭션 안에서 같은 쿼리를 두 번 실행했을 때 결과 집합이 달라지는 현상
- 충돌 구체화(materializing conflict)
직렬성
가장 강력한 격리수준이지만 동시성 제어를 위해 가장 비싼 방법이다
- 실제적인 직렬 실행
- 동시성 문제를 피하는 가장 간단한 방법은 동시성을 완전히 제거하는 것
- 직렬로 단일 스레드에서 실행
- 트랜잭션을 스토어드 프로시저 안에 캡슐화 하기
- 스토어드 프로시저의 장단점
- 벤더 마다 제각각 sp용 언어가 따로 있다
- 코드관리가 어렵다, 디버깅이 어렵다
- 데이터베이스 서버는 애플리케이션 서버보다 훨씬 성능에 민감하다(공유자원문제)
- 스토어드 프로시저의 장단점
- 파티셔닝
- 여러 cpu 코어와 여러 노드로 확장하기 위해 데이터를 파티셔닝할수 있다
- 트랜젝션은 단일 파티션내에서만 데이터를 읽고 쓰도록 데이터셋을 파티션 할수 있으면 각각 트렌젝션 스레드를 가질수 있다
- 2단계 잠금(2PL)
- two-phase locking
- 쓰기 트렌젝션 뿐만 아니라 읽기 트랜잭션도 막는다
- 교착상태(deadlock) : 두 트랜잭션이 서로 상대방이 가지고 있는 잠금을 요구하면서 서로 기다리는 상황
- 성능이 약하다
- 팬덤을 막아야 된다(서술잠금)
- 색인범위잠금(index-range locking) 다음키 잠금(next-key locking)
- 직렬성 스냅숏 격리(SSI)
- 직렬성 스냅숏 격리(serializable snapshot isolation)
- 비관적 동시성 제어(pessimistic concurrency control) : 트랜잭션을 실행하기 전에 미리 잠금을 획득하는 방법
- 낙관적 동시성 제어(optimistic concurrency control) : 트랜잭션을 실행하는 도중에는 다른 트랜잭션과 충돌하지 않는다고 가정하고 트랜잭션을 실행한 다음에 충돌이 없었는지 확인하는 방법
- 오래된 MVCC 읽기 감지
- 과거의 읽기에 영향을 미치는 쓰기 감지