DB 엔지니어링 — 고급 주제·CAP·Saga·Caching

2026-05-03확률과 통계 마스터 노트

데이터베이스 엔지니어링 마스터 노트 시리즈 8편 (마지막). Connection Pooling이 처리량을 결정하는 이유, 분산 트랜잭션 2PC vs Saga, Eventual Consistency가 표준이 된 이유, CAP·PACELC 정리의 실제 의미, Cache Invalidation 5가지 패턴, Materialized View 활용까지 — 시리즈 마무리.

이 글은 데이터베이스 엔지니어링 마스터 노트 시리즈의 마지막 여덟 번째 편입니다. 1~7편이 토대였다면, 이번엔 운영·분산 시스템에서 마주치는 고급 주제 모음.

CAP·PACELC가 분산 DB 선택을 결정. Connection Pool 잘못 잡으면 처리량 폭락. Saga 없이 마이크로서비스 트랜잭션 X. Cache Invalidation은 영원한 문제.

Connection Pooling

문제 — 연결은 비싸다

새 PostgreSQL 연결:
  - TCP handshake
  - SSL 협상
  - 인증
  - Backend process fork
  → 50 ~ 수백 ms

PostgreSQL 연결당 RAM ~10MB

수천 동시 연결 = 수십 GB RAM + 컨텍스트 스위칭 폭발.

해결 — Connection Pool

App ← (재사용) ← Pool ← (소수 영구) ← DB

App이 connection을 반납·재사용. DB는 적은 수의 영구 연결만 유지.

도구:

  • PgBouncer (PostgreSQL) — Transaction Pooling
  • ProxySQL (MySQL)
  • HikariCP (Java) — 애플리케이션 사이드 풀
  • AWS RDS Proxy

Pool 모드 (PgBouncer)

모드 의미
Session 클라이언트 연결 종료 시까지 점유
Transaction 트랜잭션 끝나면 반납 (가장 일반적)
Statement 매 쿼리 후 반납 (트랜잭션 X)

여기서 정말 중요한 시험 함정 — Transaction Pooling 사용 시 prepared statement·session 변수 주의. Session에 묶인 기능 못 씀. 코드에서 바인딩 사용.

분산 트랜잭션

2PC — Two-Phase Commit

Coordinator → 참여 노드 모두에 PREPARE
  각 노드: 트랜잭션 준비 + 응답
Coordinator → 모두 OK면 COMMIT, 하나라도 실패면 ROLLBACK
  각 노드: 결정 적용

문제:

  • Coordinator 장애 = 무한 대기 (블로킹)
  • 느림 (모든 노드 대기)
  • 운영 복잡

여기서 시험 함정이 하나 있어요. 2PC는 사실상 마이크로서비스에서 거의 안 씀. 이론적·과거 표준이지만, 모던 분산 시스템은 Saga 선호.

Saga Pattern

각 단계를 독립 트랜잭션으로 분해 + 보상 트랜잭션 정의.

주문 처리 Saga:
  1. 주문 생성 → (실패 시 X)
  2. 결제 → (실패 시 보상: 주문 취소)
  3. 재고 차감 → (실패 시 보상: 결제 환불, 주문 취소)
  4. 배송 → (실패 시 보상: 재고 복구, 환불, 주문 취소)

종류:

  • Choreography — 각 서비스가 이벤트 발행·구독 (분산)
  • Orchestration — 중앙 코디네이터가 흐름 제어 (집중)

여기서 정말 중요한 시험 함정 — Saga는 ACID 보장 X, BASE만. 실시간으론 일관성 깨진 상태 보일 수 있음. 보상 가능 비즈니스에만 적용 (송금·주문 OK / 의료 처방 X).

Eventual Consistency vs Strong Consistency

Strong Consistency

쓰기 → 즉시 모든 노드 반영
모든 읽기 = 최신 값

비싼 비용. 동기 복제·합의 알고리즘 필요.

Eventual Consistency

쓰기 → 일부 노드만 즉시 반영
시간 지나면 모두 반영
중간에 stale 읽기 가능

저렴. 비동기 복제. 분산 시스템 표준.

사용 사례

영역 일관성
금융 잔액 Strong
**재고 (정확) Strong (또는 보상 가능 Saga)
타임라인·게시물 수 Eventual
분석·대시보드 Eventual

CAP 정리

분산 시스템은 다음 3가지 중 2개만 보장 가능.

C - Consistency (모든 노드 같은 값)
A - Availability (요청 항상 응답)
P - Partition Tolerance (네트워크 단절 견딤)

P는 현실에서 불가피 → 실제 선택은 CP vs AP.

시스템 분류
RDBMS (단일 노드) CA (분산 X)
HBase·MongoDB(단일 primary) CP
Cassandra·DynamoDB·Riak AP
Spanner·CockroachDB CP (특수)

여기서 시험 함정이 하나 있어요. CAP은 "장애 시" 트레이드오프. 정상 시는 다 됨. 네트워크 분할 발생 시 C 또는 A 중 하나 포기.

PACELC — CAP 보충

P (Partition) → A or C 선택
E (Else, 정상 시) → L (Latency) or C (Consistency) 선택

CAP은 장애만 다룸. PACELC = 정상 시까지.

시스템 PACELC
Cassandra PA / EL (둘 다 가용성·지연 우선)
MongoDB PA / EC (가용성·일관성)
HBase PC / EC (둘 다 일관성)
DynamoDB PA / EL

여기서 정말 중요한 시험 함정 — PACELC가 CAP보다 실무 의사 결정에 유용. 정상 시 latency vs consistency 선택이 더 자주 부딪힘.

Cache Invalidation — 영원한 문제

"There are only two hard things in Computer Science: cache invalidation and naming things." — Phil Karlton

패턴 1 — Cache-Aside (Lazy Loading)

def get_user(id):
    user = cache.get(f"user:{id}")
    if user:
        return user
    user = db.query("SELECT * FROM users WHERE id = ?", id)
    cache.set(f"user:{id}", user, ttl=300)
    return user

def update_user(id, ...):
    db.update(...)
    cache.delete(f"user:{id}")  # 무효화

가장 일반적. 단순.

패턴 2 — Write-Through

쓰기 시 cache·DB 동시 업데이트.

def update_user(id, ...):
    cache.set(f"user:{id}", new_value)
    db.update(...)

장점 — cache 항상 최신. 단점 — 쓰기 느림.

패턴 3 — Write-Behind (Write-Back)

쓰기는 cache만, DB는 비동기.

def update_user(id, ...):
    cache.set(f"user:{id}", new_value)
    queue.publish(("update_user", id, ...))  # 비동기 DB 반영

장점 — 쓰기 매우 빠름. 단점 — 데이터 손실 위험 (cache 다운).

패턴 4 — TTL 만료

단순히 시간 후 자동 삭제. 일관성 ↓ but 단순.

패턴 5 — Pub/Sub Invalidation

DB 변경 시 모든 cache 노드에 무효화 메시지.

여기서 시험 함정이 하나 있어요. Cache Aside + DB 업데이트 후 cache 삭제 순서. 잘못된 순서는 race 발생. 표준 — DB 먼저 commit → cache delete (set X). delete가 race에 안전.

Materialized View

뷰의 결과를 물리적으로 저장.

-- PostgreSQL
CREATE MATERIALIZED VIEW monthly_sales AS
SELECT date_trunc('month', order_date) AS month,
       SUM(amount) AS total
FROM orders
GROUP BY 1;

-- 새로고침
REFRESH MATERIALIZED VIEW monthly_sales;

-- 동시 조회 가능 (CONCURRENTLY)
REFRESH MATERIALIZED VIEW CONCURRENTLY monthly_sales;

장점 — 무거운 집계 미리 계산, 조회 즉시. 단점 — 신선도 ↓, 새로고침 비용.

용도 — 대시보드·통계·자주 안 변하는 집계.

Database Federation

여러 DB를 논리적으로 하나처럼.

Application
   ↓
Federation Layer
   ├── DB A (Users)
   ├── DB B (Products)
   └── DB C (Orders)

장점 — 도메인별 분리, 독립 확장. 단점 — Cross-DB JOIN 어려움.

도구 — PostgreSQL FDW (Foreign Data Wrapper), Presto, Trino.

Read/Write Pattern 결정

사용 사례 패턴
읽기 매우 많음 Read Replica + 캐시
쓰기 매우 많음 샤딩 + 비동기 처리
분석 쿼리 Column Store + ETL
실시간 분석 OLAP DB (ClickHouse)
엄격 일관성 단일 노드 + Read Replica
글로벌 분산 Multi-region (AP)

CQRS — Command Query Responsibility Segregation

쓰기 모델과 읽기 모델 분리.

Command (쓰기): 정규화된 OLTP DB
   ↓ 이벤트 발행
Query (읽기): denormalized OLAP / 검색 인덱스 / 캐시

장점 — 각 모델 최적화. 단점 — 복잡, eventual consistency.

용도 — 큰 시스템, 다양한 조회 패턴.

Event Sourcing

상태 대신 이벤트의 시퀀스 저장.

전통: account.balance = 100 (현재 값만)
Event Sourcing:
  - AccountCreated (initial 0)
  - Deposited 100
  - Withdrawn 30
  - Deposited 30
  → 현재 값 = 이벤트 재생 결과 100

장점 — 모든 변경 기록, 시간 여행 가능, 감사 자연스러움. 단점 — 스토리지 ↑, 쿼리 복잡 (CQRS 흔히 결합).

시리즈 마무리 — 8편 종합

1편부터 8편까지의 핵심:

주제 한 줄
1 ACID 트랜잭션의 4 보장. Isolation Level의 Phantom·Repeatable 차이
2 Indexing B+Tree·EXPLAIN·Composite Leftmost·Bloom Filter
3 Partitioning Range·List·Hash·Pruning·UNIQUE 제약
4 Sharding Consistent Hashing·Cross-Shard JOIN·샤딩 키 신중 선정
5 Replication 동기 vs 비동기·Lag·Failover·Split-Brain
6 Concurrency Locking·MVCC·Optimistic·Deadlock
7 Internals Page·WAL·Buffer Pool·Row vs Column
8 Advanced Pool·2PC vs Saga·CAP·PACELC·Cache·CQRS

DB 엔지니어링은 트레이드오프 인식의 학문. 한 가지 정답 X — 워크로드·일관성 요구·확장성 요구에 따라 선택.

시험 직전 한 번 더 — 자주 헷갈리는 함정 모음

여기까지가 8편의 핵심입니다. 시험 직전 또는 실무에서 헷갈릴 때 다시 펼쳐 볼 수 있게 압축 노트로 마무리할게요.

  • Connection Pool = 연결 재사용, 처리량의 핵심
  • 도구 — PgBouncer·ProxySQL·HikariCP·RDS Proxy
  • Pool 모드 — Session / Transaction(보통) / Statement
  • Transaction Pool 시 prepared statement·session 변수 주의
  • 2PC = 동기 분산 트랜잭션, Coordinator 장애 무한 대기
  • 모던 = 거의 안 씀
  • Saga = 단계 + 보상 트랜잭션, ACID X, BASE
  • Choreography(이벤트) vs Orchestration(중앙)
  • Strong vs Eventual Consistency
  • 금융·재고 = Strong / 타임라인·통계 = Eventual
  • CAP = 분산 시 C·A·P 중 2개 (P 불가피, 실제 CP vs AP)
  • CP — HBase·MongoDB(primary) / AP — Cassandra·DynamoDB
  • PACELC = 장애 시 + 정상 시 트레이드오프
  • 정상 시 Latency vs Consistency
  • Cache Invalidation 5 패턴 — Cache-Aside / Write-Through / Write-Behind / TTL / Pub/Sub
  • Cache-Aside = 가장 일반적, 표준
  • DB commit 후 cache delete (set X, race 안전)
  • Materialized View = 결과 물리 저장, REFRESH 필요
  • 무거운 집계 미리 계산
  • Database Federation = 여러 DB 하나처럼, FDW·Presto
  • Read/Write 패턴 — Read 많음=Replica·캐시 / Write 많음=샤딩
  • CQRS = Command/Query 모델 분리
  • 정규화 OLTP + denormalized OLAP
  • Event Sourcing = 상태 X, 이벤트 시퀀스
  • CQRS와 흔히 결합
  • 감사·시간 여행 자연스러움

시리즈 다른 편 (시리즈 마지막)

공식 문서: Martin Kleppmann의 Designing Data-Intensive Applications — DB 엔지니어링의 깊이를 다지는 정평 있는 도서.

데이터베이스 엔지니어링 시리즈는 여기서 마무리. 1편부터 8편까지의 흐름이 머리에 남으면 시스템 설계·면접·운영 모두에서 든든한 토대가 됩니다.

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!