요약
- 트랜잭션에 대한 내용을 이해함
- ACID의 각 의미에 대해 이해함
- 원자성
- 일관성
- 격리성
- 지속성
- ACID의 각 의미에 대해 이해함
- 트랜잭션의 단일 객체 연산과 다중 객체 연산에 대해 이해함.
- 단일 객체 연산에서 트랜잭션의 원자성 격리성이 적용되야 함.
- 다중 객체 연산에서 다른 객체에 대한 쓰기 작업은 코디네이션돼야 함.
메모
7장. 트랜잭션
- 데이터 시스템은 여러 문제가 생길수 있음.
- 소프트웨어, 하드웨어는 언제라도 실패 가능
- 애플리케이션은 언제라도 죽을 수 있음.
- 네트워크 연결이 끊기면, 애플리케이션-데이터베이스 / 데이터베이스 노드간 통신이 안될 수 있음.
- 여러 클라이언트가 동시 쓰기를 하면 내용이 덮어씌어질 수 있음.
- 데이터가 부분 갱신되서 클라이언트가 비정상 데이터를 읽을 수 있음.
- 클라이언트간 경쟁은 예측하지 못한 버그를 유발할 수 있음.
- 시스템이 신뢰성을 지니려면, 위와 같은 결함을 처리해서 전체 시스템의 치명적 장애를 막아야 함.
- 하지만, 내결함성을 갖춘 시스템 구현을 위해 여러 할일이 많음.
- 잘못될 수 있는 모든것에 대해 신중하게 생각하고, 테스트를 여러번 해서 실제로 동작하는지 확인해야 함.
- 수십년 동안 트랜잭션은 이런 문제를 단순화하는 메커니즘으로 채택돼 왔음.
- 트랜잭션은 애플리케이션에서 몇 개의 읽기와 쓰기를 하나의 논리적으로 묶는 방법임.
- 개념적으로 한 트랜잭션 내의 모든 읽기와 쓰기는 한 연산으로 실행됨.
- 트랜잭션은 전체가 성공(커밋)하거나 실패(어포트, 롤백)한다.
- 트랜잭션 실패 시 애플리케이션이 안전하게 재시도 가능함.
- 트랜잭션을 쓰면 애플리케이션 오류 처리를 하기가 훨씬 단순해짐.
- 트랜잭션은 뻔하고 당연한게 아님.
- 데이터베이스에 접속하려는 애플리케이션에서 프로그래밍 모델을 단순화하려는 목적으로 만든것임.
- 트랜잭션을 사용함으로써 애플리케이션에서 어느정도 장재적 오류 시나리오나 동시성 문제를 무시할 수 있음.
- 데이터베이스에서 이 일을 맡아주기 때문(= 안전성 보장(safety guarantee))
- 모든 애플리케이션에서 트랜잭션이 필요하지 않음.
- 때로는 트랜잭션 보장을 완하하거나 쓰지 않는게 이득임
- 성능 향상, 가용성 목적
- 또는, 트랜잭션 없이 안전성 속성이 보장되기도 함.
- 때로는 트랜잭션 보장을 완하하거나 쓰지 않는게 이득임
- 이번 장에서 동시성 제어를 깊게 다룬다.
- 커밋 후 읽기
- 스냅숏 격리
- 직렬성
- 다음과 같은 격리 수준을 어떻게 구현하는지 알아본다.
- 이번 장은 단일, 분산 데이터베이스에 모두 적용되고, 분산 시스템에서만 생기는 난제는 8장에서 다룸
애매모호한 트랜잭션의 개념
- 분산 데이터베이스가 홍보되면서 트랜잭션은 확장성의 안티테제이며, 어떤 대규모 시스템이라도 높은 성능과 고가용성을 유지하려면 트랜잭션을 포기해야 한다고 함.
- 반면, 데이터베이스 벤더에서는 트랜잭션적인 보장은 “값진 데이터”가 있는 “중대한 애플리케이션”에 필수 요구사항이라 주장함.
- 즉, 트랜잭션에 이점과 한계가 있고, 트레이드 오프를 이해하기 위해 정상 운영 상황과 극단적 상황에서의 트랜잭션이 제공하는 보장의 세부사항을 살펴봐야 함.
ACID의 의미
- 트랜잭션이 제공하는 안전성 보장
- 원자성(Atomicity)
- 일관성(Consistency)
- 격리성(Isolation)
- 지속성(Durability)
- 현실에서 데이터베이스마다 ACID 구현이 제각각임.
- 격리성의 의미 주변에는 모호함이 많음.
- 원자성, 일관성, 격리성, 지속성의 정의를 파헤쳐보면서 트랜잭션에 대한 우리의 생각을 다듬을 수 있음.
원자성
- 원자적 : 더 작은 부분으로 쪼갤 수 없는 뭔가를 가리킴
- 다중 스레드 프로그래밍에서 한 스레드가 원자적 연산을 실행한다면, 다른 스레드에서 절반만 완료된 연산을 관찰할 수 없음.
- ACID의 맥락에서, 원자성은 동시성과 관련이 없음.
- 원자성은 여러 프로세스가 동시에 같은 데이터 접근시, 발생하는 일에 대해 설명하지 않음.
- 이 문제는 격리성에서 다룸
- 원자성은 여러 프로세스가 동시에 같은 데이터 접근시, 발생하는 일에 대해 설명하지 않음.
- 오류가 생겼을 때, 트랜잭션을 어보트하고 해당 트랜잭션에서 기록한 모든 내용을 취소하는 능력은 ACID 원자성의 결정적 특성임.
- 여기서 어보트 능력(abortability)이 원자성 보다 더 나은 단어로 볼 수도 있음.
일관성
- 일관성이란 단어는 굉장히 여러 의미로 쓰임
- ACID 일관성의 아이디어는 항상 진실이어야 하는 데이터에 관해, 어떤 선언(불변식(invariant))이 있음을 의미함.
- 일관성 아이디어는 애플리케이션의 불변식 개념에 의존하고, 일관성을 유지하도록 트랜잭션을 올바르게 정의하는 것은 애플리케이션의 책임임.
- 원자성, 격리성, 지속성은 데이터베이스의 속성인 반면, 일관성은 애플리케이션의 속성임.
격리성
- 동일한 데이터베이스 레코드에 접근하면 동시성 문제(경쟁 조건)에 맞닥뜨리게 됨.
- p226 예시 참고
- ACID에서 격리성은 동시에 실행되는 트랜잭션은 서로 격리된다는 것을 의미함.
- 격리성을 직렬성이라는 용어로 공식화 하기도 함.
- 직렬성은, 각 트랜잭션이 전체 데이터베이스에서 실행되는 유일한 트랜잭션인 것처럼 동작할 수 있다는 것을 의미함.
- 데이터베이스는 실제로 여러 트랜잭션이 동시에 실행됐더라도 트랜잭션이 커밋됐을 떄의 결과가 트랜잭션이 순차적으로 하나씩 차례로 실행됐을 때의 결과와 동일하도록 보장함.
- 직렬성 격리(serializable isolation)은 성능 손해를 동반하므로 현실에서는 거의 사용되지 않음.
- 격리성을 직렬성이라는 용어로 공식화 하기도 함.
지속성
- 지속성은 트랜잭션이 성공적으로 커밋됐다면 하드웨어 결함이 발생하거나 데이터베이스가 죽더라도 트랜잭션에서 기록한 모든 데이터는 손실되지 않는다는 보장임.
- 단일 노드 데이터베이스에서 지속성은 일반적으로 데이터가 하드디스크나 SSD 같은 비휘발성 저장소에 기록됐다는 뜻임.
- 보통 디스크에 저장된 데이터 구조가 오염됐을 때, 쓰기 전 로그나 비슷한 수단을 동반함.
- 복제 기능이 있는 데이터베이스에서 지속성은 데이터가 성공적으로 다른 노드 몇 개에 복사됐다는 것을 의미함.
단일 객체 연산과 다중 객체 연산
- 요약하면 ACID에서 원자성과 격리성은 클라이언트가 한 트랜잭션 내에서 여러 번의 쓰기를 하면 데이터베이스가 어떻게 해야 하는지를 서술함.
- 원자성과, 격리성은 한 번에 여러 객체를 변경할 수 있다고 가정함.
- 다중 객체 트랜잭션은 흔히 데이터의 여러 조각이 동기화된 상태로 유지돼야 할 때 필요함.
- ex) 비정규화 : 이메일 읽지 않은 메시지 개수 → emails 테이블 unread_flag 갯수 AND mailboxes 테이블 unread 갯수 → 동기화 돼야 함.
- 격리성이 적용되지 않으면 emails 테이블에는 값이 있지만, mailboxes 가 아직 업데이트 되지 않았는데(즉 커밋되지 않았는데), dirty read 로 읽어버리면, 이메일에는 읽지않은 메시지가 있지만, 읽지 않는 메시지 갯수가 아직 증가되지 않은 상태가 됨.
- 즉, 다른 사용자가 삽입된 이메일과 갱신된 갯수를 모두 보거나 모두 보지 못하게 해서 일관성이 꺠지지 않게 만들어 줘야 함.
- 원자성이 적용되지 않으면 위의 비정규화된 필드들이 동기화 되지 않을 수 있음.
- 이메일 insert, 메일 박스 update 두 쿼리 실행 도중 트랜잭션이 실패하면 트랜잭션은 어보트되고 삽입된 이메일과 메일박스 update는 롤백 되야 함.
- 격리성이 적용되지 않으면 emails 테이블에는 값이 있지만, mailboxes 가 아직 업데이트 되지 않았는데(즉 커밋되지 않았는데), dirty read 로 읽어버리면, 이메일에는 읽지않은 메시지가 있지만, 읽지 않는 메시지 갯수가 아직 증가되지 않은 상태가 됨.
- 다중 객체 트랜잭션은 어떤 읽기 연산과 쓰기 연산이 동일한 트랜잭션에 속하는지 알아낼 수단이 있어야 함.
- 관계형 데이터베이스에서는 클라이언트와 데이터베이스 서버 사이의 TCP 연결을 기반으로 함.
- 특정 연결 내에서 BEGIN TRANSACTION 문과 COMMIT 문 사이의 모든 것은 같은 트랜잭션에 속하는 것으로 여겨짐.
- 사실 이 방식도 이상적이지 않음.
- TCP 연결이 끊기면 트랜잭션은 어보트돼야 함.
- 클라이언트가 커밋 요청을 보냈지만 서버가 커밋 여부를 확인해주기 전에 연결이 끊긴다면 클라이언트는 트랜잭션이 커밋됐는지 아닌지 알 수 없음.
- 이 문제를 해결하려면 트랜잭션 관리자는 특정 TCP 연결이 엮이지 않은 고유한 트랜잭션 식별자를 사용해서 연산을 묶을 수 있음.
- p514 “데이터베이스에 관한 종단 간 논증” 에서 다시 얘기함.
- 이 문제를 해결하려면 트랜잭션 관리자는 특정 TCP 연결이 엮이지 않은 고유한 트랜잭션 식별자를 사용해서 연산을 묶을 수 있음.
- 특정 연결 내에서 BEGIN TRANSACTION 문과 COMMIT 문 사이의 모든 것은 같은 트랜잭션에 속하는 것으로 여겨짐.
- 비관계형 데이터베이스는 이런 식으로 연산을 묶는 방법이 없는 경우가 많음.
- 다중 객체 API(= 키-값 저장소에서 여러 키를 갱신하는 다중 put 연산)가 있더라도 반드시 트랜잭션 시멘틱을 뜻하지 않음.
- 즉, 어떤 연산은 성공하고 나머지 키에 대한 연산은 실패해서 데이터베이스가 부분 갱신될 수 있음.
- 관계형 데이터베이스에서는 클라이언트와 데이터베이스 서버 사이의 TCP 연결을 기반으로 함.
단일 객체 쓰기
- 원자성과 격리성은 단일 객체를 변경하는 경우에도 적용됨.
- 저장소 엔진들은 거의 보편적으로 한 노드에 존재하는 (키-값 쌍과 같은) 단일 객체 수준에서 원자성과 격리성을 제공하는 것을 목표로 함.
- 원자성은 장애 복구용 로그를 서서 구현할 수 있음.
- 격리성은 각 객체에 잠금을 사용해 구현할 수 있음.
- 어떤 데이터베이스는 증가 연산처럼 더 복잡합 원자적 연산을 제공하기도 함.
- 증가 연산은 read-modify-write 주기를 없애고 compare-and-set 연산을 적용한다.
- 즉, 이 연산은 변경하려는 값이 누군가에 의해 동시에 바뀌지 않았을 때만 쓰기가 반영되도록 함. (p245 참고)
- 이는 단일 객체 연산에서 여러 클라이언트에서 동시에 같은 객체에 쓰려고 할 때 갱신 손실(lost update)을 방지하므로 유용함.
- 증가 연산은 read-modify-write 주기를 없애고 compare-and-set 연산을 적용한다.
다중 객체 트랜잭션의 필요성
- 많은 분산 데이터스토어는 다중 객체 트랜잭션 지원을 포기함.
- 다중 객체 트랜잭션은 여러 파티션에 걸쳐 구현하기 어렵고, 매우 높은 가용성과 성능이 필요한 곳에서는 방해가 되는 시나리오도 있기 때문.
- 하지만, 분산 데이터베이스 근본적으로 트랜잭션을 막는 것은 아무것도 없음.
- 9장에서 분산 트랜잭션 구현에 대해 살펴봄
- 여러 개의 다른 객체에 실행되는 쓰기 작업은 코디네이션돼야 함.
- 서로 참조하는 여러 레코드를 삽입할 때, 참조 키는 옳바른 값이어야 하고 최신 정보를 반영해야 함. 그렇지 않으면 비정상적인 데이터가 만들어짐
- 문서데이터 모델의 경우 함께 생신돼야 하는 필드들이 단일 객체로 다뤄지는 동일한 문서 내에 존재하는 경우가 흔함.
- 비정규화된 정보를 갱신할 떄, 한 번에 여러 문서를 갱신해야 함.
- 트랜잭션을 이용하면 비정규화된 데이터가 깨지는 것을 방지할 수 있음.
- 보조 색인이 있는 데이터베이스에서 값 변경 시, 색인도 갱신돼야 함.
- 트랜잭션 관점에서 색인은 서로 다른 데이터베이스 객체임.
오류와 어보트 처리
- 트랜잭션 핵심 기능은 오류 발생시 어보트되고 안전하게 재시도 할 수 있다는 것임.
- 하지만 모든 시스템이 이 철학을 따르지 않음.
- 리더 없는 복제를 사용하는 데이터스토어는 “최선을 다하는(best effort)”원칙을 기반으로 훨씬 더 많은 일을 함.
- 즉, 데이터베이스는 가능한 모든 것을 할 것이며 오류가 발생하면 이미 한 일은 취소 하지 않는다는 뜻이며, 오류 복구는 애플리케이션 책임이라는 것임.
- 어보트된 트랜잭션을 재시도하는 것은 간단하고 효과적인 오류 처리 메커니즘이지만 완벽하지 않음.
- p232 예시 참고
'Book > 데이터 중심 애플리케이션 설계' 카테고리의 다른 글
책너두 (데이터 중심 애플리케이션 설계) 21일차 (~245p) (0) | 2023.04.07 |
---|---|
책너두 (데이터 중심 애플리케이션 설계) 20일차 (~241p) (0) | 2023.04.06 |
책너두 (데이터 중심 애플리케이션 설계) 18일차 (~220p) (0) | 2023.04.02 |
책너두 (데이터 중심 애플리케이션 설계) 17일차 (~208p) (0) | 2023.04.02 |
책너두 (데이터 중심 애플리케이션 설계) 16일차 (~193p) (0) | 2023.04.01 |