Consistency Models — linearizability থেকে eventual ladder
Consistency Models: Linearizability to Eventual
Consistency model মানে replica-client চুক্তি — linearizability real-time recency চায়, sequential শুধু per-process ক্রম, causal কারণ-প্রভাব, eventual শুধু শেষে মিল; ধাপ নামলে latency লাভ, reasoning-ভার application-এ।
আগে এটা বুঝি
CAP লেসনে map-টা দেখেছিলাম — linearizable > sequential > causal > eventual সিঁড়িটা গায়ে-গত্তে ছিল। গত লেসনে happens-before relation
হাতে এলো। কিন্তু একটা অস্বস্তি ঝুলছে: ঠিক কী দাবি করে প্রতিটা
ধাপ? “Strong consistency” বলা সহজ; কিন্তু interview-board-এ
“strong মানে কোনটা?” জিজ্ঞেস করলেই ঘর পরিষ্কার হয়ে যায়।
আজকের hook একটা ছোট history:
A: w(x = 1) t = 0..10 (complete!)
B: r(x) -> 0 t = 20..30 ← পড়ল init!A-এর লেখা ১০ tick-এ শেষ হয়ে গেছে; B পড়েছে ২০-এ — তবু পুরনো মান পেল। প্রশ্ন: এটা কি bug? আশ্চর্যের উত্তর — কোন model-এর চুক্তি তার ওপর দাঁড়ায় সেটা না বললে প্রশ্নটাই অর্থহীন। এক model-এ এটা অপরাধ, আরেক model-এ একেবারে legal।
আজ চুক্তিগুলো আইনের ভাষায় পড়ব: প্রতিটা model মানে history-র ওপর একটা predicate — কোন interleaving মেনে নেবে, কোনটা ফেরত দেবে। আর শেষে বিচারক-কোড লিখব যে ইতিহাস পড়ে রায় দেয়।
মূল ধারণা
Model মানে history-র ওপর predicate
ভোকাবুলারি আগে। Operation-এর জীবন দুই মুহূর্তের: invocation (client call) আর response (ack ফেরা) — মাঝখানের জায়গাটা interval। Client-দের চোখে যত op-এর invocation/response সাজানো থাকে, সেটাই history। Consistency model = একটা নিয়ম: এই history-র পেছনে এমন কোনো এক-ক্রম (total order) আছে কি, যেটা নির্দিষ্ট শর্ত মেনে চলে? Model-ভেদে শর্ত বদলায় — system-গুলো আসলে বলে না “আমরা fast,” বলে “আমাদের history এই predicate পাস করে।”
Linearizability — real-time recency
শর্ত দুইটা:
- প্রতিটা op কোনো না কোনো মুহূর্তে ঘটে — সেই মুহূর্ত op-এর invocation আর response-এর মাঝে (একে linearization point বলি);
- সব op-এর linearization point-এর ক্রম একটা valid single-object total order দেয় — এবং সেই ক্রম real-time সম্মান করে: এক op-এর response অন্যটার invocation-এর আগে হলে, প্রথমটা order-এও আগে।
ফল প্রতিটা read-এর জন্য: completed write-এর পরে শুরু হওয়া read নতুন মান দেখবে (বা তার পরে কোনো write হলে সেটা)। Intro-র history-তে A-এর write complete (t=10) হয়েছে B-এর read-start (t=20)-এর আগে — real-time শর্ত B-এর read-কে write-এর পরে বসাতে বাধ্য করে, তখন read-এর 0 মেলে না → not linearizable।
দামটাও এখানেই: real-time respect মানে প্রতিটা op-এর জন্য replicas কারো সাথে না কারো coordination — consensus-জাতীয় যন্ত্র ছাড়া partition-এ এই promise রাখা অসম্ভব (CAP-এর C ঠিক এটাই)।
Sequential consistency — real-time ফেলে দাও
Lamport ১৯৭৯-এ একটা শর্ত বাদ দিয়ে দেখলেন: order-টা যদি শুধু
প্রতিটা process-এর নিজের op-ক্রম সম্মান করে, cross-process
ঘড়ি-ক্রম না মানে? Intro-র একই history এবার legal — order
সাজাও [B:r->0, A:w(1)]: B একা, A একা, কারো নিজের ক্রম ভাঙে না,
আর cross-process কোনো real-time duty নেই।
Mind-bending কিন্তু মনে রাখার মতো দুই মুখ:
- Legal হয়ে যায়: “write complete-এর অনেক পরের read পুরনো মান দেখল” — যতক্ষণ ওই read-এর process-এর নিজের আগের op-গুলো মিলে যায়।
- তবু lawless নয়: Dekker-ধাঁচের ফল — A:
w(x=1)তারপরr(y)->0; B:w(y=1)তারপরr(x)->0(দুইজনই দুই মান শূন্য দেখল) — এটা sequential consistency-ও ভাঙে: per-process order চাপাচাপি করে cycle বানায়w_x < r_y < w_y < r_x < w_x। CPU memory-model জগতে ঠিক এই ফলটাই acquire/release দিয়ে আটকানো হয়।
Causal consistency — শুধু কারণ-প্রভাব ধরো
গত লেসনের relation এখানে contract হয়ে ফেরে: যে op-pair-এর মধ্যে happens-before edge আছে, সব replica/observer একই ক্রমে দেখবে; concurrent write-গুলো নিয়ে কেউ কারো কাছে রাজি নয় — ভিন্ন replica ভিন্ন ক্রমে merge করলেও চলে। Reply-before-parent অসম্ভব হয়ে যায়, কিন্তু unrelated দুই post-এর display-order স্বাধীন থাকে।
Eventual — শুধু শেষ কথাটা
Promise একটাই: write থামলে (quiescence) আর replication network ঠিক থাকলে, সব replica শেষে একই value-তে converge করবে। পথের কোনো মুহূর্তে, কোনো read-এর, কোনো ক্রমের — কোনো দাবি নেই। Convergence-এর জন্য লাগে conflict-rule (LWW/vector/CRDT) — CAP লেসনের কথা মনে আছে।
শক্তি ▲
│ linearizable real-time + total order <- consensus-দাম
│ sequential per-process order only
│ causal শুধু happens-before chain
│ eventual quiescence-এ convergence
└──────────────────────────────► latency-লাভভেতরে কী ঘটছে
Anomaly zoo — দুর্বল চুক্তির দৈনিক ভাড়াটে
Monotonic-read violation: user প্রথমে replica-A-তে (lag ০) comment-count 12 দেখল; refresh-এ load-balancer replica-B-তে (lag ৩s) — এখন 11। User-এর চোখে ভবিষ্যৎ ফিরে এলো। History-ভাষায়: দুই read ভিন্ন replica-র ভিন্ন snapshot — কোনো model-ভাঙা না, যদি চুক্তিটা eventual-ই থাকে।
Read-your-writes violation: গত লেসনের violation #2 — password বদলের ack-এর পরে lagging replica পুরনো hash দেখাল। Session-boundary security incident।
Bouncing-between-replicas: উপরের দুটোর common root — পরপর request ভিন্ন replica-তে পড়ছে; staleness distribution-এর random sample user নিজে দেখছে।
Sticky routing — সস্তা ঔষধ
Anomaly-গুলোর বেশিরভাগের cure মাত্র একটা: এক session-এর সব request এক replica-তে (বা catch-up না হওয়া পর্যন্ত redirect)। Load-balancer/app-tier-এ session-affinity — নতুন consensus, নতুন vector-clock কিছুই লাগে না। Read-your-writes আর monotonic-read দুই-ই session-ভেতরে ফিরে আসে। খরচ: node-down-এ rebind-মুহূর্তে anomaly-window, hot-replica skew, আর cross-session causality এখনো uncovered।
Implementation ladder — কে কোথায় দাঁড়ায়
| System | Guarantee | Mechanism | Config |
|---|---|---|---|
| ZooKeeper | writes linearizable-ish; reads sequential | ZAB total-order log + versioned znode | sync-flag |
| Cassandra | per-op tunable ONE→ALL | replica-count overlap + timestamps | CL per query |
| DynamoDB | eventually consistent / strongly (per-op) | quorum + version context | ConsistentRead |
| PostgreSQL primary | per-object linearizable | single-writer serialization | default |
| PG standby read | eventual | WAL lag window | hot_standby |
খরচের সারাংশ: উপরের ধাপে উঠতেই coordination — প্রতি op বা প্রতি epoch consensus round-trip; নামলে replicas local-serve করে, latency floor ভেঙে পড়ে, আর reasoning-ভার application-কোডে চলে আসে। এই trade-off-এর সংখ্যা experiment-এ।
উদাহরণ
এক history, তিন আদালত
Register x, init 0। তিন client, ছয় op:
H:
c1: w(x=1) t = 0..1
c2: r(x) -> 0 t = 2..3
c2: r(x) -> 1 t = 4..5আদালত ১ — linearizable: c2-এর প্রথম read start (t=2) >
write-end (t=1) → real-time শর্ত write-কে আগে বসাতে বাধ্য করে;
তখন read-এর মান 1 হওয়ার কথা, দেখল 0 → দোষী। Counterexample-
morph দরকার নেই — শর্তই ভাঙা।
আদালত ২ — sequential: real-time শর্ত ফেলে order সাজানো যায়?
[r->0, w(1), r->1] — প্রতিটা client-এর নিজের ক্রম অক্ষত
(c2-এর দুই read ক্রমে), মান-মিল ঠিক (init 0 → read 0; write 1 →
read 1) → খালাস। Legal order-টাই verdict-এর witness।
আদালত ৩ — causal: c1-এর write আর c2-এর read-এর মধ্যে message-path ধরা যায় না — এরা concurrent; causal-consistent world-এ এই history-র জন্য রায়ই লাগে না: কোনো causal-chain ভাঙেনি।
মোড়ের কথা — history-টাই যদি একটু ঘুরিয়ে দিই:
H':
c1: w(x=5) t = 0..1
c2: r(x) -> 5 t = 2..3
c2: r(x) -> 0 t = 4..5এবার c2-এর per-process order (r->5 আগে, r->0 পরে) এমন order
দাবি করে যেখানে 5 লেখার পরেও 0 পড়া যায় — value-check-ই cycle
বানায় → sequential-ও দোষী। H আর H’-এর ফারাকটাই model-
সংবেদনশীলতা — চোখে আঙুল দিয়ে দেখানো।
ছবিতে
overlap: A: w(x=1) non-overlap: A: w(x=1)
├───────┤ ├──┤
B: r(x)->0 or 1 ← দুই-ই legal │
├────────┤ ▼
B: r(x)->1 ← শুধু এটাই
(lin: দুই order-ই সম্ভব) (r->0 = violation) linearizable ── ZK-writes, PG-primary, etcd, Spanner*
│ (*TrueTime-bounded wait)
sequential ──── ZK-reads (sync ছাড়া), CPU-TSO-ish
│
causal ──────── MongoDB-sessions, COPS, comment-threads
│
eventual ────── Cassandra ONE, DNS-cache, view-counters
latency-cost ◄────────────────────────────► guaranteeনিজে চালিয়ে দেখুন
R/W dial ঘুরিয়ে staleness distribution মাপা — আর linearizability-ভাঙা window ধরা
# staleness_probe.py — N=3 KV cluster-এ R/W dial আর violation window
import random
def run(W, R, rounds=300, seed=42):
rng = random.Random(seed)
N = 3
applied = [0] * N # প্রতিটা replica-র latest applied version
inflight, ackq = [], [] # wire আর pending-ack queue
acked = 0 # client-confirmed সর্বোচ্চ version
latencies, stales = [], []
viol_trace = None
for t in range(1, rounds + 1):
v = t # ---- write ----
arrs = [(t + rng.randint(1, 3), v, i)
for i in rng.sample(range(N), W)]
inflight += arrs
ackq.append((max(a for a, _, _ in arrs), v, t))
done = [e for e in inflight if e[0] <= t] # ---- pump ----
inflight = [e for e in inflight if e[0] > t]
for _, ver, i in done:
applied[i] = max(applied[i], ver)
ready = [q for q in ackq if q[0] <= t]
ackq = [q for q in ackq if q[0] > t]
for at, ver, st in ready:
acked = max(acked, ver)
latencies.append(at - st)
picks = rng.sample(range(N), R) # ---- read ----
obs = max(applied[i] for i in picks) # max-version read
lag = max(0, acked - obs)
stales.append(lag)
if lag > 0 and viol_trace is None:
viol_trace = (t, acked, obs) # lin-violation!
s = sorted(stales)
ls = sorted(latencies)
pct = lambda xs, p: xs[min(int(len(xs) * p), len(xs) - 1)]
stale_pct = 100 * sum(1 for x in s if x > 0) / len(s)
return stale_pct, pct(s, .95), pct(ls, .50), pct(ls, .95), viol_trace
print(f"{'config':<10}{'stale%':>8}{'p95lag':>8}"
f"{'w-p50':>6}{'w-p95':>6} W+R>N?")
for W, R in [(1, 1), (2, 2), (3, 1)]:
sp, l95, l50, l95, _ = run(W, R)
mark = "হ্যাঁ" if W + R > 3 else "না"
print(f"W={W},R={R:<4}{sp:>7.1f}%{l95:>8}{l50:>6}{l95:>6} {mark}")
_, _, _, _, vt = run(1, 1)
t, exp, got = vt
print(f"\nviolation window (W=1,R=1): tick {t}-এ v{exp}-এর ack "
f"already-complete, তবু read দেখল v{got}")প্রত্যাশিত output (seed-fixed — deterministic):
config stale% p95lag w-p50 w-p95 W+R>N?
W=1,R=1 67.3% 3 2 3 না
W=2,R=2 0.0% 3 3 3 হ্যাঁ
W=3,R=1 0.0% 3 3 3 হ্যাঁ
violation window (W=1,R=1): tick 2-এ v1-এর ack already-complete, তবু read দেখল v0পড়ার সময়: (1,1)-এ প্রায় দুই-তৃতীয়াংশ read stale — eventual-
contract-এর দৈনিক জীবন; (2,2)-তে overlap-এর জাদু — window শূন্য
(কেন, পরের লেসনের pigeonhole-proof); আর violation-line-টাই intro-র
history-র simulation-রূপ — completed write, তবু পুরনো মান।
Async replication-এ W/R dial staleness-এর histogram বদলায়; completed write-এর পরেও stale read ধরা পড়ে — linearizability violation live; আর QUORUM-overlap দিলে window বন্ধ হয়, যেটা পরের লেসনের NWR-গণিতের প্রিভিউ।
নিজে বানান
ConsistencyChecker — history পড়ে প্রতি model-এ রায় + witness
- History-op model করুন: id, client, kind, val/seen, start, end
- Value-check: এক order-এ হাঁটুন, প্রতিটা read তার সামনের শেষ write-এর সাথে মিলছে কি
- Linearizable = value-check + real-time constraint মেনে কোনো permutation
- Sequential = শুধু value-check + per-client order edges
- n <= 7 brute-force — প্রতিটা model-এ witness-order বা দোষ ছাপুন
লক্ষ্য: উপরের আদালত-তিনটার automation। একই engine তিনবার চলবে — শুধু constraint-set বদলাবে; রায়ের সাথে legal order (বা তার অনুপস্থিতি) প্রমাণ হিসেবে ছাপবে।
# consistency_checker.py — ছোট history-তে model-verdict + counterexample
from itertools import permutations
H2 = [
dict(id="w1", client="A", kind="w", val=1, start=0, end=1),
dict(id="r1", client="B", kind="r", seen=0, start=2, end=3),
dict(id="r2", client="B", kind="r", seen=1, start=4, end=5),
]
H3 = [
dict(id="w1", client="A", kind="w", val=5, start=0, end=1),
dict(id="r1", client="B", kind="r", seen=5, start=2, end=3),
dict(id="r2", client="B", kind="r", seen=0, start=4, end=5),
]
def program_edges(hist):
"""একই client-এর op-গুলোর মধ্যে per-process order edge"""
by_c, edges = {}, set()
for op in hist:
by_c.setdefault(op["client"], []).append(op)
for ops in by_c.values():
ops = sorted(ops, key=lambda o: o["start"])
for a, b in zip(ops, ops[1:]):
edges.add((a["id"], b["id"]))
return edges
def feasible(order, hist, realtime, edges):
pos = {op["id"]: i for i, op in enumerate(order)}
cur = 0 # register init = 0
for op in order: # value-consistency
if op["kind"] == "w":
cur = op["val"]
elif op["seen"] != cur:
return False
if realtime: # linearizability-শর্ত
for a in hist:
for b in hist:
if a is not b and a["end"] <= b["start"] \
and pos[a["id"]] > pos[b["id"]]:
return False
return all(pos[a] < pos[b] for a, b in edges)
def find_witness(hist, realtime, edges):
assert len(hist) <= 7, "brute-force n<=7"
for perm in permutations(range(len(hist))):
order = [hist[i] for i in perm]
if feasible(order, hist, realtime, edges):
return [op["id"] for op in order]
return None
def verdict(name, H):
print(f"-- history {name} --")
for op in H:
what = f"w(x={op['val']})" if op["kind"] == "w" \
else f"r(x)->{op['seen']}"
print(f" {op['id']} [{op['client']}] {what} "
f"t={op['start']}..{op['end']}")
edges = program_edges(H)
lin = find_witness(H, True, edges)
seq = find_witness(H, False, edges)
show = lambda w: "[" + ", ".join(w) + "]" if w else None
print(f" linearizable : {'হ্যাঁ ' + show(lin) if lin else 'না'}")
print(f" sequential : {'হ্যাঁ ' + show(seq) if seq else 'না'}")
if not lin and seq:
print(f" morph: real-time ফেলেই legal {show(seq)}")
if not seq:
print(" কোনো permutation-ই value+order মানে না — causal-ও ভাঙা")
print()
verdict("H2", H2)
verdict("H3", H3)প্রত্যাশিত output:
-- history H2 --
w1 [A] w(x=1) t=0..1
r1 [B] r(x)->0 t=2..3
r2 [B] r(x)->1 t=4..5
linearizable : না
sequential : হ্যাঁ [r1, w1, r2]
morph: real-time ফেলেই legal [r1, w1, r2]
-- history H3 --
w1 [A] w(x=5) t=0..1
r1 [B] r(x)->5 t=2..3
r2 [B] r(x)->0 t=4..5
linearizable : না
sequential : না
কোনো permutation-ই value+order মানে না — causal-ও ভাঙাH2-র witness-order খেয়াল করুন — read আগে, write পরে; এটাই
sequential-এর অনুমোদিত সময়-ভ্রম। H3-তে per-process order (r5
আগে r0) এমন order দাবি করে যেখানে 5 লেখার আগে 0 ফেরত দেওয়া
যায় — কোনো permutation পারে না। নিজে বাড়ান: (১) H1 যোগ করুন
(w(1) → single fresh read) — তিন verdict-ই হ্যাঁ; (২) n=7-এ
runtime মাপুন — factorial growth চোখে; (৩) read-from edges যোগ
করে পূর্ণ causal-validator বানান।
বাস্তব সিস্টেমে
Jepsen-শিল্প। Kyle Kingsbury-র distributed-systems analysis-গুলো আসলে আজকের build-এর industrial রূপ — real database-এর ওপর linearizability/consistency probe চালিয়ে violation-documentary; MongoDB, Redis, Elasticsearch সবাই একসময় ধরা খেয়েছে।
Cassandra-র PBS। Bailis-র VLDB paper দেখিয়েছে QUORUM-config-এ staleness-এর probabilistic bound — “eventual মানে অসীম” নয়, measure করা যায়; production-team আজও CL-dial ঘোরায় এই math-এ।
CPU memory model। আপনার laptop-এ x86-TSO আসলে sequential- consistency-র চেয়ে সামান্য দুর্বল চুক্তি — store-buffer-এর জন্য; acquire/release fences দিয়ে শক্ত করা হয়। Ladder-টা distributed- এর আগে silicon-এ জন্মেছিল।
DynamoDB-র dual-mode। একই API-তে ConsistentRead=false (cheap,
eventual) আর true (strong) — per-operation model-choice-এর
mass-market রূপ; bill-এ পার্থক্যটা সরাসরি দেখা যায়।
যে ভুলগুলো সবাই করে
“Linearizable আর serializable একই কথা।”
Scope আলাদা। Linearizable = single-object, real-time recency; serializable = multi-object transactions যেন কোনো serial ক্রমের সমান — serializable real-time মোটেই মানে না। Isolation-levels লেসনের transaction-জগৎ আর আজকের object- জগৎ — দুই আদালতের আইন আলাদা; কেউ কাউকে imply করে না।
“Sequential consistency মানে প্রায় strong — ব্যবহারিক পার্থক্য নেই।”
পার্থক্যটা ঠিক আজকের H2-history: completed write-এর পরে পুরনো মান — linearizability এটা আজীবন আটকায়, sequential একে অনুমোদনই করে। ZooKeeper-এর read-path দিনে-রাতে এই চুক্তিতেই চলে — এবং বেশিরভাগ config-workload-এর জন্য এটাই সঠিক দাম।
“Eventual consistency মানে milliseconds-এ মিলে যাবে।”
Model-এ কোনো time-bound নেই — শুধু quiescence-শর্ত। Network partition ঝুলে থাকলে divergence minutes-এ যেতে পারে; আর conflict-rule খারাপ হলে convergence-এর পরেও ভুল value-তে মেলে (LWW data-loss)। Bound চাইলে আলাদা করে কিনতে হয় — PBS-ধাঁচে measurement, assumption নয়।
“QUORUM read + QUORUM write = linearizable।”
Overlap fresh-read দেয় — কিন্তু linearizability আরও চায়: total order, recency-across-concurrent-writes। LWW clock-skew, non-sticky session, sloppy-quorum window — সব জায়গাই ফাঁক। এই ভুলটা এত জনপ্রিয় যে পরের লেসনের প্রথম কাজই একে সংখ্যায় ভাঙা।
বুঝেছেন কি না দেখুন
1Linearizability-র দুই শর্ত এক-বাক্যে করে; আর এটা কোন scope-এ কাজ
করে?
স্মরণ
(১) প্রতিটা op-এর ভেতরে একটা linearization point আছে; (২) points-এর ক্রম valid total order এবং real-time সম্মান করে। Scope: এক object; transaction-level নয়।
2Intro-র history (write complete t=10, read t=20 returns old) —
sequential consistency-তে legal হওয়ার ঠিক কোন দরজা দিয়ে ঢুকল?
যুক্তি
Cross-process real-time শর্তটাই দরজা। Order [B:r->0, A:w(1)] —
B একা, A একা, per-process ক্রম ভাঙে না; আর “write-এর response read-
এর invocation-এর আগে” দেখার কেউ নেই। Sequential শুধু নিজের-হাতের
ক্রমের প্রতিশ্রুতি দেয়।
3Dekker-ধাঁচের ফল — দুই process-ই একে অপরের write শূন্য দেখল —
sequential consistency-ও ভাঙে কেন, যেখানে H2-র মতো stale-read ভাঙে না?
যুক্তি
Per-process order-গুলো এবার বিপরীত দিকে টানে: w_x < r_y (A-র
ক্রম) আর w_y < r_x (B-র ক্রম), অথচ read-দুটোর মান দাবি করে
w_y > r_y, w_x > r_x — মিলিয়ে cycle, কোনো total order-ই
সম্ভব নয়। H2-তে কোনো cycle ছিল না, শুধু real-time-শর্ত ছিল।
4Monotonic-read violation-এ user 12 দেখে 11 দেখল। Sticky routing
বসালে কোন মুহূর্তে কী বদলায়, আর কোন anomaly তবু থেকে যায়?
প্রয়োগ
Session-affinity প্রথম request-এর পরেই user-কে এক replica-তে pin করে — দ্বিতীয় read এখন একই snapshot-stream-এ, পিছিয়ে যাওয়া অসম্ভব। থেকে যায়: failover/rebind-মুহূর্তের window, আর cross-session causality (অন্য user-এর ক্রম) — সেটার জন্য session-guarantee যথেষ্ট নয়।
5Product-এ তিন feature: feature-flag, like-counter, cart-item-list।
তিনটার ladder-target আর mechanism — খরচের যুক্তিসহ।
ডিজাইন
Feature-flag: linearizable-leaning (consensus store) — ভুল flag মানে wrong deploy, খরচ justify। Like-counter: eventual + batch-flush — ±কয়েকটা like business-neutral, latency-লাভ full। Cart: session- scoped read-your-writes (sticky) + checkout-moment-এ strong validate। Per-operation targeting-ই সস্তা সঠিকতা।
6Experiment-এ (2,2)-এ stale% 0 এলো — এটা কি linearizability-প্রমাণ?
না হলে কী প্রমাণ, কী বাকি?
যুক্তি
(2,2)-এ stale% 0 এলো — এটা কি linearizability-প্রমাণ?
না হলে কী প্রমাণ, কী বাকি?না। Zero-stale প্রমাণ করে read সবসময় latest acked version দেখছে — freshness-under-this-workload। Linearizability আরও চায়: concurrent writes-এর total order, প্রতি op-এ real-time respect। বাকি ফাঁকগুলো পরের লেসনের NWR-limits আলোচনার খাদ্য।
এরপর কী
এরপর কী
চুক্তির ভাষা এবার হাতে — এবার সেই চুক্তি রাখার যন্ত্র। পরের
লেসনে replication-এর তিন পরিবার: primary-backup-এর sync/async
গভীরে, Dynamo-ধাঁচে leaderless NWR — W+R>N intersection-argument
আর তার সীমা — sloppy quorum, hinted handoff, Merkle-tree healing,
আর chain replication যেটা দেখায় strong consistency-ও throughput-
scale করতে পারে। Misconception #4-এর QUORUM-রহস্যের মোচড়ও এখানেই।
আরও পড়ুন
- How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs — Leslie Lamport — IEEE Transactions on Computers C-28(9), 1979 · Sequential consistency-র জন্মসংজ্ঞা — শব্দগুলো আজও হুবহু উদ্ধৃত হয়
- Linearizability: A Correctness Condition for Concurrent Objects — Maurice P. Herlihy, Jeannette M. Wing — ACM TOPLAS 12(3), 1990 · Linearizability-র formal ভিত্তি — interval semantics আর এই লেসনের সংজ্ঞার উৎস
- Probabilistically Bounded Staleness for Practical Partial Quorums — Peter Bailis, Shivaram Venkataraman, Michael J. Franklin, Joseph M. Hellerstein, Ion Stoica — VLDB 2012 · Cassandra-ধাঁচে tunable consistency-এ staleness মাপার quantitative ভাষা
- Designing Data-Intensive Applications, Chapter 9 — Martin Kleppmann · Ladder-এর practitioner-সংস্করণ — প্রতিটা ধাপের খরচের বাস্তব হিসাব