반응형
이번 글은 데이터 중심 어플리케이션 설계 도서의 트랜잭션의 내용을 정리하였습니다.
들어가기 전에
데이터 시스템의 여러 가지 문제
- 데이터베이스 포스프퉤어나 하드웨어는 언제라도 실패할 수 있음
- 애플리케이션은 언제라도 죽을 수 있음
- 네트워크가 끊기면 애플리케이션과 데이터베이스의 연결이 갑자기 끊기거나 데이터베이스 노드 사이의 통신이 안될 수 있음
- 여러 클라이언트가 동시에 데이터베이스에 쓰기를 실행해서 다른 클라이언트가 쓴 내용을 덮어쓸 수 있음
- 클라이언트가 부분적으로만 갱신돼서 비정상적인 데이터를 읽을 수 있음
- 클라이언트 사이의 경쟁 조건은 예측하지 못한 버그를 유발할 수 있음
트랜잭션이란?
- 위와 같은 문제를 단순화하는 매커니즘으로 채택
- 애플리케이션에서 몇 개의 읽기와 쓰기를 하나의 논리적 단위로 묶는 방법
- 한 트랜잭션 내의 모든 읽기와 쓰기는 한 연산으로 실행
- 데이터베이스에 접속하는 애플리케이션에서 프로그래밍 모델을 단순화
- 안정성 보장 ( safety guarantee )
애매모호한 트랜잭션의 개념
- 비관계형 데이터베이스 중 다수는 트랜잭션을 완전히 포기하거나 과거에 인식되었던 것보다 훨씬 약한 보장을 의미하는 단어로 재정의
- 대규모 시스템이라도 높은 성능과 고가용성을 유지하려면 트랜잭션을 포기해야 한다는 의미로 재해석
ACID의 의미
원자성 ( Atomicity )
- 더 작은 부분으로 쪼갤 수 없는 무언가를 가리킴
- 다중 스레드 프로그래밍에서 한 스레드가 원자적 연산을 실행한다면 다른 스레드에서 절반만 완료된 연산을 관찰 불가
- 연산을 실행하기 전이나 후의 상태만 읽을 수 있음
- 여러 쓰기 작업이 하나의 원자적인 트랜잭션으로 묶여 있어 처리 도중 결함이 있다면 모든 쓰기는 어보트 처리
- 어떤 것도 변경하지 않았음을 알 수 있으므로 안전하게 재시도 가능
일관성 ( Consistency )
- 데이터에 관한 불변식 ( invariant )
- 트랜잭션에서 실행된 모든 쓰기가 유효성을 보존한다면 불변식이 항상 만족된다는 확신
- 애플리케이션의 불변식 개념에 의존적이고 트랜잭션을 올바르게 정의하는 것은 애플리케이션의 책임
- 데이터베이스는 불변식을 위반하는 잘못된 데이터를 쓰지 못하도록 막을 수 없음
- 일관성은 애플리케이션의 속성, 원자성, 격리성, 지속성은 데이터베이스의 속성
격리성 ( Isolation )
- 클라이언트들이 동일한 데이터베이스의 레코드에 접근하여 동시성 문제(경쟁 조건)를 격리
- 데이터베이스는 여러 트랜잭션이 동시에 실행됐더라도 커밋됐을 때의 결과가 순차적으로 실행했을 때의 결과와 동일하도록 보장
- 성능 손해로 현실에서는 거의 사용하지 않음
- 스냅숏 격리 사용
지속성 ( Durability )
- 데이터베이스의 목적은 데이터를 읽어버릴 염려가 없는 안전한 저장소를 제공
- 트랜잭션이 성공적으로 커밋됐다면 하드웨어 결함이 발생해도 기록된 데이터는 손실되지 않도록 보장
- 일반적으로 하드디스크나 SSD 같은 비휘발성 저장소에 기록
단일 객체 연산과 다중 객체 연산
ACID에서 원자성과 격리성은 클라이언트가 한 트랜잭션 내에서 여러 번의 쓰기를 하면 데이터베이스가 어떻게 해야하는가?
원자성
- 부분 실패에 대한 걱정이 없음
- 한 트랜잭션에서 쓰기 후 오류가 발생하는 경우 Abort 처리
격리성
- 동시에 실행되는 트랜잭션들은 서로 방해할 수 없음
- 다중 객체 트랜잭션은 데이터의 여러 조각이 동기화된 상태로 유지되어야 할때 필요
- 다중 객체 트랜잭션은 읽기 연산과 쓰기 연산이 동일한 트랜잭션에 속하는지 알아낼 수단이 있어야 함
관계형 데이터베이스
- TCP 연결 기반으로 작동
- 연결 내에서
BEGIN TRANSACTION
문과COMMIT
문 사이의 모든 것은 같은 트랜잭션에 속함
비관계형 데이터베이스
- 연산을 묶는 방법이 없는 경우가 많음
- 다중 객체 API가 있더라도 어떤 키에 대한 연산은 성공하고 나머지 키에 대한 연산은 실패해서 데이터베이스가 부분적으로 갱신된 상태가 있을 수 있음
단일 객체 쓰기
- 여러 클라이언트에서 동시에 같은 객체에 쓰려고 할 때 갱신 손실을 방지하므로 유용
read-modify-write
,compare-and-set
로 예를 들 수 있음
다중 객체 트랜잭션의 필요성
- 관계형 데이터 모델에서 테이블의 레코드는 종종 다른 테이블의 레코드를 참조하는 외래 키를 갖는데, 이 때 참조가 유효한 상태로 유지되도록 보장 ( 만약 보장되지 않는다면 데이터가 비정상 적으로 생성될 우려가 있음 )
- 비정규화된 정보를 갱신할 때는 한 번에 여러 문서를 갱신이 필요한데 트랜잭션은 이런 상황에서 비정규화된 데이터가 동기화가 깨지는 것을 방지하는 데 유용
- 보조 색인이 있는 데이터베이스에서 값을 변경할 때마다 색인도 갱신 필요할 경우 트랜잭션 관점에서 색인은 서로 다른 데이터베이스 객체이기 때문에 트랜잭션의 격리성이 없으면 문제가 발생
- 원자성이 없으면 오류 처리가 복잡해짐
- 격리성이 없으면 동시성에 문제 발생
오류와 Abort 처리
트랜잭션의 핵심 기능은 오류가 생기면 Abort 되고 안전하게 재시도 할 수 있음 but
완벽하지는 않음
- 트랜잭션이 성공했지만 서버가 클라이언트에게 성공을 알리기 전 네트워크 장애가 발생한다면 클라이언트는 재시도를 요청할 것이고 이는 곧 중복처리로 이어짐
- 오류가 과부하 때문이라면 트랜잭션 재시도는 문제 개선이 아닌 악화로 발전, 과부화 관련 오류가 발생한다면 재시도 횟수를 제한, 백오프, 재시도가 아닌 다른 처리 등으로 풀어야 함
- 일시적인 오류만 재시도할 가치가 있고 영구적인 오류에 대해서는 재시도는 피해야함
- 트랜잭션이 데이터베이스 외부에도 부수 효과가 있다면 트랜잭션이 어보트될 때도 부수 효과에 대한 처리가 필요
완화된 격리 수준
- N개의 트랜잭션이 동일한 데이터에 접근하지 않으면 안전하게 병렬 실행될 수 있음
- N개의 트랜잭션이 동일한 데이터에 접근한다면 동시성 문제가 발생할 수 있음
동시성 문제
- 다른 트랜잭션에서 동시에 변경한 데이터를 읽거나 변경하려할 때 발생
- 이론적으론 트랜잭션 격리를 통해 애플리케이션에서 동시성 문제를 감출 수 있음
- 직렬성 격리를 통해 여러 트랜잭션들이 직렬적으로 실행되도록 함
but
직렬성 격리는 성능 비용이 존재하고 일부 데이터베이스는 그 비용을 지불하지 않음 - 비용을 지불하지 않는 데이터베이스는 완화된 격리 수준을 제공하고 이런 격리성 수준은 이해하기 어려울 뿐더러 버그를 발생함
내용이 길어 다음 글에서 트랜잭션의 완화된 격리수준에 대해서 정리해보겠습니다.
반응형
'Study' 카테고리의 다른 글
대규모 시스템 설계 - 채팅 시스템 설계 (1) | 2021.12.07 |
---|---|
MongoDB 특징과 쉘 사용에 대해서 알아보자 - 1 (0) | 2021.06.08 |