Leader Election — একজনকে দায়িত্ব দেওয়ার protocol
Leader Election
Replication-এর চুক্তি একজন leader-এর হাতে থাকে; election protocol (bully, ring) সেই leader বাছে — কিন্তু failure detector ভুল হলে দুই leader জন্মায়, তাই epoch/term fencing number আর majority gate লাগে।
আগে এটা বুঝি
Quorum লেসন শেষে আমরা একটা খোলা প্রশ্ন রেখেছিলাম: primary-backup পরিবারের সব promise primary জীবিত থাকার ওপর দাঁড়িয়ে। primary মারা গেলে — crash, network-isolation, datacenter হারিয়ে — কে দায়িত্ব নেবে? আর সবচেয়ে কঠিন: কে decide করবে যে পুরনো primary আসলেই মরে গেছে?
উত্তরটা শুনতে সরল: বাকিরা ভোট দিয়ে নতুন primary বাছবে। এই যন্ত্রটার নাম leader election। কিন্তু ওই সরল বাক্যের ভেতরে তিনটা ফাঁদ লুকানো:
ফাঁদ ১ : দুইজন একসাথে candidate হলে? (split vote)
ফাঁদ ২ : ভোট চাইতে গিয়ে দেখা গেল নিজেই isolated? (quorum-of-eligibility)
ফাঁদ ৩ : নতুন leader এল, কিন্তু পুরনোও নিজেকে leader ভাবছে! (split brain)Interview-তে সবাই বলে “leader down hole হলে auto-failover হব” — আজ আমরা দেখব failover-টা ঠিক কোন মুহূর্তে ভুল সিদ্ধান্ত নেয়, আর বাস্তব system-গুলো (ZooKeeper, etcd, Kafka) সেই মুহূর্তকে কীভাবে fencing করে।
মূল ধারণা
Leader কেন দরকার — দুইটা কংক্রিট সুবিধা
Quorum লেসনের LWW-limit মনে করুন: leaderless write-এ concurrent write-এর total order হারিয়ে যেত। একজন ordering point থাকলে সমস্যাটা জন্মায়ই না — সব write একটাই log-এ সারি বাঁধে। দ্বিতীয় সুবিধা single writer: streaming-replication লেসনের primary ঠিক এই কাজটাই করত — WAL-এ append করে standby-দের পাঠায়। N জন writer হলে conflict-resolution লাগে; ১ জন হলে replication মানেই order-preserving forwarding।
| দায়িত্ব | leader ছাড়া | leader-সহ |
|---|---|---|
| Write ordering | LWW/vector-clock merge | log position-ই order |
| Conflict resolution | application-দায়িত্ব | নেই-ই |
| Read freshness | R-replica probe | leader-এ linearizable |
| Failure response | প্রতিটা node নিজে ভাবে | একটা election |
দামটাও স্পষ্ট: leader এখন single point of failure। Election হলো সেই SPOF-কে repairable বানানোর যন্ত্র।
Bully algorithm — সবচেয়ে বড় ভোটে জেতে
Garcia-Molina-র 1982-র classic। প্রতিটা node-এর একটা id; সর্বোচ্চ id-র জীবিত node-ই leader — invariant এইটুকুই।
node3 বুঝল node4 (leader) সাড়া দিচ্ছে না:
1. node3 -> সবাইকে ELECTION(id=3) পাঠায়
2. id বেশি যারা জীবিত (node4? না; node5 হ্যাঁ) -> উত্তরে নিজের বড় id
-> node3 হার মানে, অপেক্ষা
3. node5 নিজে ELECTION(id=5) চালায় -> কেউ বড় id ফেরত দেয় না
4. node5 সবাইকে COORDINATOR(node5) ঘোষণাসরল, deterministic, আর message-count worst case-এ O(N²) —
প্রতিটা candidate-ই সবাইকে জিজ্ঞেস করে।
Ring election — একটা token, একটা দিক
Node-গুলো logical ring-এ সাজানো। Candidate একটা ELECTION message ঘুরিয়ে দেয়; প্রতিটা node নিজের id max-এর সাথে merge করে forward করে; message candidate-এর কাছে ফিরে এলে winner জানা যায়, তারপর COORDINATOR message আবার ঘোরে।
ring 0->1->2->3->4, node4 মৃত:
t1 n0->n1 ELECTION(max=0); n1->n2 ELECTION(max=1);
n2->n3 ELECTION(max=2); n3->n0 ELECTION(max=3) [circle done]
t2 COORDINATOR(leader=3) আবার ঘুরে আসেMessage count মাত্র 2(N−1) — কিন্তু latency hop-count-এ বাড়ে,
আর ring-এর মাঝে একটা dead link থাকলে bypass ব্যবস্থা লাগে।
Failure detector — পুরো খেলার আসল জুয়া
Election শুরু হয় একটা অভিযোগ দিয়ে: “leader কেমন আছে, উত্তর নেই।” এই সিদ্ধান্তটা নেয় failure detector — আসলে কিছুই না, একটা timeout timer। আর timer দুই দিকেই ভুল করতে পারে:
GC pause / network jitter / CPU starvation
-> জীবিত leader উত্তর দিতে দেরি -> detector বলে DEAD (false positive!)
partition
-> মৃত leader-এর কাছ থেকে কিছু node দূরে -> detector বলে ALIVE (false negative)failure-models লেসনের চোখে এটা inevitable: asynchronous system-এ crash-আর-slow-এর পার্থক্য নিখুঁতভাবে বলা অসম্ভব। তাই election protocol-গুলোর আসল প্রশ্ন algorithm নয় — ভুল detector-এর ওপরেও safety টেকে কি না।
Dueling leaders — যখন দুই দিকই election জেতে
Partition ধরুন: {A,B} | {C,D,E}, leader ছিল C।
A-র timer চলে গেল → A-side election → ছোট side-ও একজনকে leader বানাতে পারে (নিজেদের মধ্যে ভোট!) → dueling leaders;- পুরনো leader
Cনিজের side-এ জীবিত, নিজেকে leader-ই মনে করছে;
দুই leader-ই client-এর write নিলে state দুই ভাগে চিরতরে diverge — এটাই split brain, quorum লেসনের fencing-অধ্যায়ের সেই ভূত।
প্রতিষেধক দুইটা, দুই স্তরে:
- Majority gate: leader হতে cluster-এর strict majority (
N div 2 + 1) vote লাগবে। দুই side কখনোই একই majority পাবে না — pigeonhole! - Epoch/term fencing: প্রতিটা election-এ এক-ঘর বাড়া generation number — ZooKeeper-এর ভাষায় epoch, Raft/MongoDB-র ভাষায় term। পুরনো epoch-এর প্রমাণ (lease, write-ack) নতুন leader reject করে। fencing token এই number-কেই storage-পর্যন্ত নিয়ে যায়।
lease-ভিত্তিক leadership-এও একই কৌশল: lease grant-এর সাথে epoch জুড়ে দিলে পুরনো lease-holder-এর authority নতুন epoch-এর সামনে কাগজ।
Liveness বনাম safety — partition-এর দরদি বাণিজ্য
Majority gate-এর দামটাও মানতে হবে:
safety : কখনো একাধিক effective leader নেই (gate কিনে দেয়)
liveness: minority side-এ কিছুই চলে না (gate খেয়ে ফেলে)CAP-এর ভাষায়: consensus-family CP — partition-এ consistency রক্ষা করে availability বিসর্জন দেয়। কোন election-ই এই বাণিজ্য ভাঙতে পারে না; ভাঙলে split-brain ফিরে আসে।
ভেতরে কী ঘটছে
Timeout window-এর গণিত
Leader-dead detection latency = প্রথম follower-এর fire-time। Window
[lo, hi] uniform হলে expected min ≈ lo + (hi−lo)/(k+1) (k জন
follower)। কিন্তু window সরু হলে collision: দুইজন একই tick-এ
fire করলে split vote, সবাই retry — fixed [15,15] window-এ তো
collision প্রতি রাউন্ডেই, livelock!
Randomized window-এ collision probability প্রতি রাউন্ডে ≈
1/(hi−lo+1) — এজন্যই Raft timeout-গুলো randomize করে। Trade-off:
window চওড়া : collision rare, কিন্তু dead-leader detection ধীর
window সরু : detection দ্রুত, কিন্তু false-positive বেশি -> churnBully-র churn pathology
Bully-র লুকানো বিষ: highest-id node-টা unstable হলে। node5 বারবার unreachable→reachable হলে:
node5 down -> election -> node3/4 জেতে
node5 back -> নিজেকে ELECTION(id=5) জানায় -> re-election
node5 down -> ... # প্রতি flap-এ O(N^2) messageপুরো cluster বারবার leadership বদলায় — churn। Real system-এ এজন্যই stable-leader preference (incumbent advantage) রাখা হয়: চলমান leader যতদূর সম্ভব টিকে থাকে।
Election state machine — এক নজরে
- suspectheartbeat timeout পেরলে follower নিজে candidate হয়
- canvassvote-request ছড়ায়; split হলে randomized backoff-এ retry
- majority gateN div 2 + 1 distinct vote ছাড়া ঘোষণা নেই
- announceCOORDINATOR/AppendEntries-এ epoch সহ ঘোষণা
- fencestorage/lock layer পুরনো epoch-এর লেখা reject করে
Message complexity-র তুলনা
| Algorithm | Messages (best) | Messages (worst) | Winner | Pathology |
|---|---|---|---|---|
| Bully | N−1 | O(N²) | max id | flapping-max churn |
| Ring | 2(N−1) | 2(N−1) | max id | dead-link bypass |
| Randomized-timeout + majority | O(N) per attempt | attempts × O(N) | any eligible | split-vote rounds |
উদাহরণ
Full scenario — N=5, bully, তারপর partition
cluster: node0..node4, leader=node4, heartbeat every 2 ticks
t10 node4 GC-pause 300ms -> node2-র timeout fire
t11 node2 broadcasts ELECTION(2)
t12 node3 replies BIGGER-ID(3); node0,node1 also defer
t13 node3 wins its own round -> COORDINATOR(node3), epoch=2
t14 node4 wakes up, still thinks leader (stale epoch=1!)
t15 node4 accepts a client write <-- GHOST WRITE attempt
t16 storage rejects: epoch 1 \< epoch 2 <-- fencing saves us
t20 partition: {node0,node1} | {node2,node3,node4}
t21 node0 timeout -> local election -> node1 declared on minority
t22 node3 side: already has leader node3 (epoch 2) = DUAL LEADERS?
t23 node1 tries commit -> needs 3 votes, has 2 -> BLOCKED forever
t24 net effect: only majority side serves; safety intactলক্ষ্য করুন তিনটা স্তর: t13-এ election শেষ, t15–16-এ fencing পুরনো leader-কে নিঃশব্দে neutralize করল, t21–23-এ majority gate minority- কে অজু করে দিল। Election, fencing, gate — তিনটাই লাগে; কোনো একটা বাদ দিলে গল্পটা ভাঙে।
ছবিতে
node0 node1 node2 node3 node4(dead)
| | |--ELECTION->| X
| | |\<--BIGGER--| X
| | | (node3 takes over the canvass)
| | |\<-COORDINATOR(node3, epoch=2)--|
| | | |
all nodes record leader=node3, epoch=2 partition {n0,n1} | {n2,n3,n4}
---------------------+---------------------
n1: votes=2 | n3: votes=3
need 3 -> BLOCKED | need 3 -> LEADER
writes queued | writes served
|
pigeons: 5 votes total, two sides cannot BOTH hold >= 3নিজে চালিয়ে দেখুন
Leader-death re-election timing + partition-এ dual-leader নাটক
# election_probe.py — leader-death re-election timing + partition dual-leader demo
import random
def reelection(n=5, lo=10, hi=40, seed=7, death_at=50, horizon=300):
"""Leader dies; followers fire timeouts uniform in [lo,hi];
unique earliest fires wins — collision means retry."""
rng = random.Random(seed)
alive = [True] * n
splits = attempts = 0
latency = None
t = 0
while t < horizon:
t += 1
if t == death_at:
alive[n - 1] = False # leader dies
if t <= death_at:
continue
fires = [rng.randint(lo, hi) for i in range(n) if alive[i]]
first = min(fires)
if fires.count(first) > 1: # same-tick collision
splits += 1
attempts += 1
continue # everyone retries
attempts += 1
latency = first # ticks after death
break
return latency, splits, attempts
print("config leader-by split-rounds")
for label, lo, hi in (("fixed [15,15]", 15, 15),
("jitter [12,18]", 12, 18),
("wide [10,40]", 10, 40)):
lat, sp, att = reelection(lo=lo, hi=hi)
if lat is None:
print(f"{label:<14} NO LEADER by tick 300 {sp}+ splits")
else:
print(f"{label:<14} +{lat:<3} ticks {sp}/{att}")
def partition_run(majority_gate):
sides = [{0, 1}, {2, 3, 4}] # cut between node1-node2
result = []
for side in sides:
cand = max(side) # bully-style pick
votes = 1 # self-vote
for v in side - {cand}:
votes += 1 # VOTE-YES arrives
ok = votes * 2 > 5 if majority_gate else votes >= 2
result.append((sorted(side), cand if ok else None))
return result
for gate in (False, True):
res = partition_run(gate)
tag = "majority-gate ON " if gate else "majority-gate OFF"
parts = "; ".join(
f"side{side}: {('leader=node%d' % l) if l is not None else 'BLOCKED'}"
for side, l in res)
dual = sum(1 for _, l in res if l is not None) > 1
print(f"{tag}: {parts} -> {'DUAL-LEADER!' if dual else 'single leader'}")প্রত্যাশিত output (seed-fixed):
config leader-by split-rounds
fixed [15,15] NO LEADER by tick 300 250+ splits
jitter [12,18] +13 ticks 0/1
wide [10,40] +14 ticks 0/1
majority-gate OFF: side[0, 1]: leader=node1; side[2, 3, 4]: leader=node4 -> DUAL-LEADER!
majority-gate ON : side[0, 1]: BLOCKED; side[2, 3, 4]: leader=node4 -> single leaderপড়ার সময়: প্রথম row-টা হলেন villain — identical timeout মানেই প্রতি রাউন্ডে five-way collision, চিরতরে leaderless। শেষ দুই line-এ gate-এর বাণিজ্য: OFF-এ দুই leader, ON-এ এক leader + এক disabled side।
Fixed timeout window-এ split vote livelock বানায় (কোনো leader-ই নির্বাচিত হয় না), randomized window-এ সাথে সাথে leader আসে; partition-এ majority gate বন্ধ করলে দুই side-ই leader বানায় (DUAL-LEADER!), gate চালু করলে minority block হয় — liveness-vs-safety trade-off live।
নিজে বানান
ElectionRing — ring election + majority variant, hop-by-hop ASCII timeline
- N-node logical ring বানান; next_alive() dead node skip করে
- ELECTION token hop-by-hop ঘোরে, প্রতিটা node নিজের id max-merge করে
- Token origin-এ ফিরলে COORDINATOR message দ্বিতীয় circle ঘোরে
- প্রতিটা message (tick, from, to, msg) timeline-এ print করুন
- Variant: unicast VOTE-REQUEST/VOTE-YES + strict-majority gate, message-count তুলনা করুন
লক্ষ্য: দুই protocol-এর message anatomy চোখের সামনে trace করা — কে কাকে কী পাঠাল, কত message খরচ হলো, winner কে।
# election_ring.py — ElectionRing: ring election vs majority-vote, hop-by-hop trace
N = 5
LEADER = N - 1 # node 4 starts as leader, then dies
class ElectionRing:
def __init__(self, mode="ring"):
self.mode = mode
self.alive = [True] * N
self.log = [] # (tick, from, to, msg)
self.tick = 0
self.msgs = 0
def next_alive(self, i):
j = (i + 1) % N
while not self.alive[j]:
j = (j + 1) % N
return j
def send(self, frm, to, msg):
self.msgs += 1
self.log.append((self.tick, frm, to, msg))
def kill(self, i):
self.alive[i] = False
# ---- ring protocol: ELECTION token carries highest id seen ----
def elect_ring(self):
origin = self.next_alive(LEADER)
hi, cur = origin, origin
while True: # forward hop-by-hop
nxt = self.next_alive(cur)
if cur != origin:
hi = max(hi, cur)
self.send(cur, nxt, f"ELECTION(max={hi})")
if nxt == origin: # token completed circle
break
cur = nxt
cur = origin # announce phase
while True:
nxt = self.next_alive(cur)
self.send(cur, nxt, f"COORDINATOR(leader={hi})")
if nxt == origin:
break
cur = nxt
return hi
# ---- majority variant: unicast votes, declare only with > N/2 ----
def elect_majority(self):
origin = self.next_alive(LEADER)
votes = 1 # own vote
for v in range(N):
if v != origin and self.alive[v]:
self.send(origin, v, "VOTE-REQUEST")
votes += 1
self.send(v, origin, f"VOTE-YES(for={origin})")
if votes > N // 2:
for v in range(N):
if v != origin and self.alive[v]:
self.send(origin, v, f"COORDINATOR(leader={origin})")
return origin
return None
def run(self):
self.kill(LEADER)
self.tick = 1
return (self.elect_ring() if self.mode == "ring"
else self.elect_majority())
for mode in ("ring", "majority"):
r = ElectionRing(mode)
w = r.run()
print(f"=== mode={mode}: leader=node{w}, messages={r.msgs}")
for t, f, to, m in r.log[:6]:
print(f" t{t:>2} node{f} -> node{to} {m}")
if len(r.log) > 6:
print(f" ... (+{len(r.log) - 6} more)")প্রত্যাশিত output (deterministic):
=== mode=ring: leader=node3, messages=8
t 1 node0 -> node1 ELECTION(max=0)
t 1 node1 -> node2 ELECTION(max=1)
t 1 node2 -> node3 ELECTION(max=2)
t 1 node3 -> node0 ELECTION(max=3)
t 1 node0 -> node1 COORDINATOR(leader=3)
t 1 node1 -> node2 COORDINATOR(leader=3)
... (+2 more)
=== mode=majority: leader=node0, messages=9
t 1 node0 -> node1 VOTE-REQUEST
t 1 node1 -> node0 VOTE-YES(for=0)
t 1 node0 -> node2 VOTE-REQUEST
t 1 node2 -> node0 VOTE-YES(for=0)
t 1 node0 -> node3 VOTE-REQUEST
t 1 node3 -> node0 VOTE-YES(for=0)
... (+3 more)পড়ার সময়: ring-mode winner node3 (max-id invariant), majority-mode winner node0 (initiator) — একই cluster, ভিন্ন চুক্তি। Message-count প্রায় সমান (৮ বনাম ৯), কিন্তু majority-mode-র প্রতিটা vote আলাদা round-trip — WAN-এ ring-এর sequential hops আরও ব্যথা দেয়।
নিজে বাড়ান: node4-কে flapping করান (kill→revive লুপ) আর দেখুন bully-invariant কতবার re-election ট্রিগার করে; majority-mode-এ candidate নিজের বদলে lowest-id পেলে কী হয়?
বাস্তব সিস্টেমে
ZooKeeper (ZAB)। Ensemble-এ fast leader election (epoch-based), তারপর সব write সেই leader-এর atomic broadcast-এ। ZooKeeper নিজেই coordination-service — হাজারো HDFS/YARN/SolrCloud cluster এটাকে authority হিসেবে ভাড়া নেয়।
etcd (Raft)। Kubernetes-এর হৃদয়। Raft election — randomized timeout + term + majority vote; extra production armor: pre-vote (unproven candidate আগে জিজ্ঞেস করে disruption এড়াতে) আর check-quorum (leader নিজে majority হারিয়েছে কি না মাঝপথে যাচাই করে)।
Kafka KRaft migration। Kafka জীবনভর metadata-র জন্য ZooKeeper ভাড়া নিয়েছিল; KRaft (Kafka Raft) metadata topic-এর জন্য built-in Raft quorum controller আনে — dependency এক ঘরে নামল, controller failover সেকেন্ডে নামল। Migration note: একই প্রতিষ্ঠানের দুই generation, একই lesson — election-কে dedicated consensus-layer-এ দিন, ad-hoc নয়।
Kubernetes leader election। Controller-manager-এর HA-র জন্য API-server-এ Lease object: holder identity + renewTime; timeout-এ অন্য replica takeover করে — মূলত এই লেসনের lease+epoch pattern-এর managed রূপ।
যে ভুলগুলো সবাই করে
“সবচেয়ে বড় ID-ই জিতুক — bully সব সময় optimal।”
Bully-র invariant সরল, কিন্তু highest node unstable হলেই churn:
প্রতি flap-এ full re-election, worst-case O(N²) message। Stable-leader
preference ছাড়া bully busy cluster-এ self-inflicted outage বানায়।
“Election জিতলাম, এখন সব ঠিক আছে — কাজ চলবে।”
Election শেষ মানে শুধু একজনকে দায়িত্ব দেওয়া হলো; পুরনো leader নিজের মৃত্যু মানেনি — ghost-write আটকাতে epoch/fencing আর majority gate লাগে। Detection, designation, enforcement — তিন আলাদা স্তর।
“Dual leader হলেই data corruption নিশ্চিত।”
Fencing layer থাকলে পুরনো epoch-এর write স্টোরে ঢোকেই না — দুই leader দেখতে থাকে, এক leader-ই লেখে। Corruption তখনই, যখন storage-পর্যন্ত fencing number পৌঁছায় না (অথবা non-fenced lock)।
“Randomized timeout এমনি magic — fixed দিলেও তো চলত।”
Fixed window-এ collision deterministic — experiment-এর first row:
250+ split, zero leader। Randomization magic নয়, গণিত: collision
probability ≈ 1/window-width; width আর detection-latency-র বাণিজ্য।
“Ring election পুরনো তাই — বাদ দিতেই হবে।”
Message-count bounded (2(N−1)), deterministic, memoryless —
embedded/fabric network-এ আজও sensible। Bad হওয়ার কারণ পুরনো নয়;
general-purpose WAN consensus-এ majority-vote family-র feature-set
(term fencing, log check) richer।
বুঝেছেন কি না দেখুন
1Bully আর ring election-এ winner কে? Message complexity কত-কত?
স্মরণ
দুটোতেই winner = সর্বোচ্চ id-র জীবিত node। Bully best N−1,
worst O(N²); ring সবসময় 2(N−1) (dead-link bypass ছাড়া)।
2Fixed [15,15] timeout window-এ কী হয় আর কেন? Randomize করলে কী বদলায়?
যুক্তি
[15,15] timeout window-এ কী হয় আর কেন? Randomize করলে কী বদলায়?পাঁচজনই এক tick-এ fire → collision → split vote → retry → আবার
collision: livelock, কোনো leader নেই। Randomization-এ same-tick
probability ≈ 1/width; প্রথম unique-min fire-ই জেতে — detection
latency মাত্র কয়েক tick।
3Example-এ t16-এ storage কীভাবে node4-এর write ফেলে দিল? কোন সংখ্যা কার?
প্রয়োগ
Epoch comparison: node4-এর authority epoch 1-এর, স্টোর এখন epoch 2
দেখছে; 1 \< 2 → reject। Epoch-টাই fencing-token: পুরনো generation-এর
প্রমাণ নতুন generation-এ কাগজ।
4Majority gate ছাড়া দুই partition-side-ই leader বানাল; gate দিলে minority
BLOCKED। Safety-liveness বাণিজ্যটা বাক্যে বলুন।
যুক্তি
Gate কিনে দেয় at-most-one-leader (safety), খেয়ে ফেলে minority-র availability (liveness)। Pigeonhole: 5-এর মধ্যে দুই disjoint side একসাথে ≥3 vote পায় না — তাই guarantee ভাঙে না।
5Flapping highest-id node-সহ busy cluster-এ কোন election design বাছবেন, কেন?
ডিজাইন
Randomized-timeout + majority + incumbent-preference (Raft-ধাঁচ): stable leader টিকে থাকে, flapper শুধু নিজের ভোট না দিলেই চলে; bully হলে প্রতি flap-এ গোটা cluster re-election করত। Pre-vote/check-quorum যোগ করলে disruption আরও কমে।
6ZooKeeper, etcd, Kafka-KRaft — election দিক থেকে এক লাইনে তুলনা করুন।
প্রয়োগ
ZooKeeper: ZAB-এর fast-election + epoch + atomic broadcast। etcd: Raft election (randomized timeout, term, pre-vote, check-quorum)। Kafka: ZooKeeper-dependency KRaft built-in Raft quorum দিয়ে বদলেছে — metadata election এখন broker-cluster-এর নিজের।
এরপর কী
এরপর কী
আমাদের হাতে এখন একজন leader — majority-র সই, epoch-এর গায়ে-বাঁধা। কিন্তু লক্ষ্য করুন: election ঠিক করে কে সিদ্ধান্ত নেবে, কোন value-তে একমত হতে হবে তা নয়। পুরনো leader-এর half-propagated value, নতুন proposer-এর conflicting value — এদের মধ্যে একটা বেছে নেওয়ার নিয়ম কী? এই হলো consensus problem — আর এর ঐতিহাসিক উত্তর Paxos, যার reputation এমন: “সবাই বোঝে consensus দরকার; কেউ বোঝে না Paxos কেন কাজ করে।” পরের লেসনে আমরা intuition দিয়ে শুরু করব — কেন naive attempt গুলো ব্যর্থ হয়, সেখান থেকে Paxos-এর invariant-গুলো নিজেই বেরিয়ে আসবে।
আরও পড়ুন
- Elections in a Distributed Computing System — Hector Garcia-Molina — IEEE Transactions on Computers, 1982 · Bully আর ring election-এর মূল paper — এই লেসনের দুই classic algorithm এখানেই প্রথম formalize হয়
- ZooKeeper: Wait-free Coordination for Internet-scale Systems — Patrick Hunt, Mahadev Konar, Flavio P. Junqueira, Benjamin Reed — USENIX ATC 2010 · ZooKeeper-এর ZAB protocol — leader election + atomic broadcast-এর production রূপ
- In Search of an Understandable Consensus Algorithm (Raft) — Diego Ongaro, John Ousterhout — USENIX ATC 2014 · Raft-এর leader election section — randomized timeout আর term-এর আধুনিক treatment; পরের-পরের লেসনের ভিত্তি