트랜잭션 ( Transaction )
。DB의 상태를 변화시키기 위해 수행하는 논리적 작업 단위
▶ DB의 상태변화가 올바르게 이뤄지도록 논리적으로 묶은 단위

。Transaction 단위는 한 작업을 위해 수행하는 복수 이상의 SQL Query으로 구성될 수 있다.
▶ Query 中 하나라도 실패하는 경우 ROLLBACK
。사용자가 Transaction을 사용하지않고 SQL Query를 실행 시 DB에서 암묵적으로 Transaction을 BEGIN 및 Query의 실행이 끝나는 경우 즉시 자동으로 COMMIT이 수행.
DB Transaction의 동시성 제어
。트랜잭션에서는 적절한 격리수준을 설정하여 동시성제어를 수행
。격리성이 완전히 보장되는 경우 트랜잭션 간 간섭을 철저히 차단하여 무결성을 보장하지만, 동시성이 감소하여 전체 Throughput이 감소하면서 시스템 성능 저하를 유발하는 단점이 존재.
어플리케이션 트랜잭션과 DB 트랜잭션을 별도 개념
。어플리케이션의 트랜잭션은 실제 비즈니스 서비스 작업단위로서 서비스 계층 @Transactional이 적용된 메서드에 해당
ex ) Post 수정의 경우 Post를 찾고, 수정하는 2개의 작업을 하나의 서비스 작업단위로 지정
。DB 트랜잭션은 DB와 상호작용하는 행위를 수행하는 개별 작업단위로서 Repository계층 내 @Transactional 메서드에 해당
ex ) Post 수정에서 각각 Post를 찾는 작업 / Post를 수정하는 작업은 각각 별개의 작업단위
ACID : 트랜잭션 4대 원칙
。원자성 / 일관성 / 격리성 / 지속성
。DB 트랜잭션은 해당 ACID 원칙을 반드시 준수해야함.
。각 원칙은 서로 관련되어있음
▶ 원자성을 위반하는 경우 일관성을 위배할 수 있음.
Atomicity ( 원자성 )
。단위 트랜잭션 내 모든 SQL Query의 실행이 전부 성공하거나 전부 실패해야함.
▶ 트랜잭션 내 한 SQL Query이라도 실패하는 경우 성공적으로 실행된 SQL Query의 변경사항도 전부 ROLLBACK
。하나의 트랜잭션은 더 이상 나눌 수 없는 최소단위이므로 원자성에 의해 중간상태를 불허
。DB가 트랜잭션 중 다운되는 경우 재실행 시 해당 트랜잭션은 비록 SQL Query들이 모두 정상적으로 실행되더라도 COMMIT되지 않았으므로 원자성을 준수하기 위해 ROLLBACK
Consistency ( 일관성 )
。트랜잭션의 실행 전후의 DB 상태에 대해 항상 일관성을 유지하도록 보장하는 원칙
ex ) 계좌 이체 시 두 계좌의 총액은 항상 동일해야함.
。DB 일관된 상태 : DB에 정의된 모든 규칙과 제약조건이 항상 만족되어야한다.
。일관성은 DB가 보장하는게 아닌, 어플리케이션이 보장해야한다.
。데이터 동시성과 직접적인 Trade off 관계의 성질
▶ 일부 DBMS에서는 성능을 위해 일관성을 포기하는 경우도 존재.
일관성 유형
데이터 일관성 ( Data Consistency )
。일반적인 일관성 개념으로서 트랜잭션에 의한 DB 데이터 변경이 항상 유효하고 일관된 상태를 유지하는 성질
。트랜잭션이 영구성과 고립성을 위반하는 경우 연쇄적으로 데이터 일관성 위반이 발생하게된다.
。일관성을 준수하기위해 각 DB Table은 제약조건 ( PK, FK, UNIQUE 등 )을 강제하도록 설계해야함.

▶ 다음 DB Table에서 참조 무결성에 의해 Pictures Table의 ID = 1의 row의 LIKES = 2를 만족해야하지만 LIKES = 5로 등록되어있으므로 데이터 일관성을 위반
읽기 일관성 ( Read Consistency )
。Snapshot 방식으로서 트랜잭션이 시작된 시점에서 COMMIT된 상태의 변경사항만 반영된 데이터를 기준으로 읽는 성질
。특정 트랜잭션에 의한 데이터 변경에 대해 COMMIT이 수행된 직후 새로운 트랜잭션이 실행 시 COMMIT 이전의 데이터를 참조하는 경우 읽기 일관성을 위반
최종적 일관성 ( Eventual Consistency )
。데이터 변경이 발생 시 모든 업데이트가 여러 분산 DB에 전파되는 단계에서 현재 시점에서는 일관성을 보장하지않지만 최종적으로 일관성을 보장하는 성질
。분산 데이터베이스 등에서 데이터 일관성을 유지하는 방법
Isolation ( 격리성 )
。복수의 트랜잭션이 동시에 수행하더라도 각각 독립적으로 실행되어 트랜잭션 내 SQL Query들이 다른 트랜잭션의 SQL Query와 서로 간섭하지않는 성질
。격리성을 철저하게 보장하는 경우 비동기 실행이 불가능하여 성능이 매우 떨어지는 단점이 존재
▶ 적절한 격리수준을 설정할 필요가 존재
。각 DBMS는 각각 다른 격리수준으로 개발.
Durabillity ( 영속성 )
。트랜잭션의 COMMIT 후 반영된 변경사항이 시스템이 장애가 발생하더라도 영구적으로 비휘발성 보조기억장치에 변경사항을 저장하여 영속성을 보장하는 성질
▶ COMMIT된 트랜잭션의 변경사항을 비휘발성 보조기억장치 ( = 디스크 )에 영구적으로 저장하는 것을 보장
。DBMS는 디스크에 트랜잭션에 의한 변경사항을 저장 시 IO 횟수를 감소하기위해 OS Cache에 1차적으로 저장 후 일괄적으로 디스크에 IO하여 기록.
▶ 중간에 OS가 마비될 경우 영속성을 보장하지 못할 수 있다
영속성 기법 종류
비동기 스냅샷 ( Asynchronous Snapshot )
。트랜잭션에 의한 변경내역을 주기억장치에 보관 및 백그라운드에서 비동기적으로 변경사항들을 한번에 디스크에 작성하는 기법
▶ 캐싱 개념으로서 Redis에서 주로 사용하는 방식
WAL ( Write Ahead Log )
。트랜잭션의 지속성을 보장하는 핵심 메커니즘
▶ 데이터를 보조기억장치에 작성 전 반드시 로그( = WAL )를 선행적으로 기록
。트랜잭션에 의해 데이터 변경이 수행 시 해당 데이터 변경사항들을 기록한 로그들을 WAL 세그먼트로 추가하여 해당 WAL 세그먼트를 기반으로 디스크에 작성하는 기법.
▶ WAL 활용 시 시스템이 갑자기 종료되어 디스크에 변경사항을 작성 중 실패하더라도 WAL 세그먼트의 로그를 기반으로 REDO / UNDO가 가능
。주로 MySQL의 InnoDB에서 활용하는 방식
트랜잭션 실행
↓
변경 내용을 로그(Log)에 먼저 기록 ← WAL
↓
버퍼 풀(메모리)에 반영
↓
COMMIT 시 실제 디스크에 영구 반영
영속성을 위해 트랜잭션의 변경사항을 디스크에 IO하여 반영하는 과정
DBMS에 의해 트랜잭션에 의한 변경사항에 대한 로그를 WAL 세그먼트에 추가 및 OS에게 디스크에 반영하도록 요청
OS는 해당 WAL 세그먼트를 디스크가 아닌 메모리 상 OS Cache에 작성
。OS Cache에 변경사항을 반영 시 OS에서 충돌이 발생 시 디스크에 변경사항이 반영되지않아 영속성을 위반할 수 있음
▶ 중요한 트랜잭션에 대해서만 fsync()를 통해 변경사항이 OS Cache를 거치지않고 직접 디스크에 반영하도록 설정
-
OS Cache에 기록된 변경사항을 일괄적으로 디스크에 IO하여 반영
。각 어플리케이션은 디스크에 수많은 쓰기 작업을 수행하는데 각 작업마다 일일이 IO 작업을 수행하는 경우 성능이 매우 저하
▶ IO 횟수를 감소하기위해 1차적으로 OS Cache에 변경사항들을 기록 후 일괄적으로 디스크에 IO를 수행
트랜잭션 복구
。트랜잭션 장애 발생 시 데이터 일관성을 보장하여 트랜잭션의 원자성 보장을 위한 메카니즘
▶ REDO / UNDO 연산을 통해 복구를 수행
。DB 갱신 방식에는 즉시 / 지연갱신이 존재
REDO
。COMMIT된 트랜잭션이 장애로 인해 실제 DB에 반영되지 못한 경우 트랜잭션 로그를 확인 후 다시 실행하여 DB에 반영하는 작업
UNDO
。COMMIT된 트랜잭션이 장애로 인해 실제 DB에 반영되지 못한 경우 트랜잭션 로그를 확인 후 트랜잭션 실행 이전으로 복구하는 작업
즉시 갱신( Immediate Update )
。트랜잭션 실행 중 트랜잭션 내 Query를 DB에 즉시 반영하는 방식
▶ 변경 전 데이터를 트랜잭션 로그에 저장
。트랜잭션 장애 발생 시 주로 UNDO 연산을 사용
지연 갱신( Deffered Update )
。트랜잭션 실행 중 트랜잭션 내 Query가 부분 완료될 때까지 COMMIT을 지연하는 방식
▶ 부분완료 전 까지 트랜잭션 작업내용을 로그에 기록 및 실제 DB 반영은 부분 완료 이후 반영하는 방식
。트랜잭션 장애 발생 시 주로 REDO 연산을 사용
▶ DB에 반영되지 않은 트랜잭션은 무시하고 반영된 트랜잭션은 트랜잭션 로그를 확인 후 REDO 연산을 통해 복구