“단일 DB 가 *터졌다”전통 적 시스템최대 fear. 해결책 은 2 가지 뿐 : vertical scale (한 대를 더 크게) 또는 horizontal scale (여러 대 로 나눔). 전자 는 *물리적 상한. 후자 는 *복잡성 의 지옥.

복잡성 의 지옥어휘분산 시스템. CAP 정리, BASE 의 결정, Saga 의 보상, 2PC 의 차단, CDC 의 우회, Raft / Paxos 의 합의. 이 어휘 를 *알아야 마이크로서비스 의 *경계 결정, eventual consistency 의 *trade-off, outbox 패턴 의 *왜근거 있는 선택 이 된다.

이 글은 기본기 시리즈 의 *분산 편CAP 의 진짜 의미, 3 가지 trade-off 의 결정 매트릭스, 7 가지 일관성 모델, 분산 트랜잭션 의 *4 가지 패턴 (2PC / Saga / Outbox / Sourcing), 합의 알고리즘 (Raft, Paxos) — 을 시스템 설계자 의 *깊이 로 정리한다.

기본기 시리즈 :


TL;DR — 한 줄 결론

분산 시스템 의 본질7 가지 : (1) CAPPartition 발생 시 *C 와 A 중 택일, (2) BASEstrict ACID 대신 *eventual consistencythroughput 교환, (3) 일관성 spectrum — Linearizability → Sequential → Causal → Eventual 의 7 단계, (4) 2PCatomicity 의 *blocking 동기 합의, (5) Sagalong-lived transaction 의 *보상 (compensating), (6) Outbox + CDCdual-write 의 *우회, settlement 의 핵심 패턴, (7) Raft / Paxosleader-based 합의 의 *현대 표준 (etcd, ZooKeeper, Kafka KRaft). MSA 의 *모든 결정 의 *근거이 7 가지 trade-off명시 적 선택. 깊이 는 *어떤 패턴 을 *왜 선택 했는지 설명 할 수 있는 능력 이 만든다.


1. 왜 *분산 시스템 인가

1.1 단일 머신 의 *3 가지 벽

한계
CPU 60 코어 (Threadripper 9995WX) 정도 가 현실적 상한
메모리 TB 단위 가능 하지만 DDR5 8 채널 정도. cache localitylatency 증가
단일 실패점 노드 죽으면 서비스 0HA 불가능

어느 단일 머신수억 사용자 의 *throughput + availability 둘 다 동시에 보장 못 함.

1.2 분산 의 *3 가지 어려움

분산 시스템 = 여러 machine 이 *network 로 통신. 그 network 가 *불완전:

  1. Partial failure일부 노드 만 죽음. 살아있는 노드 가 *그 사실 을 *늦게 알아냄.
  2. Network partition네트워크 분리 가 *일시적 발생.
  3. Clock skew각 노드 의 *시계 가 *조금씩 다름. NTP 도 ms 단위 오차.

이 3 가지 가 *분산 의 *모든 복잡성 의 *원천.


2. CAP 정리

2.1 Eric Brewer 의 *2000 년 conjecture, 2002 년 증명**

Consistency, Availability, Partition tolerance — 3 가지 중 *최대 2 가지 만 동시 보장 가능*.

   
C (Consistency) 모든 노드 가 동일한 데이터 본다 (= Linearizability)
A (Availability) 살아있는 모든 노드 가 응답 한다
P (Partition tolerance) 네트워크 partition 시에도 시스템 계속 작동

2.2 진짜 의미 — *“P 발생 시 C vs A”**

P 는 선택 의 문제 가 아니다. 현실 의 *네트워크 는 *언젠가 partition 됨. 그러므로 분산 시스템 은 *P 를 항상 가짐. 진짜 선택 은 *partition 발생 시:

  • CP (Consistency 선택) — partition 시 일부 노드 응답 거부 (예: etcd, ZooKeeper, MongoDB primary-only)
  • AP (Availability 선택) — partition 시 모든 노드 응답 (옛 데이터 가능) (예: Cassandra, DynamoDB)

2.3 CAP 의 *오해 와 진실**

오해 1 : “우리 시스템 은 CA 다 (CP 도 AP 도 아님)”틀림. P 는 *선택 안 함. partition 일어나면 *어떻게 든 행동 해야 함. CA 는 *non-distributed 단일 머신 만.

오해 2 : “CP 는 항상 C 다”틀림. partition 없을 때 의 *Consistency 는 *isolation level 같은 *별도 개념. CAP 의 C 는 partition 시 만 중요.

오해 3 : “Cassandra 는 AP 라 C 가 없음”틀림. Cassandra 도 *tunable consistencyLOCAL_QUORUM / ALL 같은 write/read levelpartition 없을 때 C 보장 가능.

2.4 PACELC — *CAP 의 확장 (2010)**

Daniel Abadi2010 년 확장 : if Partition then A vs C, Else then Latency vs Consistency.

PACELC:
  P (Partition 있을 때) → A or C
  E (Else / partition 없을 때) → L (Latency) or C (Consistency)

partition 없는 *평상시 에도 strong consistency 는 *latency 대가 가 있음. quorum read = network round-trip 추가.

시스템 PACELC
MySQL primary-replica PA / EL (replica 가 lag)
PostgreSQL synchronous replication PC / EC (둘 다 strong)
Cassandra (QUORUM) PA / EL (lower latency 선택 가능)
DynamoDB PA / EL
etcd PC / EC
Spanner PC / EC (geographic — TrueTime)

3. BASE — *ACID 의 *반대편**

3.1 ACID vs BASE

  ACID (전통 RDBMS) BASE (분산)
A Atomic — all or nothing Basically Available — 항상 응답
C Consistent — invariant 보존 Soft state — 시간 지남 에 따라 상태 변할 수 있음
I Isolated — 동시 tx 영향 0  
D Durable — commit 후 영속 Eventually consistent — 결국 일관

BASE 는 *strict ACID 를 *throughput / availability 와 교환. 대부분 의 e-commerce, social media, IoTBASE 채택.

3.2 언제 ACID, 언제 BASE

ACID 가 필수:

  • 금융 (잔액 / 결제 / 정산)
  • 재고 (oversell 절대 불가)
  • 의료 / 법률 기록

BASE 가 합리적:

  • 사용자 프로필 / 게시물 / 좋아요수 초 지연 허용
  • 시계열 메트릭최근 데이터 우선
  • 추천 / 검색 인덱스eventual 충분

settlement (정산)ACID 필수. sns / sparta 검색BASE OK.


4. 일관성 Spectrum — *7 단계**

4.1 강한 순서

가장 강함 ↓                                                      가장 약함 ↓
[Linearizable] > [Sequential] > [Causal] > [Read-your-writes] > [Monotonic] > [Bounded staleness] > [Eventual]

4.2 각 단계 의 *정의 와 *예**

Linearizable (= Strict / Atomic Consistency) :

  • 외부 관찰자 가 *모든 operation 의 *전체 순서 합의. 각 operation 이 원자 적 으로 *그 사이 어딘가 의 순간 에 발생.
  • 단일 머신 의 atomicity 와 동등.
  • 예: etcd, ZooKeeper, Spanner.

Sequential :

  • 모든 노드 가 *같은 순서로 operation 봄. 하지만 그 순서 가 *실제 시간 과 다를 수 있음.
  • Lamport 1979.

Causal :

  • 인과 관계 가 있는 operation 만 *순서 보장. 동시 적 operation 은 *각 노드 에서 *다른 순서 가능.
  • vector clock 사용.

Read-your-writes :

  • 내가 쓴 데이터 는 *내가 다음 read 에서 *반드시 봄. 다른 사용자 는 늦게 봄 가능.
  • session affinity 로 구현.

Monotonic reads :

  • 내가 한 번 본 데이터 의 *옛 버전 을 *다시 보지 않음.

Bounded staleness :

  • 최대 X 초 (또는 X 회 write) 만큼 옛 데이터 가능. 그 이상 안 됨.
  • Azure Cosmos DB 의 공식 모델.

Eventual :

  • 언젠가 수렴. 언제모름.
  • DNS, S3 (옛날 read-after-write 제외).

4.3 trade-off — *Strong = Slow**

Linearizable:  매 write 마다 *quorum 합의* (예: Raft 의 majority). latency ↑↑
Eventual:      master 가 *즉시 응답*. *나머지 노드 는 *async 복제*. latency ↓↓

latency 와 *consistency 의 *반비례. 어느 지점 을 선택 하는가 가 시스템 설계 의 *핵심 결정.


5. 분산 트랜잭션 — *4 가지 패턴**

5.1 문제 설정

주문 시스템:
  1. Order 서비스 — order 생성
  2. Inventory 서비스 — 재고 감소
  3. Payment 서비스 — 결제 호출

→ *3 가지 가 *모두 성공* 해야 *order 완료*. *하나만 실패* 하면 *나머지 도 *롤백* 해야*.

이게 *분산 트랜잭션* 의 고전 문제.

5.2 패턴 1 — *2PC (Two-Phase Commit)**

[Coordinator]                    [Service A]   [Service B]   [Service C]

Phase 1 (Prepare):
  PREPARE ─────────────────────→
                         ←───── VOTE_YES (또는 NO, abort 시작)
  PREPARE ─────────────────────────────────────→
                                       ←───── VOTE_YES
  PREPARE ──────────────────────────────────────────────────→
                                                     ←───── VOTE_YES

Phase 2 (Commit):
  COMMIT ───────────────────────→ COMMIT ──────→ COMMIT ───→
  ACK ←──────────────────────── ACK ←─────── ACK ←────────

작동 시: 모두 원자 적 commit. 문제 :

  • Coordinator 가 *Phase 2 사이 죽으면참여자 가 *영원히 대기 (blocking).
  • latency 증가 — 모든 참여자 의 왕복 2 회.
  • availability 감소한 참여자 가 응답 안 하면 *전체 차단.

XA Transaction 의 표준. 현대 MSA 에선 *거의 사용 안 함. Java 의 JTAlegacy enterprise 영역.

5.3 패턴 2 — *Saga**

long-lived transaction짧은 local transaction 의 sequence + 보상 (compensating) 트랜잭션 으로 분해.

[Forward path]
   Step 1: Order 생성       (T1)
   Step 2: 재고 감소        (T2)
   Step 3: 결제 호출        (T3)
   Step 4: Order 확정       (T4)

[실패 시 보상]
   Step 3 실패 → T2' (재고 복구) + T1' (Order 취소)

2 종류:

  • Orchestration Saga — 중앙 coordinator (Saga manager)모든 단계 진행 / 보상 결정.
  • Choreography Saga — 각 서비스 가 이벤트 발행/구독 으로 분산 협력.

장점: blocking 없음, 각 단계 local 트랜잭션. 단점:

  • 보상 의 *복잡성 (이미 발송 한 SMS 는 어떻게 보상?)
  • isolation 약함 — 다른 사용자 가 중간 상태 볼 수 있음
  • 이중성 (idempotency) 의무 — 보상 트랜잭션 도 중복 실행 안전 해야

settlement / sparta MSA분산 처리 의 *기본 패턴.

5.4 패턴 3 — *Transactional Outbox**

single-write atomicityDB 변경 + 메시지 발행한 트랜잭션 안 에.

BEGIN;
INSERT INTO orders (...) VALUES (...);        -- 비즈니스 변경
INSERT INTO outbox (event, payload, ...) VALUES ('OrderCreated', ...);  -- 발행할 이벤트
COMMIT;

별도 Outbox Relay주기 적 으로 :

  1. SELECT * FROM outbox WHERE published = false
  2. Kafka 등 으로 *발행
  3. published = true 표시

:

  • dual-write 문제 해결 — DB 트랜잭션 commit 했는데 Kafka publish 실패하면 불일치.
  • at-least-once delivery 보장.
  • consumer 가 idempotent 면 *완전한 메시징.

→ 내 Outbox 패턴 글 참조. settlement 의 *핵심 자산.

5.5 패턴 4 — *CDC (Change Data Capture)**

Outbox 의 변종DB 의 WAL / binlog 자체이벤트 스트림 으로.

[App] → [PostgreSQL]
              ↓ logical replication
        [Debezium]
              ↓
            [Kafka]
              ↓
        [downstream consumers]

Debezium 같은 CDC 도구DB 의 *모든 변경 (insert/update/delete) 을 *event 로 변환.

장점:

  • 애플리케이션 코드 변경 0 (outbox 테이블 없어도 됨)
  • 기존 DB 그대로
  • 모든 변경 캡처 보장

단점:

  • schema evolution 어려움 (Avro / Schema Registry 같은 인프라 필요)
  • DB 의 *replication slot 자원 점유
  • 복잡한 transformation 은 외부 stream processor (Kafka Streams, Flink) 필요

MySQL → Elasticsearch 동기화, legacy DB → Data Lake 같은 integration 의 표준.


6. 합의 알고리즘 — *Raft, Paxos**

6.1 왜 *합의 필요

N 개 노드 가 *값 의 동일 sequence합의 하려면 합의 알고리즘 필수.

용도:

  • etcd (Kubernetes 의 brain) — Raft
  • ZooKeeper — ZAB (Paxos 변형)
  • Consul — Raft
  • Kafka KRaft mode — Raft

6.2 Raft (2014) — *이해 가능 한 합의**

3 단계:

  1. Leader Election — 시작 시 또는 leader 죽으면 follower 들 이 *투표 로 선출.
  2. Log Replication — leader 가 write 받으면 *follower 들에 *복제majority 가 *받으면 *commit.
  3. Safety — 일관성 보장 (Election Restriction, Leader Append-Only, Log Matching).
Leader (lemuel)
   write 받음 → log 에 append → followers (ilwon, solomon) 에 replicate
                                ↓ majority 응답 (2/3)
                            commit → client 에 OK

N 개 노드 중 *(N/2) + 1살아 있어야 *quorum. 3 노드 면 *2 노드 살아도 OK. 5 노드 면 *3 노드 살아도 OK.

6.3 Paxos — *원조**

Leslie Lamport 1989논문. 이해 어렵기로 *악명.

3 역할:

  • Proposer — 값 제안
  • Acceptor — 제안 수락
  • Learner — 합의 결과 학습

2 단계:

  • Prepare phase — proposer 가 번호 N 으로 prepare. acceptor 들 이 N 보다 큰 번호 없으면 수락.
  • Accept phase — proposer 가 N 과 값 v 보냄. majority 수락 시 *합의.

현장 적용Multi-Paxos 또는 Raft (단순 화). Spanner 의 *TrueTime + Paxos, Google Chubby 등.

6.4 Byzantine Fault Tolerance — *악의 적 노드**

Raft / Paxos 의 전제 : 노드 는 *crash 가능 하지만 *거짓말 안 함.

Byzantine : 악의 적 / bug 로 *거짓말 하는 노드. blockchain (Bitcoin, Ethereum)해결 함 — PoW, PoS.

기업 내부 시스템 에선 Byzantine 안 가정 (Raft 충분). 오픈 블록체인 에선 필수.


7. 시간 의 문제 — *Lamport / Vector Clock**

7.1 Physical Clock 의 *문제**

NTP 도 *수 ms 오차. 다른 노드 의 *timestamp 비교 불가.

GPS / TrueTime (Google Spanner) — 수 ms 의 *bounded error. 전세계 분산 db 가 *linearizable 가능.

7.2 Lamport Clock — *논리 시계**

event 발생 시 counter++
다른 노드 의 message 받을 때: counter = max(local, received) + 1

모든 event 에 *고유 순서 부여. 동시 발생 도 *정렬. causal order 보장.

7.3 Vector Clock — *각 노드 의 counter

A 의 vector: [Va=3, Vb=2, Vc=1]
B 의 vector: [Va=2, Vb=4, Vc=1]

A 의 event 1 < B 의 event 1?vector 비교 로 *판단. 부분 순서 (partial order). 동시 발생 (concurrent) 감지 가능.

Cassandra, DynamoDBconflict resolution 기반.


8. Distributed Patterns — *실전**

8.1 Idempotency

at-least-once delivery + idempotent consumer = exactly-once 효과.

// 안티
@KafkaListener(topics = "orders")
void handle(OrderCreated event) {
    repo.save(event.order());  // 같은 event 중복 시 *중복 저장*
}

// 좋음
@KafkaListener(topics = "orders")
void handle(OrderCreated event) {
    if (processedRepo.existsByEventId(event.id)) return;  // *중복 차단*
    transactionTemplate.execute(s -> {
        repo.save(event.order());
        processedRepo.markProcessed(event.id);
        return null;
    });
}

settlement 의 *Triple Idempotencyoutbox event_id UNIQUE → processed_events PK → DB UNIQUE 제약.

8.2 Circuit Breaker

상대 가 죽었으면 *시도 중단 + 주기 적 retry.

Resilience4j 의 3 상태 전이:

  • CLOSED — 정상. 요청 통과.
  • OPEN — 실패율 임계치 초과. 모든 요청 즉시 reject.
  • HALF_OPEN — 시간 지난 후 몇 개 요청 *시도. 성공 시 CLOSED, 실패 시 OPEN.

→ 내 I/O 병목 글 참조.

8.3 Bulkhead — *자원 격리**

Titanic 의 *방수 칸막이유래.

resilience4j.bulkhead:
  instances:
    paymentClient:
      maxConcurrentCalls: 10   # 다른 client 가 *thread pool 100 다 써도 *payment 는 *10 까지 보장*

8.4 Backpressure

느린 consumer 가 *fast producer 를 *멈추게 함. Reactive Streams핵심.

Flux.create(sink -> {
    sink.onRequest(n -> {
        for (int i = 0; i < n; i++) {
            sink.next(produce());  // *consumer 요청 만큼만*
        }
    });
}, FluxSink.OverflowStrategy.BUFFER);

8.5 Quorum Read/Write

N = 3 (3 replicas)
W = 2 (write 시 *2 노드 에 *commit 확인*)
R = 2 (read 시 *2 노드 에 *동시 read 후 *최신 반환*)

→ W + R > N (2+2 > 3) 면 *strong consistency 보장*

→ Cassandra, DynamoDB 의 tunable consistency 의 *기반.


9. 실전 의사결정 — *5 가지 질문**

새 분산 시스템 설계 시 반드시 답해야 할 질문 :

9.1 Q1 — *Partition 시 *어떻게 행동?

  • CP — 응답 거부 (etcd, MongoDB, ZooKeeper)
  • AP — 옛 데이터 응답 (Cassandra, DynamoDB)

9.2 Q2 — *Eventual consistency 수용 가능?

  • 읽기 가 *수 ms ~ 수 분 lag 가능 한가?
  • user-facing 데이터 면 *read-your-writes 필수

9.3 Q3 — *Idempotency 보장?

  • consumer 가 *중복 메시지 받아도 안전?
  • event_id 기반 dedup 필수 (Triple Idempotency)

9.4 Q4 — *분산 트랜잭션 패턴?

  • 2PC — legacy, 거의 안 씀
  • Saga — long-running, 보상 가능
  • Outbox — single DB + Kafka, settlement 의 표준
  • CDC — DB binlog 자체 가 source

9.5 Q5 — *HA 와 quorum?

  • 최소 3 노드 (1 fail 가능)
  • 5 노드 권장 (2 fail 가능)
  • etcd 처럼 *write-heavy3 또는 5 이하 (합의 비용)

10. 결론 — *trade-off 의 *명시화**

분산 시스템 의 모든 결정 의 *밑trade-off 가 있다. strong consistency vs latency, availability vs durability, exactly-once vs simplicity, flexibility vs throughput.

오늘 정리한 7 본질 :

  1. CAPpartition 시 *C vs A
  2. BASEACID 의 *throughput 교환
  3. 일관성 spectrum — Linearizable → Eventual 의 7 단계
  4. 2PC vs Saga vs Outbox vs CDC분산 트랜잭션 의 *4 패턴
  5. Raft / Paxos합의 의 *현대 표준
  6. Lamport / Vector Clock시간 의 *논리적 모델
  7. 실전 패턴 — Idempotency / Circuit Breaker / Bulkhead / Backpressure / Quorum

MSA 의 *모든 결정근거 있게 *설명 가능 해지려면 — 이 7 가지 의 *각 trade-off 의 *명시 적 선택 의 *어휘필요.

settlement / sparta MSA 의 *Outbox + Triple Idempotency + Saga조합그 어휘 위에서 *근거 있게 *서 있다. 그 근거 없이 *MSA 라 다 분산 으로 부른 시스템eventually consistent 의 *의미 도 모른 채 *production 의 *eventual 오류겪는다.

분산 의 *본질“같이 가는 게 *불가능두 좋은 것 의 *선택 의 명시화”. 그 명시화 가 *시니어 의 *시스템 설계 의 *진짜 일.


참고

  • Designing Data-Intensive Applications (Martin Kleppmann) — 분산 의 *최고 의 reference.
  • Distributed Systems for Practitioners (Dimos Raptis).
  • In Search of an Understandable Consensus Algorithm (Raft) (Diego Ongaro, John Ousterhout, 2014).
  • Paxos Made Simple (Lamport, 2001).
  • Time, Clocks, and the Ordering of Events in a Distributed System (Lamport, 1978).
  • CAP Twelve Years Later (Brewer, 2012).
  • 자매편: