제목, 태그, 카테고리로 검색

모든 글
약 25분 분량 이론/데이터베이스

트랜잭션 ACID ③: Consistency는 사실 두 가지다

목차

0. 들어가며

ACID에서 가장 모호한 글자가 C입니다. 면접에서도 가장 자주 헷갈리는 글자고요. 이 글의 핵심 메시지는 — “ACID의 C와 CAP의 C는 같은 단어를 쓸 뿐 완전히 다른 개념이다.” Martin Kleppmann은 Designing Data-Intensive Applications 에서 더 강한 주장을 합니다 — “Consistency는 사실 ACID에 들어갈 자격이 없다” 고요.

1. 왜 C가 가장 모호한가

① 편(Atomicity)은 명확했어요. “전부 성공 or 전부 실패.” ② 편(Isolation)도 (조금 복잡하지만) 명확했어요. “동시 트랜잭션 사이의 가시성 제어.” 곧 다룰 D(Durability)도 분명합니다. “커밋된 변경은 영속적이다.”

그런데 C는 다릅니다. 강의에서, 책에서, 면접에서 이 단어가 등장할 때마다 사람들은 서로 다른 의미로 써요:

  • “DB에 쓴 데이터가 일관성을 유지한다” — 데이터 무결성?
  • “분산 노드들이 같은 값을 본다” — 복제본 동기화?
  • “Eventually consistent하다” — 최종 일관성?
  • “ACID 보장한다” — 트랜잭션 무결성?

이 네 가지가 모두 “consistency” 라는 한 단어로 표현됩니다. 진짜 문제는 이들이 서로 다른 개념인데 같은 단어를 공유한다는 점이에요 — 첫 번째와 네 번째는 ACID의 C에 가깝고, 두 번째는 CAP의 C, 세 번째는 또 다른 차원의 보장이에요.

Consistency가 가리키는 4가지

이번 글은 이 혼동을 풀어봅니다.

2. ACID의 C — 사실 애플리케이션의 책임이다

정의

ACID의 C(Consistency): 트랜잭션이 데이터베이스를 한 유효한 상태에서 다른 유효한 상태로 옮기는 것을 보장한다.

여기서 “유효한 상태” 란 무엇인가? 애플리케이션이 정의한 무결성 제약(invariants) 을 만족하는 상태입니다:

  • 외래 키 제약 (foreign key): 참조하는 행이 실제로 존재해야 함
  • 유니크 제약 (unique): 중복된 값이 없어야 함
  • 체크 제약 (check): 값이 특정 범위 안에 있어야 함
  • NOT NULL 제약: 빈 값이 들어가면 안 됨
  • 그 외 비즈니스 규칙: “잔액은 음수가 될 수 없다”, “좋아요 수는 좋아요 테이블의 행 수와 같아야 한다”

트랜잭션이 시작될 때 이 제약들이 만족되어 있고, 트랜잭션이 끝났을 때도 만족되어야 한다는 것이 C의 의미예요.

Instagram 예시

Instagram 예시 — invariant이 두 테이블에 걸쳐 있다

여기서 invariant: photos.likes_count = COUNT(*) FROM likes WHERE photo_id = ?

두 테이블이 따로 있지만 “좋아요 수의 합” 이라는 한 가지 진실을 두 곳에서 표현하고 있어요. 이 둘이 어긋나면(예: photos에 likes_count가 5인데 likes 테이블엔 2개뿐, 또는 likes 테이블에 photo_id=4가 있는데 photos엔 4가 없음) → 데이터 불일치, 즉 C 위반입니다.

Kleppmann의 주목할 만한 입장

여기서 면접에서 차이를 만드는 디테일이 있어요. Designing Data-Intensive Applications (Chapter 7)에서 Martin Kleppmann이 직접 한 말:

“Consistency refers to the application-specific notion of the database being in a ‘good state.’ It is not something that the database can guarantee; it is a property of the application, that may rely on the database’s atomicity and isolation to achieve it. Thus, the letter C doesn’t really belong in ACID.”

번역하면: “Consistency는 DB가 보장할 수 있는 게 아니라 애플리케이션의 속성이다. 그래서 C는 사실 ACID에 들어갈 자격이 없다.”

왜 그런가? 생각해보면:

  • DB가 보장할 수 있는 것: 외래 키(FK), 유니크(UNIQUE), 체크(CHECK), NOT NULL, 그리고 PostgreSQL의 EXCLUSION 제약 같은 DB가 알 수 있는 무결성. 트랜잭션이 이걸 위반하면 DB가 자동으로 ROLLBACK하므로, DB는 결코 “별 역할 없는” 게 아닙니다. 잘 설계된 스키마라면 상당 부분의 invariant을 DB 레벨에서 강제할 수 있어요.
  • DB가 보장할 수 없는 것: DB가 알 수 없는 비즈니스 규칙. “이체할 때 출금 = 입금” 같은 규칙은 DB가 모릅니다(여러 행 사이의 관계라 일반적인 제약으로 표현 불가). 애플리케이션이 트랜잭션을 올바르게 작성해야 보장돼요.

① 편에서 다룬 계좌 이체 예시를 다시 보면:

BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
COMMIT;

이 트랜잭션이 “출금 = 입금” 이라는 invariant을 유지하는 건 개발자가 이렇게 작성했기 때문이에요. 만약 두 번째 UPDATE를 빼먹어도 DB는 아무 불평 없이 커밋합니다 — DB는 이게 invariant 위반인지 모르니까.

즉 C는 개념적으로는 A·I와 별개의 속성이지만, 실제로는 A(원자성)와 I(격리) 위에서 구현됩니다. A와 I가 잘 작동해야 애플리케이션이 invariant을 유지할 수 있는 기반이 마련돼요. 그 위에서 invariant을 정의하고 지키는 것은 애플리케이션의 몫입니다.

2장 요약 — ACID의 C는 애플리케이션이 정의한 무결성 제약이 트랜잭션 전후로 유지된다는 의미입니다. DB가 직접 보장하는 건 일부(FK, UNIQUE 등)뿐이고, 비즈니스 규칙은 애플리케이션 책임이에요. Kleppmann은 “C는 사실 ACID에 들어갈 자격이 없다” 고 주장합니다.

3. CAP의 C — 완전히 다른 개념

여기서부터 헷갈림의 진원지예요. CAP 정리에 나오는 C는 ACID의 C와 완전히 다른 개념입니다.

정의

CAP의 C(Consistency) — 일반적으로 Linearizability 로 해석돼요. 분산 시스템이 마치 단일 복사본만 있는 것처럼 동작한다는 보장이며, 모든 연산이 invocation과 response 사이의 어느 시점에 원자적으로 일어난 것처럼 보이고, 실시간 순서(real-time ordering) 를 따릅니다 — A 연산이 끝난 후 B 연산이 시작되면 B는 반드시 A의 결과를 봅니다. 이 real-time 순서 보장이 sequential consistency나 causal consistency 같은 더 약한 모델과 구분되는 핵심이에요.

Kleppmann의 Designing Data-Intensive Applications (Chapter 9)에서 더 정확한 정의:

“Make a system appear as if there were only one copy of the data, and all operations on it are atomic. Once a new value has been written or read, all subsequent reads see the value that was written, until it is overwritten again.”

이게 핵심이에요 — 단일 복사본 추상화 + 쓰기 후 모든 읽기는 그 값(또는 이후 값)을 본다.

Martin Kleppmann의 직접 인용 (블로그 “Please stop calling databases CP or AP”, 2015):

“Consistency in CAP actually means linearizability, which is a very specific (and very strong) notion of consistency. In particular it has got nothing to do with the C in ACID, even though that C also stands for ‘consistency’.”

번역: “CAP의 C는 linearizability를 의미하고, ACID의 C와는 아무 관계가 없다.”

직관적 예시

Bob과 Alice가 같이 호텔을 예약합니다. John이 마지막 방을 예약했고, 그 응답을 받은 시점 이후에 Bob이 페이지를 새로고침한다고 가정해요.

  • Linearizable system: Bob의 새로고침은 반드시 John의 예약 결과를 봅니다 — “예약 불가능” 표시.
  • Non-linearizable system: Bob의 요청이 아직 동기화 안 된 복제본으로 가서 “예약 가능” 표시. 잠시 후 진실이 드러남.

Linearizability의 핵심은 실시간 순서 보장입니다 — 한 연산 A가 완료된 후에 시작된 연산 B는 반드시 A의 결과를 본다는 것. 마치 데이터베이스가 한 카피만 있는 것처럼 동작한다는 보장이에요.

”일관된 읽기”가 바로 이거다

흔히 말하는 두 번째 종류의 일관성 — primary에 쓰고 replica에서 읽으면 옛날 값이 나올 수 있다는 — 그게 정확히 CAP의 C(linearizability) 위반 입니다. ACID의 C와는 별개 문제예요.

ACID-C와 CAP-C 비교

ACID-C vs CAP-C

측면ACID의 CCAP의 C (Linearizability)
의미트랜잭션이 무결성 제약을 깨지 않음단일 복사본처럼 보이고, 쓰기가 끝난 후의 모든 읽기는 그 값(또는 그 이후 값)을 본다
범위단일 DB의 트랜잭션 단위분산 시스템 전체
누가 보장?애플리케이션 (DB는 일부 도움)합의 알고리즘(Paxos/Raft 등) + 복제
예시”좋아요 수가 likes 테이블 행 수와 같다""쓰고 즉시 읽으면 그 값이 나온다”
반대 개념데이터 손상 (corruption)Stale read (linearizability를 보장하지 않는 약한 모델들)

3장 요약 — CAP의 C는 Linearizability(시스템이 단일 복사본처럼 보이고 실시간 순서를 따름)를 가리키는 분산 시스템 개념이고, ACID의 C(트랜잭션 무결성)와는 완전히 다른 개념입니다.

4. Eventual Consistency — 또 다른 C

정의

Eventual Consistency: “충분한 시간이 지나면 모든 복제본이 동일한 값으로 수렴(converge)한다” 는 보장. 핵심은 replica convergence 이며, stale read는 그 결과 중 하나일 뿐이에요.

단, 수렴 시점에 대한 시간적 보장은 없습니다. 1초 후일 수도, 1분 후일 수도, 노드 장애가 회복될 때까지일 수도 있어요. 이게 strong consistency와의 결정적 차이예요 — strong consistency는 “쓰자마자 보인다” 를 보장하지만, eventual consistency는 “언젠가 보인다” 만 보장합니다.

이건 CAP의 C(linearizability)를 약화시킨 보장이에요. ACID의 C와는 또 다른 차원의 이야기예요.

핵심 통찰 — “Eventual Consistency는 손상된 데이터를 회복시키지 못한다”

흔한 오해를 정확히 짚으면:

  • 흔한 오해: “지금 데이터가 좀 이상해도 결국엔 일관성을 가질 거야”
  • 정확한 사실: Eventual consistency는 복제본 간 수렴에만 적용돼요.

Instagram 예시로 돌아가서 — photos.likes_count = 5인데 likes 테이블엔 행이 2개뿐이라면, 이건 eventual하게 5와 2가 일치하게 되지 않아요. 이미 데이터가 손상된 것이고, eventual consistency 자체는 이걸 자동으로 회복시켜주지 않습니다. 회복하려면 별도의 보정 메커니즘이 필요해요 — 배치 reconciliation 작업, CRDT 같은 충돌 해소 자료구조, 재처리 파이프라인, 또는 트랜잭션 재실행 같은 것들. 이런 메커니즘을 따로 설계하지 않으면 손상 상태로 남습니다.

즉:

  • ACID의 C 위반 (데이터 손상): eventual하게 회복 안 됨. 별도 수정 필요.
  • CAP의 C 위반 (stale read): 보통 복제 동기화로 회복되지만, 비동기 복제에서 primary 장애 시 미복제 데이터는 영구 손실 가능.

이 둘을 구분하는 게 결정적이에요.

흔한 오해 정정 — “eventual consistency는 NoSQL 얘기다”: 아닙니다. 단일 노드 PostgreSQL에 read replica를 한 대 붙이는 순간, 또는 앞단에 Redis / Memcached 캐시를 두는 순간부터 시스템은 이미 eventual consistency 모델로 들어가요 — primary에 쓰고 직후 replica에서 읽으면 옛 값이 나오고, DB를 갱신해도 캐시는 한 박자 늦게 무효화됩니다.

“우리 DB가 ACID를 지키니까 시스템 전체도 strong consistency” 라는 가정은 단일 노드에서만 성립해요. 복제본 · 캐시 · CDN — 데이터가 두 군데에 존재하는 순간 eventual consistency의 영역 이고, 그 trade-off를 “NoSQL 쓸 때만 신경 쓴다” 고 미루면 운영에서 직접 부딪힙니다.

Eventual Consistency를 받아들이는 이유

DynamoDB, Cassandra, Riak 같은 시스템들이 의도적으로 eventual consistency를 선택하는 이유:

  • Linearizability는 비싸다. 합의 알고리즘으로 quorum의 합의를 받아야 하고, 네트워크 지연·노드 장애 시 가용성이 저하돼요.
  • 수많은 워크로드는 stale-read를 견딜 수 있다. SNS 좋아요 수가 1초 늦게 갱신돼도 비즈니스 영향 거의 없음.
  • CAP 정리 (정확한 의미): 네트워크 분할(P)이 발생한 상황에서만 일관성(C)과 가용성(A) 중 하나를 포기해야 한다는 정리예요. 평소(분할 없을 때)에는 셋 다 가능. Brewer 본인이 2012년에 “two out of three” 단순화는 오해를 부른다고 명확히 했고, 평소 상황의 트레이드오프(consistency vs latency)는 PACELC 정리 가 다룹니다.

“최종 일관성은 마케팅 용어” 라는 표현은 약간 과한 비판이에요. 제대로 설계된 분산 시스템에서는 합리적인 트레이드오프입니다. 다만 그것이 데이터 무결성을 보장한다는 의미는 아니라는 점을 명확히 해야 해요.

4장 요약 — Eventual Consistency는 CAP의 C를 약화시킨 보장이고, 복제본 간 수렴에 대한 약속이지 데이터 무결성 회복 약속이 아닙니다. 분산 시스템에서 가용성·성능을 위한 합리적 선택일 수 있지만, ACID의 C를 대체하지는 못해요.

5. 동기 복제 vs 비동기 복제

CAP의 C를 어떻게 강하게 보장할지가 복제 전략의 핵심이에요. 두 극단부터 보면:

동기 복제 (Synchronous Replication)

  • 쓰기 시 정해진 수의 복제본(보통 quorum, 또는 모든 동기 standby)에 기록되어야 커밋 완료.
  • Linearizability에 가까움 (특히 합의 알고리즘과 결합 시).
  • 단점: 느림. quorum이 못 모이거나 동기 standby가 응답하지 못하면 쓰기가 막힘.

비동기 복제 (Asynchronous Replication)

  • 쓰기는 primary에 반영되고 즉시 커밋. 복제는 백그라운드.
  • 일반적으로 eventual consistency 모델.
  • 장점: 빠름, 가용성 높음. 단점: stale read 가능 + primary 장애 시 복제 안 된 데이터 손실 가능.

실제 DB의 풍부한 스펙트럼

PostgreSQL의 synchronous_commit 설정을 보면 두 극단 사이의 단계가 보여요:

의미
offWAL이 디스크에 fsync되기 전에 커밋 응답 (가장 빠름, 데이터 손실 위험)
local로컬 WAL만 fsync 확인 (복제 무관)
remote_write복제본의 메모리까지만 도착 확인
on (기본)로컬 WAL fsync 확인 (복제본 관련 의미는 synchronous_standby_names 설정이 있을 때만)
remote_apply복제본이 실제 적용까지 완료 확인 (가장 강한 보장, 가장 느림)

주의: synchronous_commit = on이 복제본까지의 보장을 가지려면 별도로 synchronous_standby_names로 동기 standby를 지정해야 해요. 둘이 조합되어야 의미가 완성됩니다 — 단독으로 on만 보고 “복제본까지 보장” 이라고 단정하면 부정확해요.

이런 다이얼은 D편(Durability)에서 더 자세히 다룰 거예요. 핵심은 linearizability 자체는 만족/불만족의 boolean 성질이지만, 어떤 일관성 모델을 선택하느냐는 풍부한 모델 공간이라는 점이에요.

일관성 모델 공간

일관성 모델 — 두 차원과 그 교집합

일관성 모델들은 단순한 일직선이 아니라 두 차원으로 나뉘어요 (Bailis, Jepsen.io 분류):

  • 단일 객체(single-object) 차원: linearizability → sequential consistency → causal consistency → eventual consistency. 강한 → 약한 순서.
  • 다중 객체/트랜잭션 차원: serializability — 트랜잭션이 어떤 직렬 순서와 동등하다는 보장. linearizability와는 직접 비교 불가능한 다른 축.
  • 두 차원을 합친 것: strict serializability — 트랜잭션 직렬화 + 실시간 순서. Google Spanner가 대표적.

즉 linearizability는 단일 객체 일관성의 최강이고, serializability는 트랜잭션 일관성의 표준이며, 둘이 만나는 지점이 strict serializability예요. 시스템은 워크로드에 따라 이 모델 공간 어딘가를 선택합니다.

5장 요약 — 일관성 모델은 단일 객체 차원(linearizability ↔ eventual)과 트랜잭션 차원(serializability)으로 나뉘고, 둘을 합친 strict serializability가 가장 강합니다. 시스템은 동기/비동기 복제 + fsync 타이밍 + 적용 시점 등의 다이얼로 어느 모델을 선택할지 조정해요.

6. 정리 — C라는 단어가 가리키는 4가지

면접/실무에서 “consistency” 라는 단어가 나오면 어떤 의미인지 먼저 명확히 해야 해요:

#명칭의미누가 보장?
1ACID의 C트랜잭션이 무결성 제약을 유지애플리케이션 (DB는 FK/UNIQUE 등 일부 도움)
2CAP의 C (Linearizability)시스템이 단일 복사본처럼 보임 + 실시간 순서 보장합의 알고리즘 + 복제 메커니즘
3Eventual Consistency시간이 지나면 노드들이 같은 값으로 수렴비동기 복제 시스템
4Transaction-level Read Consistency같은 트랜잭션 안에서 같은 값을 봄② 편의 격리 수준 (RR, SERIALIZABLE)

이 네 개는 같은 단어를 쓸 뿐 완전히 다른 개념이에요. 면접/실무에서 어느 의미로 쓰이는지 명확히 하지 않으면 대화가 어긋납니다.

핵심 통찰들

  • C는 개념적으로는 독립적이지만, 실제로는 A와 I 위에서 구현된다: Atomicity가 깨지면 무결성 제약도 쉽게 깨지고(반쪽 트랜잭션), Isolation이 약하면 일관성 없는 읽기로 invariant 검증이 잘못될 수 있어요. 개념적으로는 C(invariant 유지)가 A·I와 별개의 속성이지만, 애플리케이션이 invariant을 유지하려면 A와 I가 정상 작동해야 합니다. 이게 Kleppmann이 “C는 ACID에 들어갈 자격이 없다” 고 한 배경이에요.
  • ACID의 C는 데이터 무결성, CAP의 C는 분산 노드 동기화: 이름만 같지 푸는 문제가 다릅니다.
  • Eventual Consistency는 복제본 간 수렴(convergence)을 보장합니다: 그러나 invariant이 깨진 데이터(데이터 손상)는 자동 회복되지 않으며, 별도의 보정 메커니즘(reconciliation 배치, CRDT, 재처리 등)이 필요해요.
  • 복제 전략은 트레이드오프: 강한 일관성 ↔ 가용성 ↔ 성능. 절대값이 아니라 다이얼로 조절.

참고 (1차 자료 우선)

0. Introduction

The most ambiguous letter in ACID is C — and the one most often confused in interviews. The core message of this post is: “ACID’s C and CAP’s C share a word but mean completely different things.” Martin Kleppmann goes further in Designing Data-Intensive Applications“Consistency does not really belong in ACID.”

1. Why C Is the Most Ambiguous

Part ① (Atomicity) was clear: “all succeed or all fail.” Part ② (Isolation) — slightly complex but still clear: “visibility control between concurrent transactions.” The upcoming Part D (Durability) is also clear: “committed changes are persistent.”

But C is different. Every time the word appears in lectures, books, and interviews, people use it with different meanings:

  • “Data written to the DB stays consistent” — data integrity?
  • “Distributed nodes see the same value” — replica synchronization?
  • “Eventually consistent” — eventual consistency?
  • “ACID-compliant” — transaction integrity?

All four are expressed by the single word “consistency.” The real problem is that they are different concepts sharing a name — the first and the fourth are close to ACID’s C, the second is CAP’s C, and the third is yet another dimension of guarantee.

Four meanings of "consistency"

This post unpacks that confusion.

2. ACID’s C — Actually the Application’s Responsibility

Definition

ACID’s C (Consistency): a transaction takes the database from one valid state to another valid state.

What is a “valid state”? A state that satisfies the invariants defined by the application:

  • Foreign key: referenced rows must exist
  • Unique: no duplicates
  • Check: values must fall within a range
  • NOT NULL: empty values are disallowed
  • Other business rules: “balance cannot be negative”, “likes_count must equal the row count in the likes table”

The meaning of C is that these constraints are satisfied at the start of the transaction and remain satisfied at the end.

Instagram example

Instagram example — the invariant spans two tables

The invariant: photos.likes_count = COUNT(*) FROM likes WHERE photo_id = ?

The two tables are physically separate, but they each express the same truth — “how many likes does this photo have.” When they disagree (e.g., photos.likes_count = 5 but only 2 rows exist in likes; or a row in likes references photo_id = 4 that doesn’t exist in photos) → data inconsistency, i.e., C violation.

Kleppmann’s notable position

Here is the detail that makes a difference in interviews. Martin Kleppmann in Designing Data-Intensive Applications (Chapter 7):

“Consistency refers to the application-specific notion of the database being in a ‘good state.’ It is not something that the database can guarantee; it is a property of the application, that may rely on the database’s atomicity and isolation to achieve it. Thus, the letter C doesn’t really belong in ACID.”

Translated: “Consistency is not something the DB can guarantee — it is a property of the application. So the letter C does not really belong in ACID.”

Why? Consider:

  • What the DB can guarantee: integrity the DB can know about — FK, UNIQUE, CHECK, NOT NULL, and PostgreSQL’s EXCLUSION constraint. The DB auto-rolls-back transactions that violate these, so the DB is by no means “playing no role.” A well-designed schema can enforce a substantial portion of invariants at the DB level.
  • What the DB cannot guarantee: business rules the DB cannot know. “On a transfer, debit must equal credit” is invisible to the DB (it spans multiple rows, not expressible as a generic constraint). The application must write the transaction correctly.

Recall the transfer example from Part ①:

BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
COMMIT;

This transaction maintains the “debit = credit” invariant only because the developer wrote it that way. If you forget the second UPDATE, the DB still commits without complaint — it has no idea that’s an invariant violation.

So C is conceptually independent of A and I, but is built on top of A and I in practice. A and I must work for the application to even be able to maintain invariants. Defining and protecting invariants on top of that is the application’s job. This is the background for Kleppmann’s “C does not really belong in ACID.”

Section 2 takeaway — ACID’s C means the integrity constraints defined by the application hold across a transaction. The DB enforces some of them directly (FK, UNIQUE, etc.), but business rules are the application’s responsibility. Kleppmann argues “C does not really belong in ACID.”

3. CAP’s C — A Completely Different Concept

This is the source of the confusion. The C in the CAP theorem is a completely different concept from ACID’s C.

Definition

CAP’s C (Consistency) — typically interpreted as Linearizability. The system behaves as if there is only a single copy of the data, every operation appears to take effect atomically at some point between its invocation and response, and operations follow real-time ordering — once operation A completes and operation B starts, B must see A’s effects. This real-time-ordering guarantee is the key that distinguishes it from weaker models like sequential or causal consistency.

A more precise definition from Kleppmann’s DDIA (Chapter 9):

“Make a system appear as if there were only one copy of the data, and all operations on it are atomic. Once a new value has been written or read, all subsequent reads see the value that was written, until it is overwritten again.”

That is the core — single-copy abstraction + every read after a write sees that value (or one written later).

Kleppmann’s direct quote (blog “Please stop calling databases CP or AP”, 2015):

“Consistency in CAP actually means linearizability, which is a very specific (and very strong) notion of consistency. In particular it has got nothing to do with the C in ACID, even though that C also stands for ‘consistency’.”

Intuitive example

Bob and Alice are booking a hotel together. John books the last room, and Bob refreshes the page after John’s booking response is received.

  • Linearizable system: Bob’s refresh must see John’s booking — “unavailable” shown.
  • Non-linearizable system: Bob’s request goes to a not-yet-synced replica → “available” shown. Truth surfaces later.

The core of linearizability is the real-time-ordering guarantee — an operation B that started after operation A completed must see A’s effect. The system behaves as if it were a single copy of the database.

”Consistent reads” refers exactly to this

The other commonly-mentioned kind of consistency — “write to primary, read from replica, get an old value” — is exactly a CAP-C (linearizability) violation. It is unrelated to ACID’s C.

ACID-C vs CAP-C compared

ACID-C vs CAP-C

AspectACID’s CCAP’s C (Linearizability)
MeaningA transaction does not break integrity constraintsLooks like a single copy; every read after a write sees that value (or later)
ScopeSingle DB, transaction-scopedDistributed system as a whole
Who guarantees?Application (DB helps with some constraints)Consensus algorithm (Paxos / Raft) + replication
Example”likes_count equals the row count in the likes table""Write, then read immediately, and the write is visible”
OppositeData corruptionStale read (weak models that do not provide linearizability)

Section 3 takeaway — CAP’s C points to Linearizability (the system appears single-copy and follows real-time ordering), a distributed-systems concept. It is completely different from ACID’s C (transaction integrity).

4. Eventual Consistency — Yet Another C

Definition

Eventual Consistency: the guarantee that “after enough time, all replicas converge to the same value.” The core is replica convergence; stale reads are just one consequence.

Crucially, there is no time bound on convergence. It could be a second later, a minute later, or whenever a node failure recovers. This is the decisive difference from strong consistency — strong consistency guarantees “visible immediately after writing”, while eventual consistency only guarantees “visible eventually.”

This is a weakened version of CAP’s C (linearizability). It is yet another dimension separate from ACID’s C.

Key insight — “Eventual Consistency does not heal corrupted data”

A common misconception, stated precisely:

  • Common misconception: “Even if the data looks weird now, it will be consistent eventually.”
  • Accurate fact: Eventual consistency applies only to convergence between replicas.

Back to the Instagram example — if photos.likes_count = 5 but likes has only 2 rows, this does not become consistent (5 vs 2 will not reconcile) eventually. The data is already corrupted, and eventual consistency by itself does not heal it. To recover, you need a separate corrective mechanism — batch reconciliation, CRDTs (conflict-free data structures), reprocessing pipelines, transaction replay, etc. Without those, the corruption persists.

So:

  • ACID-C violation (data corruption): not healed eventually. Requires explicit repair.
  • CAP-C violation (stale read): usually heals via replica sync, but with async replication and a primary failure, unreplicated data can be lost permanently.

Distinguishing the two is decisive.

Common misconception fix — “eventual consistency is a NoSQL thing”: it is not. The moment you attach a single read replica to single-node PostgreSQL, or place a Redis / Memcached cache in front of it, your system is already in the eventual-consistency model — write to primary and read from replica right after, you get the old value; update the DB and the cache is invalidated one beat late.

So the assumption “our DB is ACID, therefore the whole system has strong consistency” only holds on a single node. Replicas, caches, CDNs — the moment data exists in two places, you are in eventual-consistency territory, and deferring the trade-off as “only when we use NoSQL” will hit you directly in production.

Why teams accept eventual consistency

DynamoDB, Cassandra, Riak, and other systems intentionally choose eventual consistency because:

  • Linearizability is expensive. Consensus algorithms require quorum agreement; under network latency or node failures, availability degrades.
  • Many workloads tolerate stale reads. A like count being 1 second behind has near-zero business impact.
  • CAP theorem (precise meaning): it says you must choose between consistency (C) and availability (A) only when a network partition (P) occurs. Without partitions, all three are possible. Brewer himself clarified in 2012 that the “two out of three” simplification misleads. The latency-vs-consistency trade-off in normal operation is covered by the PACELC theorem.

Calling eventual consistency a “marketing term” overshoots a bit. In well-designed distributed systems it is a reasonable trade-off. The point is to be clear that it does not mean data integrity is guaranteed.

Section 4 takeaway — Eventual Consistency is a weakened CAP-C; a promise about replica convergence, not a promise about restoring data integrity. It can be a reasonable choice for availability/performance in distributed systems, but it does not replace ACID’s C.

5. Sync vs Async Replication

How strongly to guarantee CAP’s C is the core of replication strategy. Two extremes first:

Synchronous replication

  • A write completes only after a defined number of replicas (often quorum, or all sync standbys) have recorded it.
  • Close to linearizability (especially when combined with consensus).
  • Downside: slow. If quorum cannot form or sync standbys cannot respond, writes block.

Asynchronous replication

  • A write hits the primary and commits immediately. Replication runs in the background.
  • Generally an eventual consistency model.
  • Pros: fast, high availability. Cons: stale reads possible + on primary failure, unreplicated data can be lost.

The rich spectrum in real DBs

PostgreSQL’s synchronous_commit setting shows the steps between the two extremes:

ValueMeaning
offReply commit before WAL is fsync-ed (fastest, data-loss risk)
localWait for local WAL fsync (no replica involvement)
remote_writeWait until replica has the write in memory
on (default)Wait for local WAL fsync (replica meaning only when synchronous_standby_names is also set)
remote_applyWait until the replica has actually applied the change (strongest, slowest)

Caveat: for synchronous_commit = on to mean “guaranteed to the replica”, you must also configure synchronous_standby_names to designate sync standbys. The two together complete the meaning — looking at on alone and concluding “guaranteed to the replica” is inaccurate.

These dials are covered in more depth in the upcoming Part D (Durability). The key point is that linearizability itself is a binary property (satisfied or not), but which consistency model to choose is a rich design space.

Consistency-model space

Consistency models — two axes and their intersection

Consistency models are not a single straight line but two axes (per Bailis, Jepsen.io):

  • Single-object axis: linearizability → sequential consistency → causal consistency → eventual consistency. Strong → weak.
  • Multi-object / transaction axis: serializability — transactions are equivalent to some serial order. Not directly comparable to linearizability; it is a different axis.
  • Both axes combined: strict serializability — transaction serialization + real-time order. Google Spanner is the canonical example.

So linearizability is the strongest single-object consistency, serializability is the standard for transactional consistency, and where the two meet is strict serializability. A system picks somewhere in this space depending on workload.

Section 5 takeaway — Consistency models split into a single-object axis (linearizability ↔ eventual) and a transaction axis (serializability), with strict serializability at their intersection as the strongest. Systems pick a point in this space using dials like sync/async replication, fsync timing, and apply timing.

6. Wrap-up — Four Things “C” Refers To

When “consistency” shows up in interviews or practice, clarify which one you mean first:

#NameMeaningWho guarantees?
1ACID’s CA transaction maintains integrity constraintsApplication (DB helps with FK / UNIQUE / etc.)
2CAP’s C (Linearizability)System looks single-copy + real-time orderingConsensus algorithm + replication
3Eventual ConsistencyNodes converge over timeAsync-replicated systems
4Transaction-level Read ConsistencySame value visible across reads in one transactionIsolation levels from Part ② (RR, SERIALIZABLE)

These four share a name but mean completely different things. If you do not pin down which one in a conversation, the conversation drifts.

Key insights

  • C is conceptually independent but built on A and I in practice: if Atomicity breaks, integrity constraints easily break too (half-applied transactions); if Isolation is weak, inconsistent reads can mislead invariant checks. Conceptually C (invariant maintenance) is separate from A·I, but for an application to maintain invariants, A and I must work properly. That is the backdrop for Kleppmann’s “C does not really belong in ACID.”
  • ACID’s C is data integrity; CAP’s C is distributed-node synchronization: same name, different problems.
  • Eventual Consistency guarantees convergence between replicas: but data with a violated invariant (corruption) is not auto-healed; a separate corrective mechanism (reconciliation batch, CRDT, reprocessing) is needed.
  • Replication strategy is a trade-off: strong consistency ↔ availability ↔ performance. Not absolutes — dials.

References (Primary Sources First)

Author
작성자 @범수

오늘의 노력이 내일의 전문성을 만든다고 믿습니다.

댓글

댓글 수정/삭제는 GitHub Discussions에서 가능합니다.