Basically Available, Soft state, Eventually consistent. ACID의 대척점에 놓고 이름 붙인 모델이다.
세 조각
- Basically Available — 일부 노드가 죽어도 시스템은 응답한다 (낡은 값일지라도)
- Soft state — 외부 입력이 없어도 상태가 변할 수 있다 (복제가 뒤늦게 전파된다)
- Eventually consistent 새 쓰기가 멈추면, 언젠가는 모든 노드가 같은 값에 수렴한다
ACID와의 거래
-
ACID — 쓰기가 끝나면 즉시 모두가 같은 값을 본다
- 그러려면 노드 간 확인을 기다려야 한다 → 지연 · 가용성 손해
-
BASE — 기다리지 않고 응답한다
- 잠시 노드마다 다른 값을 볼 수 있다 → 애플리케이션이 감당해야 한다
"언젠가"가 얼마나인가
최종 일관성의 문제는 '언젠가' 가 정의되지 않았다는 것이다
실무에서는 수렴 시간을 측정하고 SLA 로 잡는다
- 예: "99% 의 쓰기가 500ms 안에 모든 리전에 전파된다"
애플리케이션이 감당해야 하는 것
-
① 읽은 값이 낡았을 수 있다
- 금액·재고처럼 정확해야 하는 값은 리더에서 읽거나 정족수를 높인다
-
② 같은 키에 동시 쓰기가 충돌한다
- last-write-wins (간단하지만 데이터가 사라진다)
- 벡터 클록·CRDT (병합 규칙을 정의한다)
- 애플리케이션이 충돌을 사용자에게 보여준다
강한 일관성으로 되돌리는 손잡이
-
BASE 계열 DB 도 대개 일관성 수준을 조절할 수 있다
-
Cassandra — ONE / QUORUM / ALL 로 읽기·쓰기 강도를 정한다
- W + R > N 이면 최신 값을 읽는다
-
DynamoDB — ConsistentRead=true 로 강한 일관 읽기 (요금 2배)
BASE는 제품의 속성이 아니라 설정의 결과다.
어디에 맞나
- 맞는 곳 — 타임라인 · 조회수 · 추천 · 로그 · 세션
- (잠깐 낡아도 사용자가 피해를 안 본다)
안 맞는 곳 잔액 · 재고 · 좌석 예약 · 결제
- (낡은 값으로 판단하면 돈이 샌다)
실제 시스템은 둘을 한 서비스 안에서 섞는다 — 결제는 RDB로 ACID, 피드는 NoSQL로 BASE.
면접 함정
- ❌ "NoSQL은 트랜잭션이 없다" → MongoDB 4.0+ 등 다수가 다중 문서 트랜잭션을 지원한다.
- ❌ "최종 일관성은 데이터가 틀린 것" → 수렴이 보장된다. 문제는 언제이고, 그 사이를 설계로 감당하는 것이다.
일관성 수준을 실제로 조절해 보기
-- Cassandra (CQL)
CONSISTENCY QUORUM; -- 과반이 응답해야 성공
SELECT * FROM users WHERE id = 1;
CONSISTENCY ONE; -- 한 노드만 응답하면 성공 (빠르지만 낡을 수 있다)
-
N=3 복제 기준
-
W=1, R=1 — 가장 빠르다. 낡은 값을 볼 수 있다
-
W=2, R=2 — W+R>N → 최신 보장. 한 대가 죽어도 동작
-
W=3, R=1 — 읽기가 매우 빠르다. 쓰기는 한 대만 죽어도 실패
읽기가 압도적으로 많으면 W를 키우고 R을 줄이는 식으로 워크로드에 맞춘다.
충돌을 어떻게 합칠 것인가
-
last-write-wins — 타임스탬프가 늦은 쪽이 이긴다
- 간단하지만 진 쪽의 쓰기가 조용히 사라진다
- 서버 시계가 어긋나면 엉뚱한 값이 남는다
-
CRDT — 병합 규칙이 수학적으로 정의된 자료구조
- (카운터 · 집합 · 순서 없는 맵) → 충돌 없이 수렴한다
-
애플리케이션 해결 — 두 버전을 모두 보관하고 사용자에게 고르게 한다