Serializable
Serializable 은 트랜잭션 동시성에서 가장 강한 격리 수준으로, 실행 결과가 어떤 순차적 실행과 같도록 보장해 Dirty Read·Non-Repeatable Read·Phantom 등 모든 이상현상을 차단한다.
구현 방식은 잠금 (Strict 2PL), MVCC 기반의 직렬성 검증 (SSI), 또는 낙관적 검증 (OCC) 등이며, 분산 환경에서는 2PC·분산 합의·외부 시계 같은 추가 메커니즘이 필요하다.
실무에서는 데이터 무결성이 절대적일 때 우선 적용하되 성능 저하·교착·재시도 비용을 인덱스 튜닝, 트랜잭션 단축, 백오프/재시도 설계, 부분적 격리 상향 (핵심 경로만) 으로 완화하는 것이 핵심 전략이다.
핵심 개념
직렬가능성 (Serializable) 은 여러 트랜잭션이 동시에 실행돼도 그 결과가 어떤 순서로 하나씩 처리한 것과 정확히 같도록 보장하는 격리 수준이다. 데이터 무결성을 최대로 보장하기 때문에 금융·결제 같은 핵심 업무에서 쓰인다. 구현은 전통적 락 (Strict-2PL) 이나 최신 MVCC 기반의 SSI 같은 방식이 있는데, 모두 교착·성능 저하라는 비용을 동반하므로 실제 적용은 핵심 트랜잭션으로 제한하고, 애플리케이션은 재시도와 모니터링을 준비해야 한다.
| 핵심 개념 (한글,약어) | 정의 (요약) | 왜 중요한가 (실무 관점) |
|---|---|---|
| 직렬가능성 (Serializable) | 동시 실행 결과가 어떤 직렬 스케줄과 동일한 성질 | 데이터 일관성 최상 필요 시 필수 |
| 충돌 직렬가능성 (Conflict-Serializability) | 충돌 그래프에 사이클이 없으면 성립 | 스케줄 분석·모니터링용 판정 기준 |
| 2 단계 잠금 (2PL) / 엄격 2PL(S-2PL) | 락 획득/해제 규칙으로 직렬성 보장 | 단순·직관적, 락 경쟁·교착 유발 |
| 다중버전 동시성 제어 (MVCC) | 읽기용 스냅샷으로 블로킹 최소화 | 읽기 성능 개선, 장기 트랜잭션 비용 존재 |
| Serializable Snapshot Isolation(SSI) | MVCC 위에서 의존성 탐지로 직렬성 보장 | MVCC 장점 유지 + 직렬성, abort 가능성 |
| 팬텀 (Phantom) | 범위 질의에서 새로운 행이 보이는 현상 | 집계/범위 제약 정확성에 영향 |
| 쓰기 스큐 (Write Skew) | 상호 의존 규칙을 우회하는 동시 갱신 | 비즈니스 무결성 위험 |
| 2 단계 커밋 (2PC) | 분산 트랜잭션의 커밋 합의 프로토콜 | 분산 환경에서 원자성 보장하지만 비용 큼 |
| TrueTime / 글로벌 타임스탬프 | 전역 시간 동기화 메커니즘 | 분산 직렬성 (Spanner 스타일) 구현 기반 |
Serializable 관련 개념들은 서로 보완·대체 관계에 있다. 전통적 2PL 은 즉시적 직렬성 보장에 간단하지만 락 비용이 크고, MVCC 는 읽기 성능을 살리되 직렬성 보장을 위해 SSI 같은 추가 기법이 필요하다. 실무에서는 비즈니스 요구에 따라 적절한 조합을 선택하고, 애플리케이션 쪽에서 재시도·일관성 검증을 준비해야 한다.
개념 간 상호관계
| 출발 개념 → 도착 개념 | 관계 (방향성) | 무엇을 위해 / 어떤 영향 |
|---|---|---|
| Serializable → 2PL / S-2PL | 구현 관계 (직렬성 보장 수단) | 락으로 충돌 해결 → 직렬성 보장, 블로킹 증가 |
| MVCC → SSI | 확장 관계 (직렬성 보장 보완) | MVCC 에 의존성 탐지 추가 → 직렬성 보장, abort 발생 |
| 2PL → Deadlock | 원인 관계 | 락 획득 순서·경합 → 데드락 발생 가능성 |
| SSI → Abort/Retry | 결과 관계 | 충돌 탐지 시 트랜잭션 강제 종료 → 재시도 필요 |
| Phantom → Predicate Locking / Next-Key Lock | 완화 수단 관계 | 팬텀 방지 위해 범위 잠금 적용 |
| 2PC → 분산 Serializable | 조합 관계 | 분산 트랜잭션의 전역 직렬성 보장 (비용↑) |
관계는 대부분 " 무엇으로 직렬성을 실현하느냐 (구현 수단)" 와 " 어떤 부작용이 파생되느냐 (데드락/abort)" 로 요약된다. 방향성을 보면 구현 (예: MVCC→SSI) 은 성능 향상과 보장 간 트레이드오프로 이어지고, 락 기반 (2PL) 은 단순하지만 블로킹을 낳는다. 실무적 선택은 이 흐름을 이해하고 해당 워크로드에 맞춰 조정해야 한다.
개념별 실무 연관성
| 핵심 개념 (한글,약어) | 실무에선 무엇을 하게 되는가 (무엇) | 어떻게 적용되는가 (방법) | 왜 필요한가 (이유) |
|---|---|---|---|
| 직렬가능성 (Serializable) | 핵심 트랜잭션에 적용 | DB 격리 설정 또는 SSI/2PL 사용, 재시도 로직 준비 | 무결성 보장 (금융·정산) |
| MVCC | 읽기 성능 확보 | 버전 스토어 유지, VACUUM/GC 튜닝 | 대량 읽기·비동기 분석 성능 |
| 2PL / S-2PL | 강력한 충돌 차단 | 락 정책·타임아웃·데드락 탐지 | 단순 명확한 직렬성 보장 |
| SSI | MVCC 에서 직렬성 보장 | 의존성 탐지·충돌 시 abort | MVCC 의 이점 유지하며 직렬성 확보 |
| 2PC | 분산 커밋 안전화 | 조정자/참여자 프로토콜, 리커버리 로직 | 분산 트랜잭션의 원자성 확보 |
| 재시도/Idempotency | 충돌 시 안정 복구 | 애플리케이션 레벨 재시도·중복허용 처리 | abort 발생 시 서비스 안정성 |
| Predicate/Next-key Lock | 팬텀 방지 | 범위 잠금 적용, 인덱스 적절화 | 범위 질의 무결성 보장 |
실무에서는 단순히 DB 옵션만 바꾸는 게 아니라 애플리케이션 (재시도·idempotency), 운영 (모니터링·GC 튜닝), 설계 (인덱스·쿼리 구조) 전부를 함께 바꿔야 직렬가능성을 안정적으로 도입할 수 있다. 분산 상황에서는 2PC/글로벌 타임스탬프 같은 추가적 비용을 감수해야 한다.
기초 조사 및 개념 정립
Serializable 의 본질과 운영지침
Serializable 은 데이터베이스의 가장 강한 격리 수준으로, 여러 트랜잭션이 동시에 실행되더라도 마치 어떤 순서로 하나씩 실행된 것처럼 결과가 동일하게 보이도록 보장한다.
이로 인해 더티리드 (DIRTY), 비반복 읽기 (NON-REPEATABLE), 팬텀 리드 (PHANTOM) 같은 모든 동시성 문제를 예방한다.
구현은 전통적인 엄격 2 단계 잠금 (Strict 2PL) 으로 행·범위 락을 유지하거나, MVCC 기반의 직렬성 (예: SSI) 을 통해 충돌을 감지하고 재시도함으로써 달성한다.
장점은 완전한 일관성이며, 단점은 성능·동시성 (throughput) 손실과 데드락/재시도 증가다. 따라서 핵심 금융·결산 등 높은 정확성이 요구되는 워크로드에서 우선 적용하되, 적용 전 벤치마크·재현 테스트·재시도 정책을 반드시 설계해야 한다.
정의 (요약): Serializable 은 모든 동시 실행 트랜잭션의 외형적 결과가 어떤 일련의 단일 - 스레드 (직렬) 실행 결과와 같도록 보장하는 격리 수준이다.
근본 메커니즘:
- 락 기반 (Strict 2PL): 트랜잭션이 읽거나 쓴 자원에 대해 적절한 락을 취득하고, 커밋/롤백까지 락을 해제하지 않아 다른 트랜잭션의 간섭을 물리적으로 차단한다. 이 방식은 팬텀·비반복·더티 모두 차단하지만 데드락과 대기 비용이 크다.
- 스냅샷 기반 (SSI 등): 트랜잭션마다 스냅샷을 부여해 읽기는 무블로킹으로 수행하고, 커밋 시점에 충돌 (직렬화 이상) 을 감지하면 일부 트랜잭션을 abort(재시도) 시켜 직렬성 보장한다. 읽기 성능은 우수하지만 재시도 확률이 증가할 수 있다.
실무적 본질적 고려: 직렬성 도입은 ’ 정합성 확보 ’ 라는 명확한 목적을 달성하지만, 동시성·응답성·확장성에 대한 비용과 운영 복잡도가 따라온다. 설계 단계에서 어떤 트랜잭션이 절대적 일관성을 요구하는지를 정의하고, 그 범위만 직렬화하거나 하이브리드 패턴 (선택적 상향, 리플리카 분리, SSI 활용) 을 적용하는 것이 실무 핵심이다.
Serializable: 등장배경·기술 발전사
데이터베이스의 최고 격리인 Serializable은 여러 트랜잭션을 마치 순서대로 하나씩 실행한 것과 동일한 결과를 보장하 위한 개념이다.
초기에는 락 기반 (2PL) 으로 직렬성을 확보했지만, 읽기 위주의 워크로드에서 성능이 급격히 떨어졌다.
그래서 MVCC 가 등장해 읽기 성능을 살렸고, MVCC 의 한계를 보완하기 위해 gap-lock 같은 락 전략이나 충돌탐지 기반의 SSI 가 개발되어 **정합성 (Serializable 에 근접한 보장)**과 성능 (읽기 비차단) 사이의 균형을 찾아왔다.
규제·회계 등 엄격한 일관성이 필요한 시스템에서는 여전히 Serializable(또는 그에 준하는 기법) 을 선택한다.
등장 배경
트랜잭션 동시성으로 인한 데이터 불일치 (예: Lost Update, Dirty Read, Non-repeatable, Phantom) 가 실무에서 큰 문제를 만들었고, 이를 이론적으로 해결하려는 시도 (직렬화 가능성 연구) 가 1970 년대 이후 활발해졌다.
산업 현장에서는 " 정확성 보장 " 요구 (금융·회계 등) 와 " 높은 동시성/낮은 지연 " 요구 (웹·분석 서비스) 가 충돌했고, 이 둘을 조화시키려는 여러 기술이 등장했다.
발전 과정
| 발전 단계 | 핵심 기술/개념 | 대표 문제 해결점 | 한계·부작용 |
|---|---|---|---|
| 락 기반 (2PL) | S/X 락, 트랜잭션 직렬화 | 데이터 무결성 보장 | 읽기 성능 저하, 데드락 |
| MVCC | 버전 체인, 스냅샷 가시성 | 읽기 비차단, 높은 처리량 | 옛 버전 보존 비용, 팬텀 완전 차단 어려움 |
| Gap/Next-key Lock | 범위 락 (갭 락) | 팬텀 제어 (범위 삽입 차단) | 락 오버헤드 증가 |
| SSI (충돌탐지) | MVCC + 런타임 충돌 검출 | MVCC 유지하면서 직렬화 보장 개선 | 충돌 시 재시도 비용 |
| Serializable (고급) | 엄격 직렬성 스케줄링/검증 | 최고 수준 일관성 | 성능·운영 복잡도 증가 |
timeline
title Serializable 관련 기술 발전 타임라인 (개괄)
1970s : 직렬화 가능성 이론 발전 (학계)
1980s : 락 기반 2PL 상용 DB 채택
1990s : MVCC 채택 확산 (읽기 비차단 목표)
2000s : gap/next-key lock 등 혼합 전략 채택 (팬텀 제어)
2010s : SSI(충돌탐지) 등의 고급 MVCC 보완 기법 등장
2010s+ : 엔진별 Serializable 옵션·정교화
핵심 흐름: 정확성 확보 (락 기반) → 성능 요구로 MVCC 등장 → MVCC 의 팬텀·쓰기왜곡 약점 보완 (갭 락, SSI 등) → 필요시 최고 격리 (Serializable) 선택.
의미: 각 단계는 " 어떤 문제를 해결하려 했는가 " 와 " 그 해결이 초래한 새 문제 (부작용)" 를 함께 갖는다. 따라서 설계자는 비즈니스 요구 (정합성 민감도, 지연 허용치) 에 따라 적절한 지점을 선택해야 한다.
Serializable: 문제·목표·실무가이드
Serializable 은 데이터베이스에서 가장 엄격한 격리 수준이다. 여러 트랜잭션이 동시에 수행되더라도, 결과는 어떤 순서로 하나씩 실행했을 때 (직렬화) 와 똑같이 나온다. 그래서 회계·금융처럼 결과의 완전성과 불변성이 절대적으로 중요한 영역에서 사용된다. 구현은 락을 길게 유지하거나 (Monolithic 2PL), 최신 DB 의 경우 MVCC 기반으로 충돌을 감지해 잘못된 실행을 취소시키는 방식 (SSI) 을 사용한다. 강한 안전성을 제공하지만 성능·복잡도 비용이 크므로 필요한 곳에만 제한적으로 적용한다.
Serializable 이 해결하는 문제들
| 해결 문제 | 문제의 본질 | Serializable 이 해결하는 방식 | 실무적 이득 |
|---|---|---|---|
| 동시성으로 인한 비결정성 | 동시 실행 순서에 따라 최종 상태가 달라짐 | 직렬화 보장 (락/충돌감지) → 어떤 순서로 실행하더라도 동일 결과 | 결과 예측성·디버깅 용이 |
| Non-repeatable Read / Dirty Read | 재조회 시 값 변하거나 미커밋 값 노출 | 모든 이상현상 차단 (직렬화로 귀결) | 계산·정산 오류 방지 |
| Phantom (범위 삽입) | 같은 조건의 재조회에서 행 집합 변화 | 범위 락 또는 충돌감지로 새 행 노출 방지 | 범위 기반 집계 안정성 확보 |
| 응용 불변식 위반 | 복합 비즈니스 규칙이 동시성으로 깨짐 | 트랜잭션 수준에서 불변식 보장 | 보정·사후검사 비용 절감 |
Serializable 은 동시성으로 인해 발생하는 모든 일관성 이상 (읽기 불일치, 팬텀 등) 을 데이터베이스 수준에서 제거함으로써, 응용 레벨의 비즈니스 불변식까지 강력하게 보호한다. 다만 이를 위해 락 유지 또는 충돌 감지와 같은 비용을 지불해야 하므로, 도입 전 성능 영향과 재시도·블로킹 시나리오를 검증해야 한다.
Serializable 의 핵심 목적
| 핵심 목적 | 구체 설명 | 기대되는 효과 |
|---|---|---|
| 직렬성 보장 (Serializability) | 동시 실행의 결과가 어떤 직렬 실행과 동일하게 유지되도록 보장 | 예측 가능한 시스템 상태, 규정 준수 용이 |
| 비즈니스 불변식 보호 | DB 제약을 넘는 응용 규칙 (합계 보존 등) 도 트랜잭션 수준에서 보장 | 보정·감사 비용 절감 |
| 데이터 신뢰성 극대화 | 모든 이상현상 (Dirty/Non-repeatable/Phantom) 제거 | 운영 신뢰성·감사 추적성 향상 |
핵심 목적은 _ 시스템 전체의 결정론적 일관성 유지 _ 이며, 이는 금융·회계 등 엄격한 신뢰성 요구 분야에서 직접적인 비즈니스 가치를 제공한다. 목적 달성을 위해서는 성능과 재시도 전략을 포함한 운영 설계가 필요하다.
문제와 목적의 연결 맵
| 해결 문제 | 연관 핵심 목적 | 어떻게 연결되는가 |
|---|---|---|
| 동시성 비결정성 제거 | 직렬성 보장 | 직렬화 보장 메커니즘이 문제를 직접 해소 |
| Non-repeatable/Dirty Read 제거 | 데이터 신뢰성 극대화 | 이상현상 제거 → 신뢰성 확보 |
| Phantom 억제 | 비즈니스 불변식 보호 | 범위 안정성으로 범위 기반 규칙 보장 |
| 응용 불변식 위반 방지 | 비즈니스 불변식 보호 / 직렬성 | 트랜잭션 단위 보장이 불변식 유지로 이어짐 |
각 문제는 Serializable 의 특정 목적과 직접적으로 연결된다. 예컨대 팬텀 문제는 범위 안정성을 제공하는 직렬성 보장 메커니즘을 통해 해결되며, 그러므로 문제 - 목적 매핑을 통해 어떤 메커니즘이 필요한지 설계 단계에서 바로 판단할 수 있다.
Serializable 적용 전제와 운영 요건
Serializable 을 안전하게 운영하려면 트랜잭션 경계를 명확히 하고 트랜잭션을 짧게 설계해야 한다.
인덱스를 적절히 구성해 불필요한 범위 스캔을 줄이고, 락 (또는 검증) 기반으로 직렬성 보장을 구현해야 한다.
락 경쟁·데드락·언두 증가 등 성능 이슈를 모니터링하고, 충돌 발생 시 안전하게 재시도할 수 있는 멱등성·보상 로직을 준비해야 한다.
이러한 조건을 만족하는 시스템에서만 Serializable 적용을 권장한다.
Serializable 전제·요구 체크리스트
| 전제/요구사항 | 설명 | 근거 (무슨 문제로부터 기인) | 실무 영향 | 권장 조치 |
|---|---|---|---|---|
| 트랜잭션 경계 명확화 | 트랜잭션 시작/종료 규칙 문서화 | 불명확 경계는 긴 tx 유발 | 언두·락 축적, 디버깅 난이도 증가 | 코드·아키텍처 규약 수립 |
| 짧은 트랜잭션 설계 | 외부 I/O 분리, 연산 분해 | 긴 tx 는 락 보유시간 증가 | deadlock·throughput 저하 | 타임아웃 설정, 비동기화 |
| 적절한 인덱스 | 쿼리 커버링·범위 최소화 | 범위 스캔 → gap/next-key 락 확대 | 락 확산·성능 저하 | 인덱스 리펙토링, 쿼리 튜닝 |
| 락/검증 메커니즘 | Strict 2PL 또는 SSI 등 구현 | 직렬성 보장 필요성 | 충돌/재시도·대기 증가 | DB 옵션 검토·설정 |
| 락 경쟁 관리 | timeout, deadlock detect, escalation | 교착/경합으로 가용성 저하 | 장애 및 복구 비용 증가 | 모니터링·자동화·SRE Playbook |
| 멱등성·재시도 설계 | idempotency token, 보상 트랜잭션 | 충돌로 트랜잭션 abort 발생 가능 | 사용자 영향 완화 | 설계·코드 수준 구현 |
| 리소스·성능 검증 | 부하 테스트로 재시도율·throughput 측정 | 직렬화 적용 시 성능 저하 가능 | SLA 미달 위험 | 사전 성능 테스트 |
| 적용 도메인 선정 | 정합성 우선 영역에 적용 | 모든 트랜잭션에 적용하면 과비용 | 운영비 증가 | 핵심 트랜잭션만 선별 적용 |
Serializable 은 강력한 정합성 보장을 위해 필요한 전제 (짧은 트랜잭션, 인덱스, 락/검증 메커니즘, 멱등성 등) 가 많다. 이 전제들이 충족되지 않으면 성능·가용성 문제로 실무에 큰 부담을 준다. 따라서 핵심 트랜잭션에만 선별 적용하고, 적용 전 DB 별·시나리오별 검증을 통해 임계값을 정의해야 한다.
Serializable 핵심 특징·운영 포인트
Serializable 은 데이터베이스에서 가장 강한 격리 수준으로, 여러 트랜잭션이 동시에 실행되어도 마치 어떤 순서로 하나씩 실행된 것과 같은 결과만 나오도록 보장한다.
이를 위해 시스템은 읽기·쓰기에 대해 강력한 제어 (잠금이나 충돌 검증) 를 적용하고, 분산 환경에서는 합의 프로토콜을 동원한다.
그 결과 데이터 무결성은 극대화되지만 처리량은 줄고 지연·재시도 가능성이 커진다. 실제 운영에서는 성능 비용 때문에 모든 트랜잭션에 적용하기보다, 금전·규제·불변식이 중요한 핵심 경로에만 적용하는 전략을 쓴다.
Serializable 핵심 특징표
| 핵심 특징 | 기술적 근거 | 다른 기술과의 차별점 | 실무 영향 / 권장 적용 |
|---|---|---|---|
| 이상현상 완전 차단 | 직렬화 그래프 무사이클 보장 (2PL/SSI/OCC) | RC/RR 등은 일부 이상현상 허용 | 금전·규제 경로 우선 적용 |
| 읽기도 제어 | 공유락 또는 의존 추적·검증 | MVCC 낮은 격리는 읽기 비차단 | SELECT 도 비용 발생 |
| 수학적 직렬성 보장 | 스케줄이 직렬 스케줄과 등가 | 약한 격리는 등가성 불완전 | 데이터 무결성 최우선 상황에 유리 |
| 성능·지연 비용 | 락 경합·충돌 검증·분산 합의 오버헤드 | 약한 격리보다 처리량 낮음 | 전체 적용 비권장, 부분 적용 권장 |
| 재시도/교착 필요성 | 충돌 시 abort/재시도, 데드락 탐지 | RC/RR 에서는 빈도 낮음 | idempotency·백오프 설계 필수 |
- Serializable 은 정확성 (무결성) 을 극대화하지만 **성능·운영 비용 (재시도, 데드락, 지연)**을 동반한다.
- 실무는 엔진 특성과 비즈니스 위험을 바탕으로 핵심 경로에 국소 적용하고, 재시도/백오프·idempotency·샤딩·인덱스 설계로 비용을 완화해야 한다.
Phase 2: 핵심 원리 및 이론적 기반
Serializable 설계 원칙·철학 가이드
Serializable 은 " 동시 작업을 아무리 많이 해도, 결과는 어떤 순서로 하나씩 처리한 것과 똑같다 " 는 규칙이다.
금융·정산처럼 정확성이 생명인 곳에서 쓰이며, 대신 성능·동시성이 낮아질 수 있다.
그래서 보통은 모든 트랜잭션에 적용하지 않고, 핵심 작업에만 선택적으로 적용한다.
구현은 락 (전통적) 이나 MVCC+ 충돌탐지 (현대적) 방식이 있고, 애플리케이션은 abort·재시도를 처리하도록 준비해야 한다.
Serializable 핵심 원칙 표
| 핵심 원칙 | 설명 | 목적 (무엇을 위한) | 왜 필요한가 (근거) |
|---|---|---|---|
| 정확성 우선 | 결과의 정확성을 최우선으로 둠 | 비즈니스 무결성 확보 | 무결성 손실은 금전적·법적 리스크 |
| 직렬성 보장 | 동시 실행을 직렬 결과와 동등하게 | 모든 이상현상 제거 | 회계/결제 등 강한 일관성 필요 |
| 선택적 적용 | 핵심 트랜잭션에만 적용 | 성능 저하 최소화 | 전체 시스템 성능 보전 필요 |
| 복구·재시도 준비 | 충돌 시 안전 재시도 보장 | 사용자 경험·서비스 연속성 | SSI/2PL 은 abort 발생 가능 |
| 관찰성 확보 | 락/abort 등 지표 모니터링 | 문제 조기 탐지·대응 | 운영 문제를 빠르게 파악·완화 |
핵심 원칙은 ’ 정확성 ’ 을 중심으로 설계·운영하는 가이드라인이다. 실무에서는 직렬성의 이득 (무결성) 과 비용 (성능·운영 복잡성) 을 균형 있게 관리하기 위해 선택적 적용, 재시도 로직, 모니터링을 반드시 병행해야 한다.
Serializable 설계 철학 표
| 설계 철학 | 설명 | 목적 (무엇을 위한) | 왜 필요한가 (근거) |
|---|---|---|---|
| 정확성 - 우선 아키텍처 | 핵심 영역엔 일관성, 주변엔 성능 | 위험 분리 및 비용 집중 | 전체 성능 저하 없이 핵심 보호 |
| 작은 범위·짧은 Tx | 트랜잭션은 작고 빠르게 | 락·버전 보관 부담을 줄임 | 장기 트랜잭션이 비용 폭증 유발 |
| 구현 선택성 (MVCC vs 2PL) | 워크로드에 맞는 방법 선택 | 최적의 성능·일관성 균형 | 한 방식만으로 모든 상황 대응 불가 |
| 애플리케이션 보강 | DB 외 검증·재검증 도입 | 비즈니스 제약 보완 | DB 만으로는 모든 규칙 보장 불가 |
| 분산 비용 수용 정책 | 글로벌 일관성 적용 가이드라인 | 기대치·SLA 명확화 | 분산 직렬성은 높은 비용 요구 |
설계 철학은 ’ 어디에 직렬성을 적용할지, 어떤 방식으로 보완할지 ’ 에 대한 큰 그림이다. 핵심은 " 무엇을 위해 일관성이 필요한가 " 를 기준으로 설계 결정을 내리고, 운영·애플리케이션 측면의 보완책을 전제로 삼는 것이다.
Serializable 메커니즘과 충돌처리 흐름
Serializable 은 데이터 일관성을 최우선으로 하는 격리 수준으로, 모든 동시 트랜잭션의 최종 결과가 어떤 순차 실행 순서와 같도록 보장한다.
구현 방식은 크게
- 락 기반 (Strict 2PL)—충돌을 물리적으로 차단해 직렬성 확보
- MVCC+SSI—읽기는 스냅샷으로 무블로킹 처리하고 커밋 시 충돌을 검출해 재시도하여 직렬성 보장
- OCC—커밋 시 검증하는 방식이다.
각 방식은 성능·대기·재시도 특성이 다르므로 실무 적용 전 벤더별 동작과 재시도 정책을 확인해야 한다.
Serializable 메커니즘 비교표
| 메커니즘 | 동작 요지 | 장점 | 단점 | 실무 적용 포인트 |
|---|---|---|---|---|
| Strict 2PL (락 기반) | 읽기/쓰기 시 락 획득·커밋까지 유지 | 직렬성 확실·단순 | 데드락·대기·확장성 저하 | 데드락 탐지/타임아웃 필요 |
| MVCC + SSI | 읽기는 스냅샷, 커밋 시 rw-dep 추적→충돌시 abort | 읽기 무블로킹·좋은 읽기 성능 | 충돌시 재시도·복잡성 | serialization failure 재시도 로직 |
| OCC (검증) | 커밋 전 Validation, 위반시 abort | 락 오버헤드 없음 (낙관적) | 충돌 잦으면 비용 급증 | 충돌율 낮은 워크로드 권장 |
Serializable 보장은 메커니즘에 따라 성능·운영 비용이 크게 달라진다. 락 기반은 강력하지만 확장성이 낮고, MVCC+SSI 는 읽기 성능 우수하나 충돌 발생 시 재시도가 필요하며, OCC 는 충돌 희박 환경에서 효율적이다. 실무 적용 시 워크로드 특성 (읽기/쓰기 비율·충돌율) 을 기준으로 메커니즘을 선택하라.
Serializable 처리 흐름도
flowchart TD
A[트랜잭션 시작] --> B{동작: Read/Write}
B -->|Read| C[스냅샷 조회 또는 Shared Lock 요청]
B -->|Write| D[Write Buffer / X Lock 요청]
C --> E{메커니즘}
D --> E
E -->|2PL| F[락 획득 유지 → 충돌 시 락 대기/데드락 탐지]
E -->|MVCC+SSI| G[읽기 스냅샷, 커밋 시 rw-dep 기록]
E -->|OCC| H[로컬 작업 → 커밋 시 Validation]
F --> I{충돌?}
G --> J{"충돌(순환)?"}
H --> K{검증 실패?}
I -->|예| L[데드락 처리 or 타임아웃 → 재시도/Abort]
I -->|아니오| M[정상 진행]
J -->|예| L
J -->|아니오| M
K -->|예| L
K -->|아니오| M
M --> N[커밋 성공]
L --> O[트랜잭션 abort → 재시도 정책 적용]
흐름도는 트랜잭션이 읽기/쓰기를 수행할 때 선택되는 메커니즘 (락 기반 / MVCC+SSI / OCC) 에 따라 충돌 처리 방식이 달라지는 것을 보여준다.
락 기반은 자원에 대한 락을 유지해 충돌을 물리적으로 차단하지만 데드락과 대기 발생 가능성이 있다.
MVCC+SSI 는 읽기를 스냅샷으로 처리해 읽기 성능을 확보하고, 커밋 시점에 의존성 그래프를 검사해 순환이 발견되면 일부 트랜잭션을 abort 하여 직렬성을 보장한다.
OCC 는 커밋 전 검증 단계에서 위반을 발견하면 rollback 한다. 실무에서는 재시도·타임아웃·데드락 탐지·모니터링을 함께 설계해야 한다.
Serializable: 제어·데이터 흐름과 생명주기
Serializable 은 여러 트랜잭션이 동시에 일어나도 마치 차례대로 (직렬) 실행된 것처럼 행동하게 하는 격리 목표다. 이를 위해 DB 는 트랜잭션의 읽기/쓰기 관계를 추적하고 (혹은 락을 걸고), 순환 의존이 생기면 일부 트랜잭션을 중단시켜 시스템 전체가 직렬성과 일관성을 유지하도록 한다. 구현 방식 (락 vs MVCC+ 충돌탐지) 에 따라 대기·재시도 등 부작용이 다르므로 운영·설계 시 주의가 필요하다.
Serializable 제어 흐름 상세
동작 흐름 (단계별)
- Start: 트랜잭션 생성 → ID/시작 TS 할당 (또는 스냅샷).
- Read:
- 락: S-lock 획득 → 다른 트랜잭션의 X-lock 충돌로 대기 가능.
- MVCC: 스냅샷 기준 읽음 → 의존성 (읽음 대상과 트랜잭션) 을 기록.
- Write:
- 락: X-lock 획득 → 다른 트랜잭션 대기.
- MVCC: 새 버전 생성 (undo 정보 유지), write 의존성 그래프에 간선 추가.
- CC 처리: 의존성 그래프 갱신 → 주기적 또는 이벤트 기반으로 cycle 검사.
- Resolve: cycle 발견하면 abort(혹은 deadlock victim 선택).
- Commit: 가시성 규칙에 따라 버전 공개 (또는 log flush) → 후속 트랜잭션이 볼 수 있음.
- Cleanup: 락 해제/가비지 컬렉션.
Serializable 데이터·제어 흐름 표
| 단계 | 동작 (요약) | CC 영향/반응 | 운영 모니터 항목 |
|---|---|---|---|
| 시작 | 트랜잭션 생성, TS/ID 할당 | 스냅샷 기준/락 정책 결정 | txn 시작률, 평균 시작간격 |
| 읽기 | SELECT 처리 (S-lock or snapshot) | 읽기 의존성 기록 / 잠금 대기 발생 가능 | read latency, lock waits |
| 쓰기 | UPDATE/INSERT/DELETE 처리 | 쓰기 의존성 추가, 잠금 획득 or 버전 생성 | write latency, lock waits |
| 의존성 추적 | rw/rwr 간선 유지 | 그래프 크기 증가 → 성능영향 | dependency graph size |
| 충돌 탐지 | cycle/unsafe pattern 탐지 | deadlock/serialization failure 발생 → abort | deadlocks, serialization failures |
| 커밋 | 로그 flush, 버전 가시화 | 가시성 전파, 후속 txn 영향 | commit latency, fsync 시간 |
| 정리 | 락 해제, GC 수행 | 리소스 해제, 버전 정리 | long-running txns, GC backlog |
요약하면 데이터·제어 흐름은 연산이 의존성을 만들고 (CC 가 이를 추적), 그 의존성 속에서 오류 (사이클) 가 날 경우 일부 트랜잭션을 중단해 전체 시스템의 직렬성 (Serializable) 을 지키는 과정이다. 운영에서는 특히 의존성 그래프 크기·장기 트랜잭션·deadlock·serialization failures를 중점적으로 모니터링해야 한다.
Serializable: 데이터·제어 흐름도
flowchart LR Start[트랜잭션 시작] Start --> Read["READ (S-lock or Snapshot)"] Read --> Write["WRITE (X-lock or new version)"] Read -->|의존성 등록| Dep[의존성 그래프 업데이트] Write -->|의존성 등록| Dep Dep --> Check[충돌/사이클 검사] Check -->|사이클 없음| Proceed[계속 실행] Check -->|사이클 탐지| Abort[Abort / Serialization Failure] Proceed --> Commit[커밋 -> 가시성] Commit --> Cleanup[락 해제 / GC] Abort --> Cleanup
- 트랜잭션이 읽기/쓰기를 수행할 때 CC 가 의존성을 기록한다. 기록된 의존성은 그래프로 관리되며, 일정 기준 (또는 이벤트) 에 따라 cycle detection을 수행한다. cycle 발견 시 DB 는 정책 (데드락 victim, 또는 serialization failure victim) 에 따라 하나 이상의 트랜잭션을 abort 시켜 그래프를 깨고 직렬성을 보장한다. 성공적으로 커밋되면 변경은 가시화되고 후속 트랜잭션이 이를 본다. 이후 락 해제 또는 MVCC 의 경우 가비지 컬렉션으로 오래된 버전을 회수한다.
트랜잭션 생명주기 (Serializable)
sequenceDiagram participant C as Client participant DB as DB Engine / CC C->>DB: BEGIN DB-->>C: tx_id / snapshot C->>DB: SELECT (read) DB-->>C: rows (from snapshot or lock) C->>DB: UPDATE (write) DB-->>DB: register dependency, acquire lock / create version C->>DB: COMMIT DB-->>DB: check conflicts -> commit success or serialization failure DB->>C: COMMIT OK / ABORT (with error) DB->>DB: cleanup locks / GC
- 클라이언트가 BEGIN 하면 DB 는 tx_id 또는 snapshot 을 부여한다. 그 뒤 읽기/쓰기 연산을 수행하면서 CC 는 의존성을 기록하고 필요 시 락을 획득한다. COMMIT 요청 시 CC 는 의존성 그래프를 검사해 충돌이 있는 경우 COMMIT 을 거부 (rollback) 하거나 재시도 플로우를 유도한다. 최종적으로 락 해제·버전 가비지 컬렉션이 이루어진다.
특성 분석 및 평가
Serializable: 장점·적용 시 고려사항
Serializable 은 여러 트랜잭션이 동시에 실행되어도 결과가 꼭 순차 실행과 동일하도록 보장하는 격리 수준이다.
따라서 모든 동시성 이상 현상을 제거해 회계·결제처럼 결과 정확성이 절대적으로 필요한 곳에 적합하다.
다만 이를 위해 락 유지나 충돌감지·재시도 같은 비용이 발생하므로, 필요한 경로에만 선택적으로 적용하는 것이 실무 원칙이다.
Serializable 의 핵심 장점 요약표
| 장점 (요약) | 근거 (기술 메커니즘) | 실무 효과 |
|---|---|---|
| 데이터 무결성 극대화 | 직렬화 보장 (범위 락 또는 SSI) | 정산·회계 오류 방지, 규제 대응 |
| 모든 동시성 문제 해결 | 직렬성으로 이상현상 완전 제거 | 비즈니스 불변식 안전 보장 |
| ACID 완전 지원 | Isolation 을 최상으로 강화 | 감사 추적성·신뢰성 향상 |
| 개발·운영 단순화 | DB 수준의 일관성 책임 | 앱 복잡도 감소·운영 리스크 축소 |
| 디버깅·재현성 향상 | 결정론적 상태 보장 | MTTR 감소, 원인 분석 쉬움 |
Serializable 은 결과의 ’ 정확성 ’ 과 ’ 예측 가능성 ’ 을 극대화한다. 이로 인해 금융·회계처럼 오류 비용이 큰 도메인에서 큰 가치를 제공한다. 반면 성능·대응 비용 (락 대기·재시도 등) 이 증가하므로, 적용 전 워크로드 기반 성능 검증과 재시도/아이덴포턴시 설계가 필수다.
Serializable 단점·제약과 완화 전략
Serializable 은 데이터 정합성을 최고 수준으로 보장하지만 그 대가로 동시성·성능에 큰 비용이 따른다.
핵심 단점은 처리량 감소·응답 지연·데드락·재시도 빈도 증가이며, 긴 읽기 트랜잭션이나 인덱스 부재 등 환경적 제약은 문제를 악화시킨다.
실무에서는 핵심 무결성 트랜잭션에만 선별 적용하고, 트랜잭션을 짧게 설계하며 인덱스·파티셔닝·멱등 재시도 등 완화책을 반드시 병행해야 안정적으로 운영할 수 있다.
Serializable 주요 단점 표
| 단점 | 설명 | 원인 | 실무 문제 | 완화/해결 방안 | 대안 기술 |
|---|---|---|---|---|---|
| 처리량 감소 | 동시 실행 제한으로 TPS 저하 | 순차화·락/검증 | 처리량 부족, 비용 상승 | 핵심 트랜잭션 선별, 파티셔닝, 튜닝 | Repeatable Read, CQRS |
| 지연 증가 | 락 대기·재시도로 p99 증가 | Lock wait / Abort | 사용자 경험 저하 | 백오프·타임아웃·재시도 정책 | 비동기 처리, 리플리카 |
| 교착상태 | 잠금 순서 불일치로 Deadlock | 2PL·범위 락 | 트랜잭션 abort·운영 개입 | 일관적 잠금 순서, deadlock detection | SSI/OCC |
| 재시도 비용 | 충돌로 인한 abort/재시도 발생 | 충돌 감지/검증 실패 | 자원 낭비·지연 증가 | 멱등성·보상 트랜잭션 | 파티셔닝 |
| 운영 복잡도 | 모니터링·튜닝 요구 증가 | 높은 충돌·재시도 가능성 | 운영 비용·인력 필요 | 자동화·Runbook·대시보드 | 낮은 격리와 보완패턴 |
단점들은 Serializable 이 ’ 직렬성 ’ 을 보장하기 위해 피할 수 없이 발생하는 비용들이다. 핵심 대응은 적용 범위를 좁히고 (선별 적용), 설계 (트랜잭션 단축, 인덱스), 아키텍처 (파티셔닝/CQRS), 운영 (모니터링·자동화) 으로 비용을 흡수하는 것이다.
Serializable 적용 제약사항 표
| 제약사항 | 설명 | 원인 | 영향 | 완화/해결 방안 | 대안 기술 |
|---|---|---|---|---|---|
| 긴 읽기 트랜잭션 | 장기 스냅샷·범위락 확대 | 배치·대용량 쿼리 | 전체 경합·GC 부담 | OLTP/OLAP 분리, 리플리카 | HTAP, 리플리카 읽기 |
| 인덱스 부재 | 풀스캔으로 락 범위 확대 | 적절 인덱스 미구성 | 충돌·대기↑ | 커버링 인덱스, 쿼리 리팩토링 | 파티셔닝 |
| DBMS 별 한계 | 엔진별 구현 차이 (2PL/SSI) | 내부 동시성 제어 방식 | 예측성·이식성 저하 | DB 별 검증·문서화 | 엔진 선별 (요건 맞춤) |
| 리소스 한계 | undo/version 스토어 증가 | 긴 tx 누적 | 디스크/메모리·GC 이슈 | 트랜잭션 단축, GC 정책 | 리소스 확장 |
| 분산 환경 비용 | 분산 직렬화의 조정비용 | 합의/타임소스 필요 | 레이턴시·복잡성 증가 | 파티셔닝, 로컬 트랜잭션 | Spanner/Cockroach |
제약사항은 주로 워크로드·쿼리·플랫폼 특성에서 기인한다. 해결은 설계 (분리·파티셔닝), 튜닝 (인덱스·쿼리), 운영 (모니터링·GC) 조합으로 이뤄진다. 필요한 경우 분산 강직렬성 DB(Spanner/Cockroach) 등으로 아키텍처를 전환해 비용을 흡수할 수 있다.
직렬성 트레이드오프와 하이브리드 전략
Serializable 은 트랜잭션이 동시에 실행되더라도 마치 어떤 순서로 하나씩 실행한 것처럼 보장하는 최고 수준의 격리다. 이로써 모든 동시성 오류를 차단하지만, 동시 실행을 제한하거나 충돌 시 재시도해야 하므로 처리량과 응답성이 떨어진다. 실제 운영에서는 성능 부담 때문에 모든 요청에 적용하지 않고, 결제·정산 같은 ’ 정확성 우선 ’ 경로에만 선택적으로 적용한다.
직렬성 대 성능 선택표
| 비교 항목 | A = Serializable | B = 성능 우선 (예: RC/MVCC 낮음) |
|---|---|---|
| 일관성 수준 | 최고 (직렬성 보장) | 낮음~중간 (일부 이상현상 허용) |
| 처리량 | 낮음 | 높음 |
| 지연 | 높음 | 낮음 |
| 데드락/재시도 | 빈번함 가능 | 적음 |
| 운영 복잡성 | 높음 (재시도·모니터링 필요) | 낮음 |
| 적용 권장 영역 | 결제·정산·회계·규제 경로 | 대시보드·로그·임시 집계 |
| 분산 적용 비용 | 매우 높음 (합의 필요) | 낮음 (비동기·복제 활용) |
- 선택 기준은 **비즈니스 민감도 (정확성 필요성)**와 성능 목표 (p95/p99 요구), 그리고 재시도·운영 수용력이다.
직렬화 완화 하이브리드 패턴
| 패턴 | 적용목적 | 장점 | 고려사항 |
|---|---|---|---|
| 선택적 직렬화 | 핵심 경로 일관성 확보 | 비용 국소화 | 경로 식별·권한 필요 |
| Replica + Recheck | 읽기 성능 + 최종 검증 | 읽기 오프로드 | 복제 지연·재검증 비용 |
| OCC/SSI + Retry | 락 회피, 높은 동시성 | 낮은 락 오버헤드 | 충돌시 재시도 비용 |
| Escrow/Quota | 분산 자원 동시성 완화 | 충돌 최소화 | 설계 복잡성 |
| Sagas/보상 | 분산 일관성 (최종) | 가용성·확장성 유지 | 보상 로직 필요 |
- 하이브리드 방법들은 정확성 요구를 핵심에 집중시키고, 나머지 영역은 성능 우선으로 설계하는 실무적 타협이다.
- 선택 시 고려사항 (복잡성, 검증 비용, 지연 허용도) 을 반드시 평가하라.
Serializable 적용성 평가와 권장전략
언제 쓰나?
금융·회계·정산처럼 정확성 손실 비용이 큰 트랜잭션에 적합하다.왜 제한 적용하나?
직렬성은 무결성을 보장하지만 성능·동시성 비용(대기·교착·abort) 이 크기 때문이다.실전 원칙:
핵심 트랜잭션만 적용 → 트랜잭션 좁게 유지 → 테스트 (성능·운영) → 모니터링·재시도 체계 마련.
Serializable 적용 적합성 표
| 환경/유스케이스 | 설계 관점 (무엇/위험) | 분석 관점 (측정 지표) | 운영 관점 (운영 이슈) | 권장 여부 |
|---|---|---|---|---|
| 금융 결제·정산 | 멀티레코드 불변식 필요 / 락 증가 가능 | p99 응답, abort 율, 재시도율 | 재시도·감시 필수 | 적합 (선택적 전면 적용) |
| 재고·좌석 예약 | 경쟁적 업데이트 빈발 / 락 난항 가능 | deadlock 률, lock_wait_time | 즉시 모니터링·타임아웃 | 적합 (핵심 트랜잭션 적용) |
| 대규모 웹 OLTP(읽기多) | 대기·처리량 저하 위험 | TPS 저하, p95 상승 | 성능 저하 방지책 필요 | 부적합 (완화된 격리 권장) |
| 실시간 로그/분석 | 읽기 위주·약한 일관성 요구 | 용량·지연 영향 | 모니터링 중심 | 부적합 (Read Committed/Eventually) |
| 분산 글로벌 트랜잭션 | 2PC/TrueTime 비용·레이턴시 큼 | 전역 지연, 가용성 영향 | 운영 복잡성↑ | 신중 적용 (비용 수용 시) |
| 레거시 내부 회계 배치 | 정확성 최우선·일괄 처리 가능 | 배치시간·스루풋 | 스케줄 조정으로 부담 완화 | 적합 (배치 창 활용) |
비즈니스 손실 비용이 크고 경쟁적 업데이트가 빈번한 도메인 (금융·예약 등) 에는 Serializable 이 적합하다. 반대로 대규모 읽기·고동시성 OLTP 에는 성능 저하가 크므로 완화된 격리 (Repeatable Read / Read Committed) 나 아키텍처 대안 (CQRS, 복제) 을 권장한다. 분산 환경은 전역 직렬성 도입 시 레이턴시·운영 복잡성도 함께 수용해야 한다.
엔진별 Serializable 구현 비교표
아래 표는 PostgreSQL / MySQL(InnoDB) / Oracle / SQL Server 네 DB 엔진의 Serializable 격리 수준에 대한 실무 요약이다.
| 엔진 | 구현 방식 (요지) | 설정 예시 (세션/DB) | 직렬화 실패/부작용 | 실무 주의사항 (요약) |
|---|---|---|---|---|
| PostgreSQL | MVCC + SSI (Serializable Snapshot Isolation). 충돌 패턴을 감지하면 트랜잭션을 abort(직렬화 실패 발생) → 클라이언트 재시도 필요. | 세션: SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;기본: default_transaction_isolation = 'serializable' (postgresql.conf) | serialization failure 예외 (트랜잭션 abort) 발생. | 재시도 로직 필수. 장기 트랜잭션은 언두/버전 부담 유발. 성능·충돌율 측정 후 적용 범위 결정. |
| MySQL (InnoDB) | MVCC + 갭 락/next-key lock 또는 락 기반 동작. SERIALIZABLE 모드에서는 일부 SELECT 가 공유 락 (잠금 읽기) 으로 동작해 직렬성 확보. | 세션: SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; | 락 대기·데드락 증가 가능. 복제 환경에서 행동 차이 (특히 statement-based 복제) 유의. | 인덱스 설계·쿼리 패턴에 민감 (갭락 유발). 워크로드 벤치 후 적용. |
| Oracle | UNDO 기반 read consistency + SERIALIZABLE 지원. Oracle 의 SERIALIZABLE 은 문맥상 트랜잭션 수준의 일관성 제공; 충돌 시 ORA-08177 등 직렬화 예외 발생 가능. | 세션: ALTER SESSION SET ISOLATION_LEVEL = SERIALIZABLE; | ORA-08177: can't serialize access for this transaction 등 발생 → 애플리케이션 재시도 필요. | 기본은 READ COMMITTED. Serializable 사용 시 동시성 영향·에러 처리 (재시도) 설계 필요. |
| SQL Server | 전통적 락 기반 (범위 locks) 으로 SERIALIZABLE 구현. 대안으로 Snapshot Isolation / RCSI 제공 (버전 기반). Serializable 은 범위 락으로 팬텀 억제. | 세션: SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;또는 DB 옵션: ALTER DATABASE … SET ALLOW_SNAPSHOT_ISOLATION ON; | 락 대기·데드락↑. Snapshot 사용 시 tempdb 버전스토어 증가. | 긴 트랜잭션/쓰기 집중시 성능 저하·데드락 위험. RCSI 나 Snapshot 과 비교 검토. |
설정 예시 (즉시 쓸 수 있는 스니펫)
Postgres (세션 단위)
MySQL/InnoDB (세션 단위)
Oracle (세션 단위)
SQL Server (세션 단위)
주의: DB 옵션으로 기본격리 수준을 변경하면 전체 서비스 영향이 크므로 세션/트랜잭션 단위 적용을 먼저 검증하라.
실무적 주의사항—핵심 체크리스트
범위 최소화: Serializable 은 가능한 한 * 핵심 경로 (정산/결제 등)* 에만 적용. 전체 서비스 전역 적용은 비용이 큼.
트랜잭션을 짧게: I/O/네트워크를 줄이고 트랜잭션 내 작업 시간을 최소화해 락 보유/버전 누적을 방지.
재시도 (Retry) 전략 준비: SSI/Oracle 의 직렬화 실패 또는 락 충돌 시 재시도 로직 (지수 백오프 + 최대 재시도 횟수) 과 idempotency 확보 필요.
모니터링 지표 구성: 직렬화 실패율, 재시도율, 락 대기 시간, deadlock frequency, 언두/tempdb 버전스토어 성장 등.
쿼리·인덱스 튜닝: MySQL 갭락·range lock 은 인덱스·WHERE 절에 민감 → 적절한 인덱싱으로 락 범위 축소.
복제 환경 검증: 비동기 복제/읽기 리플리카와 결합 시 일관성 인식 (읽기 지연) 문제를 사전 테스트.
부하 테스트 필수: 실제 트래픽/동시성 수준으로 성능·직렬화 실패·데드락 시나리오를 재현해 검증.
간단한 재시도 템플릿 (Python 의사코드)
| |
SerializationError는 엔진별 예외 (예: Postgres 의serialization_failure, Oracle 의ORA-08177) 를 잡아 처리하라.- 작업은 아이덴포턴트 (idempotent) 하게 설계해 재시도 안전성을 확보할 것.
적용 권장 절차 (한줄 요약)
비즈니스 요구로 직렬성 필요성을 문서화 (어떤 불변식/계산을 보호할지).
해당 경로를 트랜잭션 단위로 식별하고 트랜잭션 길이·쿼리 패턴을 최적화.
엔진별 동작 (락/SSI/버전스토어) 이해 후 세션 레벨로 시범 적용.
부하 테스트 (동시성 높게) → 직렬화 실패·데드락·성능 영향 측정.
재시도·모니터링을 포함한 운영 룰을 수립하고 롤아웃.
실무 적용 및 사례
실습 예제 및 코드 구현
실습 예제: 트랜잭션 격리 수준 SERIALIZABLE 적용
목적
- 데이터베이스에서 직렬화 격리 수준을 SQL 로 직접 설정하고, 동시성 문제가 차단되는지 검증한다.
사전 요구사항
- MySQL, PostgreSQL 또는 Oracle DB
- DB 클라이언트 (예: DBeaver, DataGrip)
- 트랜잭션 테스트용 샘플 테이블
단계별 구현
- 1 단계: 트랜잭션 시작 및 격리 수준 지정
실무적으로, 두 명의 사용자가 동시에 동일한 레코드를 수정하거나 읽으려고 시도할 때 한 명은 반드시 락 대기 혹은 롤백이 발생된다.[1][2]
- 2 단계: 동시성 테스트
- 새로운 세션에서 동일한 데이터에 접근 시도
실행 결과
- 하나의 트랜잭션이 종료될 때까지 다른 트랜잭션은 해당 레코드에 접근 불가 (lock wait, deadlock 등 발생).
- Dirty Read, 팬텀 리드, 비반복 읽기가 완벽 차단됨을 인증.
추가 실험
- 동일 쿼리에 Repeatable Read, Read Committed 격리 수준을 비교 적용하여, 동시성/일관성 측면에서 차이점 검증.
실습 예제: 쓰기 스큐 방지 (좌석/의사 On-call 예제 변형)
목적
- REPEATABLE READ/SNAPSHOT 에서 가능한 쓰기 스큐를 SERIALIZABLE 로 차단하고 재시도 루프를 구현한다.
사전 요구사항
- PostgreSQL 또는 CockroachDB
- Python 3.10+,
psycopg[binary]또는asyncpg
단계별 구현
- 스키마 및 샘플 데이터
- 경합 트랜잭션 시뮬레이터 (Python, 동시 실행)
| |
실행 결과
- SERIALIZABLE 에서는 한 트랜잭션이 SerializationFailure 로 중단 후 재시도, 불변식 보전.
- 낮은 격리에서는 두 트랜잭션이 모두 off 로 만들어 불변식 위반 가능.
추가 실험
- 인덱스 제거/추가, WHERE 조건 범위 확대로 충돌률·대기시간 변화 측정.
실제 도입 사례
실제 도입 사례: 핀테크 실시간 잔고 관리
배경 및 도입 이유
- 다중 서비스가 동일 계좌를 갱신. 잔고 음수/이중 결제 방지 위해 직렬가능 격리 채택.
구현 아키텍처
graph TB APIGW[API Gateway] --> SVC[Ledger Service] SVC --> DB[(RDBMS: Serializable)] SVC --> Q[Outbox->Kafka] Q --> SUB[Downstream Subscribers]
핵심 구현 코드 (개념)
성과 및 결과
- 결제 오류 0 건 유지, 재시도율 1~3% 범위 관리, 평균 지연 15% 증가.
교훈 및 시사점
- Outbox 패턴으로 외부 전파 일관성 보장. 핫 파티션 (특정 계좌) 완화 위해 샤딩/파티셔닝 적용.
실제 도입 사례: 금융 결제 시스템
배경 및 도입 이유
- 다수의 사용자 및 거래가 동시에 발생하는 환경에서 오류 없는 잔고 관리와 거래내역의 정확성을 보장해야 함.
- 데이터 일관성 통해 거래의 신뢰성과 법적 증명력을 확보.
구현 아키텍처
graph TB
UserA[사용자 A 결제 요청] --> DBTransaction[DB 트랜잭션 시작]
UserB[사용자 B 결제 요청] --> DBTransaction
DBTransaction --> AccountLock[Shared/Exclusive Lock]
AccountLock --> Commit[커밋/롤백 및 락 해제]
설명: 여러 사용자의 동시 요청에 대해 트랜잭션 단위로 락 제어가 자동 적용되어, 잔고 불일치·중복 거래 등이 원천적으로 차단됨.[3][1]
핵심 구현 코드
| |
각 줄에서 트랜잭션 격리 수준 설정, SELECT 시 FOR UPDATE 로 락 적용, 갱신 후 커밋까지 완전 직렬화 보장한다.
성과 및 결과
- 거래 오류율 0% 달성
- 동시성 문제 (팬텀 리드, 비반복 읽기, 더티 리드) 전면 차단
- 데이터 정합성·감사 추적성 강화
교훈 및 시사점
- 동시성 제어에 힘을 줌으로써 대량 처리 환경에서는 성능 저하가 불가피. 트랜잭션 큐 분리, 배치 처리 등 활용 필요.
- 단일 트랜잭션 실패에 대한 롤백·재시도 정책을 반드시 적용해야 시스템 안정성 및 실무 운용성 확보 가능.[2][3]
5 단계: 최종 정리 및 학습 가이드
내용 종합
Serializable 은 데이터 일관성을 최우선으로 보장하는 격리 수준으로, 여러 트랜잭션의 동시 실행 결과를 어떤 단일 직렬 순서의 결과와 동일하게 만든다.
이를 위해 전통적으론 엄격 2 단계 잠금 (Strict 2PL) 을 사용해 자원을 잠금으로써 물리적으로 간섭을 차단하고, 현대 DB 는 MVCC+SSI 또는 OCC 같은 기법으로 읽기 성능을 유지하면서 커밋 시 충돌을 검출·해결한다.
장점은 모든 동시성 문제 (Dirty, Non-repeatable, Phantom, Write-skew 등) 를 원천 차단한다는 점이고, 단점은 처리량 저하·데드락·재시도 증가·분산 환경에서의 높은 합의 비용이다.
실무에서는 핵심 트랜잭션에 국한해 적용하거나, 선택적 상향·리플리카 분리·사가/Outbox 등 보완 패턴을 병행한다.
실무 적용 가이드
| 항목 | 설명 | 왜 필요한가 | 권장 구현/설정 예시 | 모니터링 지표 (권장) | 우선도 |
|---|---|---|---|---|---|
| 적용 범위 결정 | 어떤 트랜잭션에 Serializable 적용할지 정의 | 모든 트랜잭션 전면 적용의 비용 회피 | 비즈니스 불변식 영향 트랜잭션 우선 (예: 결제, 정산) | 적용된 TX 비율, 영향 트랜잭션 TPS | 높음 |
| 불변식 목록화·테스트 | 시스템 불변식 (비즈니스 규칙) 문서화 및 자동화 테스트 | 요구사항 검증·회귀 방지 | 불변식 기반 유닛/통합 테스트 케이스 작성 | 불변식 위반 케이스 수 | 높음 |
| 인덱스/쿼리 범위 점검 | 범위 쿼리·인덱스가 락/팬텀에 미치는 영향 검토 | 팬텀·락 확대 방지, 성능 최적화 | 범위 인덱스 최적화, 쿼리 리팩터링 | slow query, lock wait by query | 높음 |
| 재시도 정책·Idempotency | 직렬화 실패·deadlock 대비 재시도/멱등성 설계 | 클라이언트 안정성 확보, 중복 처리 방지 | 멱등 키, 지수 백오프, 최대 재시도 횟수 | serialization failures, retry rate | 높음 |
| 트랜잭션 길이 최소화 | 트랜잭션을 짧게 유지하도록 코드·API 설계 | 장기 txn 이 GC·락 문제 유발 방지 | 읽기/검증은 분리, 배치로 처리 | long-running txns 수, avg txn duration | 높음 |
| 장기 읽기 분리 | 읽기 집약 경로는 리플리카/OLAP 로 분리 | 원본 DB 락·스냅샷에 영향 줄이기 | 읽기 복제본, CQRS 패턴 적용 | replica lag, read traffic on primary | 중간 |
| 락/데드락 모니터링 | 락 대기·데드락 자동 감지·알람 | 운영 장애 사전 대응 | DB 프로메테우스 메트릭, alert 룰 | lock_waits, deadlocks/hour, max wait | 높음 |
| serialization failure 모니터링 | SSI/Serializable 실패 탐지 및 대응 | 재시도·고객영향 최소화 | DB error 코드 수집·알람 | serialization_failures, abort rate | 높음 |
| 분산 일관성 패턴 | 서비스 경계 일관성 처리 전략 수립 | 마이크로서비스 환경에서 일관성 유지 | Outbox, SAGA, 2PC(권장하지 않음 일반적) | cross-service failure rate | 중간 |
| POC·벤치마크 | 실제 시나리오로 성능·정합성 측정 | 변화 영향 계량화·SLO 설정 | pgbench/oltpbench 테스트, 시뮬레이션 | TPS, p95/p99 latency, abort % | 높음 |
| 운영 플레이북 | 사고 시 대응 시나리오·절차 (자동/수동) | 장애 대응 속도 향상 | Alarm -> Auto-kill threshold -> 재시도 정책 | MTTR, incidents resolved by playbook | 높음 |
| 배포 전략 | 격리 수준/설정 점진 적용·롤백 플랜 | 변경 리스크 최소화 | 기능 플래그, Canary 배포 | failed deploys, rollback count | 중간 |
학습 로드맵
| Phase | 포커스 (요약) | 핵심 학습 주제 | 학습 목표 | 실무 연관성 | 권장 산출물 |
|---|---|---|---|---|---|
| 1 (기초) | 이론적 토대 | 스케줄 이론, 직렬가능성, ACID 개념 | 격리 수준의 의미와 이상현상 (Dirty/Non-repeatable/Phantom) 이해 | 설계·검증의 이론 근거 | 이론 요약 노트 + 이상현상 예제 (간단 SQL) |
| 2 (핵심) | 로컬 동시성 제어 | 2PL(Strict/2PL), MVCC, OCC, SSI 개념·알고리즘 | 메커니즘 차이 이해 및 장단점 분석 | DB 엔진 선택·튜닝 근거 | 알고리즘 비교 리포트 + 간단 시뮬레이터 결과 |
| 3 (실습) | DB 별 구현 · 실험 | Postgres/MySQL/Oracle/SQL Server 에서 격리수준·재현 시나리오 | 엔진별 동작 차이 확인 및 재현 능력 확보 | 실제 서비스 DB 설정·테스트 | 엔진별 재현 스크립트 + 결과 보고서 |
| 4 (튜닝) | 성능·운영 | 락/버전 스토어 모니터링, 트랜잭션 단축, 인덱스 영향 | 성능 병목 진단·완화 기술 습득 | 프로덕션 안정성 확보 | 부하 테스트 리포트 (p95,p99,재시도율 등) |
| 5 (분산·대안) | 분산 트랜잭션·패턴 | 2PC, Saga, Outbox, 유효성 검증 패턴 | 분산 환경에서 일관성/가용성 설계 역량 | 마이크로서비스·글로벌 시스템 설계 | 분산 시나리오 설계서 + 시뮬레이션 결과 |
| 6 (운영) | 정책·모니터링 | 재시도·아이덴포턴시 전략, SLO/지표, 알림 | 운영 대응 체계 수립 | 운영 안정화·사후복구 | 운영 체크리스트 + 대시보드 템플릿 |
| 7 (심화) | 최신·연구 | SSI 내부 동작 심층, 분산 직렬화, 트랜잭션 합성 | 고급 최적화·연구 수준 이해 | 고성능 플랫폼 설계·논문 응용 | 심화 보고서 또는 PoC 코드 |
학습 항목 정리
| Phase | 항목 | 목표 (learning goal) | 실습/과제 | 평가 기준 | 선수지식 |
|---|---|---|---|---|---|
| 1 | 스케줄 이론·직렬가능성 | 트랜잭션 스케줄과 직렬가능성 증명 이해 | 스케줄 예제 만들기 (직렬/비직렬 판정) | 스케줄 판정 보고서 | SQL 기초 |
| 1 | 이상현상 분류 | Dirty/Non-repeatable/Phantom 정의·재현 | 간단 SQL 로 이상현상 재현 | 재현 스크립트 제출·해석 | SQL 트랜잭션 문법 |
| 2 | 2PL(Strict/Basic) | 락 획득/해제 규칙·데드락 이해 | 락 시나리오 작성·deadlock 유발 실험 | deadlock 분석 리포트 | 트랜잭션 기초 |
| 2 | MVCC 원리 | 버전관리·언두·스냅샷 동작 이해 | Postgres MVCC 스냅샷 실험 | 결과 비교 리포트 | DB 설치 경험 |
| 2 | OCC / SSI | 낙관적 제어 (충돌탐지) 메커니즘 습득 | SSI 충돌 케이스 재현 (Postgres) | 직렬화 실패율 측정 | MVCC 이해 |
| 3 | 엔진별 실습 (Postgres) | Postgres 격리수준·SSI 동작 실습 | 재현 스크립트 실행·분석 | 실험 결과 리포트 | Phase1–2 완료 |
| 3 | 엔진별 실습 (MySQL/InnoDB) | gap lock·next-key lock 등 재현 | 인덱스/쿼리 패턴 실험 | 락 대기·성능 비교 | Phase1–2 완료 |
| 3 | 엔진별 실습 (Oracle/SQLServer) | 각 엔진의 직렬화/예외 처리 확인 | 직렬화 실패/ORA-08177 등 재현 | 재현 및 대응 보고서 | Phase1–2 완료 |
| 4 | 성능튜닝 (트랜잭션 단축) | 트랜잭션 최적화 기법 습득 | 트랜잭션 리팩토링 실습 | p95/p99 개선 지표 측정 | 이전 실습 완료 |
| 4 | 모니터링 지표 | 핵심 메트릭 정의·대시보드 구성 | Grafana/Prometheus 예제 구성 | 알람 시나리오 시연 | 운영 기초 |
| 5 | 분산 트랜잭션 (2PC) | 2PC 흐름·장단점 이해 | 간단 분산 트랜잭션 시뮬레이션 | 실패/복구 시나리오 보고서 | 네트워크 기초 |
| 5 | Saga / Outbox | 보상 패턴·Eventual Consistency 설계 | Saga 시나리오 구현 (Microservice) | 일관성 사례 분석 | 메시지 큐 기초 |
| 6 | 운영 정책 | 재시도·백오프·아이덴포턴시 전략 수립 | 정책 문서 작성·테스트 | 운영 점검 체크리스트 | 이전 실습 완료 |
| 7 | 최신 연구 (SSI 심화) | SSI 내부 알고리즘 이해·판단 | 논문 읽기·간단 재현 | 비평 리포트·PoC | 알고리즘·DB 심화 |
용어 정리
| 카테고리 | 용어 (영문, 약어) | 정의 | 관련 개념 | 실무 활용 |
|---|---|---|---|---|
| 핵심 | 직렬가능성 (Serializability) | 다수 트랜잭션 실행 결과가 어떤 순차 실행 결과와 동일함을 보장 | 충돌 직렬성, 뷰 직렬성, 스케줄 | 격리 수준 평가, 무결성 원칙 |
| 핵심 | 직렬화 격리 수준 (Serializable Isolation Level) | 모든 트랜잭션을 논리적 순차 실행과 동일하게 보장하는 격리 수준 | ACID, 락/검증 | 금융·회계 핵심 트랜잭션 적용 |
| 핵심 | 팬텀 (Phantom) | 동일 쿼리 재조회 시 결과 집합에 새 레코드가 출현하는 현상 | 격리 수준, 범위 락 | 범위 쿼리 설계·검증 필요 |
| 핵심 | 쓰기 스큐 (Write Skew) | 독립적 업데이트로 도메인 불변식 (제약) 이 깨지는 현상 | Snapshot Isolation | SI 적용 시 불변식 점검 |
| 구현 | 락 (Lock) | 데이터 접근 제어 (공유/배타/넥스트키 등) | Deadlock, Lock Escalation | 동시성 제어·잠금 정책 설계 |
| 구현 | 2 단계 잠금 (2PL / Strict 2PL) | 성장·축소 단계로 잠금 관리, Strict 는 X 락 커밋까지 유지 | Conflict Serializability | 전통적 직렬화 구현 |
| 구현 | MVCC (Multi-Version Concurrency Control) | 여러 버전으로 읽기/쓰기 분리 (스냅샷) | Snapshot Isolation, VACUUM | 읽기 중심 워크로드 성능 향상 |
| 구현 | 스냅샷 격리 (Snapshot Isolation, SI) | 트랜잭션 시작 시 스냅샷 읽기, 일부 이상현상 허용 | MVCC, Write Skew | 고동시성 읽기 최적화 |
| 구현 | SSI (Serializable Snapshot Isolation) | SI 의 위험구조 감지·abort 로 직렬성 보장 | MVCC + 충돌 감지 | Postgres 스타일 serializability |
| 운영 | 데드락 (Deadlock) | 상호 잠금 대기로 트랜잭션이 모두 정지 | Deadlock Detection, Rollback | 자동 탐지·롤백·운영 알람 필요 |
| 운영 | 멱등성 (Idempotency) | 동일 연산 반복해도 부작용 없음 | 재시도, 토큰 | 네트워크/재시도 시 안전성 보장 |
| 운영 | 모니터링 지표 | lock-wait, deadlock/sec, long-running tx, undo size 등 | APM, Prometheus | 운영 경보·최적화 근거 |
| 고급 | 뷰 직렬성 (View Serializability) | 외형상 동일한 뷰를 보장하는 직렬성 개념 (충돌보단 뷰 기반) | Serializability 이론 | 이론적 분석·검증 |
| 고급 | 분산 강직렬성 (Spanner-like) | 분산 환경에서 외부 일관성/serializability 보장 | TrueTime, 분산 합의 | 글로벌 금융·분산 원장 요구 |
참고 및 출처
- 트랜잭션 격리 수준 완벽 가이드: 실무에서 만나는 문제와 해결법
- 트랜잭션 격리 수준 & 동시성 제어
- 트랜잭션 격리 수준(isolation level) | 기록은 기억의 연장선
- 트랜잭션 격리 수준과 동시성 제어 이야기 (2) : SERIALIZABLE과 Deadlock
- 트랜잭션의 격리수준, ACID
- 트랜잭션 격리 수준과 실무에서의 활용
- [DB] MySQL과 PostgreSQL의 격리 수준 (w/ 이상 현상)