분산 시스템은 일관성(C)·가용성(A)·분할 내성(P) 셋 중 둘만 동시에 만족할 수 있다는 정리.
흔한 오해부터 정리한다
❌ "셋 중 둘을 고른다" ✅ "P 는 고르는 게 아니라 주어진다. 분할이 일어났을 때 C 와 A 중 하나를 고른다"
네트워크는 반드시 끊긴다. 여러 노드를 쓰는 순간 P는 선택지가 아니라 전제다. 그러니 실제 선택은 이것뿐이다.
- 분할이 일어났다. 다른 노드와 통신이 안 된다.
| CP 선택 | "틀린 답을 주느니 응답하지 않겠다" | → 에러를 반환하거나 기다린다 |
|---|---|---|
| AP 선택 | "낡은 답이라도 주겠다" | → 오래된 데이터를 반환한다 |
세 글자의 정확한 뜻
| 뜻 | |
|---|---|
| Consistency | 모든 노드가 같은 시점에 같은 값을 반환한다(선형화 가능성) |
| Availability | 살아 있는 모든 노드가 에러 없이 응답한다 |
| Partition tolerance | 노드 간 통신이 끊겨도 시스템이 계속 동작한다 |
ACID의 C와 CAP의 C는 다른 말이다 — 전자는 제약 유지, 후자는 노드 간 값 일치다.
PACELC — CAP이 말하지 않은 절반
- if (P) 분할일 때 — → A 냐 C 냐
- else — 정상일 때 → L(지연) 이냐 C(일관성) 이냐
정상일 때도 트레이드오프는 있다. 강한 일관성을 원하면 노드 간 확인을 기다려야 하므로 지연이 는다. CAP은 장애 상황만 다루지만 실무 시간의 99%는 정상 상황이라, PACELC의 뒷부분이 오히려 더 자주 쓰인다.
정족수 — 겹치게 해서 최신을 본다
N = 복제본 수, W = 쓰기 성공에 필요한 노드 수, R = 읽기에 필요한 노드 수
W + R > N 이면 읽기 집합과 쓰기 집합이 반드시 겹친다 → 최신 값을 본다
예) N=3, W=2, R=2 → 2+2 > 3 ✅ (한 대가 죽어도 동작)
N=3, W=1, R=1 → 1+1 < 3 ❌ (빠르지만 낡은 값을 볼 수 있다)
W를 키우면 쓰기가 느려지고 읽기는 빨라진다. 반대도 같다 — 워크로드에 맞춰 조절하는 손잡이다.
실제 DB는 어디에 있나
- PostgreSQL · MySQL (단일 리더) — 기본적으로 CP 성향
- 리더가 죽으면 승격 전까지 쓰기 불가
- Cassandra · DynamoDB — AP 성향. W/R 을 조절해 이동할 수 있다
면접 함정
- ❌ "우리는 CA 시스템" → 분산 시스템에 CA는 없다. 단일 노드일 때만 가능한 말이다.
- ❌ "NoSQL은 AP, RDB는 CP" → 제품이 아니라 설정으로 정해진다. Cassandra도 정족수를 높이면 C 쪽으로 간다.
실제 시스템에서 어떻게 나타나나
[CP 예 — PostgreSQL 단일 리더 + 동기 복제] 리더와 팔로워 사이 네트워크가 끊긴다
- 동기 복제라 커밋이 팔로워 확인을 기다린다
- 쓰기가 멈춘다 (가용성 포기)
- 대신 어느 노드도 낡은 값을 확정하지 않는다
[AP 예 — Cassandra CONSISTENCY ONE] 노드 간 통신이 끊긴다
- 각 노드가 자기가 가진 값으로 응답한다
- 서비스는 계속된다 (가용성 유지)
- 대신 노드마다 다른 값을 줄 수 있다
설계 질문으로 바꿔서 물어본다
- "네트워크가 끊긴 30초 동안, 이 기능은 어느 쪽이 나은가?"
| 좌석 예약 | 낡은 값으로 중복 판매하느니 에러가 낫다 | → CP |
|---|---|---|
| 좋아요 수 | 30초 낡은 숫자를 보여줘도 아무도 안 다친다 | → AP |
| 장바구니 | 낡아도 되지만 사라지면 안 된다 | → AP + 병합 규칙 |
기능 단위로 다르게 고르는 것이 실제 설계다. 시스템 전체를 CP나 AP로 도장 찍는 게 아니다.