A Map of Consistency Models — Linearizable, Serializable, Causal, Eventual TODO
Concept
A consistency model is a contract for how much reordering a system allows under concurrent access. Linearizability requires that each individual operation on a single object appear to take effect atomically at some point between its call and its response, in an order that respects real time. Serializability is a property of multi-object transactions: the result of concurrent execution just has to match some sequential execution — it doesn't require respecting real-time order. Causal consistency guarantees ordering only for writes that causally precede one another; concurrent writes may be seen in different orders on different nodes. Eventual consistency promises only that replicas converge at some point once updates stop arriving. Strict serializability, combining the two strongest properties, is the strongest of all — and the stronger the guarantee, the higher the cost in availability and latency, making this fundamentally a CAP/PACELC trade-off.
Bugs of the form "I read right after I wrote, but the value isn't there" usually come from a system actually being weaker than the model people assumed it guaranteed; choosing an unnecessarily strong model, conversely, just wastes latency and cost for nothing.
Code & Formula
# 일관성 모델 지도 — 선형화(linearizable) 읽기와 최종 일관성(eventual) 읽기를 토이 복제 카운터로 비교.
# 선형화는 항상 최신 쓰기를 즉시 보고, 최종 일관성은 복제 지연 동안 stale read가 가능하다.
import random
random.seed(2)
class LinearizableCounter:
"""단일 리더에게만 쓰고 읽는다 -> 항상 최신 값 (선형화 가능)"""
def __init__(self):
self.value = 0
def write(self, delta):
self.value += delta
def read(self):
return self.value
class EventuallyConsistentCounter:
"""리더에 쓰고, 복제본은 비동기로 지연 복제 -> replica read는 stale할 수 있다"""
def __init__(self, replication_lag=2):
self.leader_value = 0
self.replica_value = 0
self.pending = [] # (도착까지 남은 tick, delta)
self.replication_lag = replication_lag
def write(self, delta):
self.leader_value += delta
self.pending.append([self.replication_lag, delta])
def tick(self):
"""시간 한 틱 진행: 복제 지연이 다 된 갱신을 replica에 반영"""
still_pending = []
for entry in self.pending:
entry[0] -= 1
if entry[0] <= 0:
self.replica_value += entry[1]
else:
still_pending.append(entry)
self.pending = still_pending
def read_from_replica(self):
return self.replica_value
lin = LinearizableCounter()
ec = EventuallyConsistentCounter(replication_lag=2)
lin.write(+1)
ec.write(+1)
print("write-then-read 직후:")
print(f" linearizable read = {lin.read()} (항상 최신)")
print(f" eventual read = {ec.read_from_replica()} (아직 복제 안 됨 -> stale)")
for t in range(1, 3):
ec.tick()
print(f" tick {t} 후 eventual read = {ec.read_from_replica()}")
print("\n결론: 최종 일관성은 갱신이 멈추면 언젠가 수렴하지만, 그 사이엔 stale read를 감수해야 한다.")
docs/code/algorithms/algorithms-52.py
Exercise
Reproduce a stale read for real by running a write-then-read scenario against a read replica with replication lag, then fix it to get read-your-writes via session pinning or reading from the leader.
Practical Connection
A blockchain's finalized chain effectively provides a global linearizable order, but pre-finality reorganization is possible, so an indexer or off-chain order book should treat pre-finality state as only eventually consistent and reflect it in settlement only after finality.
Where it lands in Jayverse
- Verex: label CLOB order-book state as eventually consistent pre-finality, and gate settlement or payout logic on finalized state only. This matches the reorg risk this page names for pre-finality data.
- Bridge: have the lock-and-mint relayer wait for source-chain finality before minting on the destination. Treat pre-finality confirmations as a weaker guarantee than linearizable rather than as good enough.
- gitboard: label any indexer-sourced dashboard figure as pre-finality or finalized. So a reorg-able number is never displayed as settled.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| take effect | 효력이 발생하다, 적용되다 · 어떤 작업이 실제로 반영되는 시점을 말할 때. "appear to take effect atomically" |
| respect (an order) | (순서 등을) 따르다, 지키다 · 규칙이나 시간 순서를 어기지 않을 때. "in an order that respects real time" |
| converge | 수렴하다, 한 값으로 모이다 · 여러 복제본이 결국 같은 상태로 맞춰질 때. "replicas converge at some point" |
| stale read | 오래돼 갱신 안 된 읽기값 · 최신 쓰기가 반영되지 않은 상태로 읽히는 현상. "reproduce a stale read for real" |
| replication lag | 복제 지연 · 원본과 복제본 사이에 데이터 반영이 늦어지는 시간차. "a read replica with replication lag" |
| session pinning | 세션 고정 · 한 사용자의 요청을 계속 같은 노드로 보내 일관성을 보장하는 기법. "read-your-writes via session pinning" |
| wastes latency and cost for nothing | 괜히 지연과 비용만 낭비하다 · 불필요하게 과한 보장을 선택해서 손해만 볼 때. "wastes latency and cost for nothing" |
| CAP | CAP 정리(Consistency, Availability, Partition tolerance) · 분산 시스템에서 세 속성을 동시에 완전히 만족할 수 없다는 정리, 일관성 모델 선택의 근본 제약. "a CAP/PACELC trade-off" |
| PACELC | PACELC 정리 · CAP를 확장해 "분할(P) 상황이 아닐 때도(Else) 지연(Latency)과 일관성(Consistency) 사이에서 선택해야 한다"는 트레이드오프를 설명하는 프레임워크. "a CAP/PACELC trade-off" |
If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/dev-100-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.