ЁЯПл The SchoolтА║ЁЯМР Distributed SystemsтА║ЁЯФА рдзрдбрд╛ 03 тАФ Ordering & causality: рдЖрдзреА, рдирдВрддрд░, рдХреА рдПрдХрд╛рдЪ рд╡реЗрд│реА
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯФА рдзрдбрд╛ 03 тАФ Ordering & causality: рдЖрдзреА, рдирдВрддрд░, рдХреА рдПрдХрд╛рдЪ рд╡реЗрд│реА

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 03 ┬╖ рдорд╛рдЧреЗ: lesson-02-clocks ┬╖ рдкреБрдвреЗ: lesson-04-failure-detection


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ02, рдЕрдзрд┐рдХ vector clocks: рдкреНрд░рддреНрдпреЗрдХ рдЪрд┐рдареНрдареАрд╡рд░ рдЕрд╕рдгрд╛рд░рд╛, рдкреНрд░рддреНрдпреЗрдХ рд╢рд╛рдЦреЗрд╕рд╛рдареА рдПрдХ counter. рддреНрдпрд╛рдВрдЪреНрдпрд╛рдореБрд│реЗ рджреЛрди рдШрдЯрдирд╛ рдПрдХрддрд░ before, after, same, рдХрд┐рдВрд╡рд╛ concurrent рдЕрд╕рддрд╛рдд тАФ рдЖрдгрд┐ "concurrent" рдореНрд╣рдгрдЬреЗ рдЦрд░рд╛ conflict, рдЙрд╢реАрд░ рдирд╡реНрд╣реЗ. dist/demo.py рдордзрд▓реЗ ordering() рдЖрдгрд┐ dist/sim.py рдордзрд▓реЗ VectorClock + compare().

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдЖрддрд╛ рдкреНрд░рддреНрдпреЗрдХ рд╢рд╛рдЦрд╛ рдЪрд╛рд░ рдЦрд╛рдиреЗ рдЕрд╕рд▓реЗрд▓реЗ рдПрдХ рдЫреЛрдЯреЗ рдХрд╛рд░реНрдб рдареЗрд╡рддреЗ: рдкреБрдгреЗ, рдирд╛рд╢рд┐рдХ, рдирд╛рдЧрдкреВрд░, рдХреЛрд▓реНрд╣рд╛рдкреВрд░. ЁЯЧВя╕П рдкреНрд░рддреНрдпреЗрдХ рдЦрд╛рдирд╛ рдореЛрдЬрддреЛ "рддреНрдпрд╛ рд╢рд╛рдЦреЗрдХрдбреВрди рдЖрд▓реЗрд▓реНрдпрд╛ рдХрд┐рддреА рдЧреЛрд╖реНрдЯреА рдореА рдкрд╛рд╣рд┐рд▓реНрдпрд╛ рдЖрд╣реЗрдд".

рдЖрддрд╛ рджреЛрди рдХрд╛рд░реНрдбрд╛рдВрдЪреА рддреБрд▓рдирд╛ рдХрд░рд╛. рдХрд╛рд░реНрдб A рд╡рд░рдЪрд╛ рдкреНрд░рддреНрдпреЗрдХ рдЦрд╛рдирд╛ рдХрд╛рд░реНрдб B рдкреЗрдХреНрд╖рд╛ рд▓рд╣рд╛рди рдХрд┐рдВрд╡рд╛ рд╕рдорд╛рди рдЕрд╕реЗрд▓, рддрд░ A рд╣реЗ B рдЪреНрдпрд╛ рдЖрдзреА рдШрдбрд▓реЗ тАФ B рд▓рд┐рд╣рд┐рдгрд╛рд▒реНрдпрд╛рдиреЗ A рдкрд╛рд╣рд┐рд▓реЗ рд╣реЛрддреЗ.

рдкрдг рдирд╛рдЧрдкреВрд░рдордзрд▓реНрдпрд╛ рджреАрдкрд┐рдХрд╛рдиреЗ рдХреЛрдгрддреАрд╣реА рдЪрд┐рдареНрдареА рди рд╡рд╛рдЪрддрд╛ рдХрд╛рд╣реАрддрд░реА рд▓рд┐рд╣рд┐рд▓реЗ. рддрд┐рдЪреЗ рдХрд╛рд░реНрдб рд╕рд╛рдВрдЧрддреЗ "рдирд╛рдЧрдкреВрд░ 1" рдЖрдгрд┐ рдмрд╛рдХреА рд╕рдЧрд│реАрдХрдбреЗ рд╢реВрдиреНрдп. рдРрд╢реНрд╡рд░реНрдпрд╛рдЪреЗ рдХрд╛рд░реНрдб рд╕рд╛рдВрдЧрддреЗ "рдкреБрдгреЗ 1, рдирд╛рд╢рд┐рдХ 1, рдирд╛рдЧрдкреВрд░ 0". рдкреНрд░рддреНрдпреЗрдХ рдХрд╛рд░реНрдбрд╡рд░ рдЕрд╕рд╛ рдПрдХ рдЦрд╛рдирд╛ рдЖрд╣реЗ рдЬреЛ рджреБрд╕рд▒реНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдореЛрдард╛ рдЖрд╣реЗ. рдХреЛрдгреАрдЪ рджреБрд╕рд▒реНрдпрд╛рдЪреЗ рдкрд╛рд╣рд┐рд▓реЗ рдирд╛рд╣реА. рддреНрдпрд╛ concurrent рдЖрд╣реЗрдд тАФ рджреЛрди рдЬрдгреАрдВрдиреА рдПрдХрд╛рдЪ рд╡реЗрд│реА рдПрдХрдЪ рдЧреЛрд╖реНрдЯ рдмрджрд▓рд▓реА, рдЖрдгрд┐ рдХрд╛рдп рдареЗрд╡рд╛рдпрдЪреЗ рддреЗ рдХреЛрдгреАрддрд░реА рдард░рд╡рд╛рдпрд▓рд╛рдЪ рд╣рд╡реЗ.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    e1["e1 at Pune<br/>pune 1 ┬╖ nashik 0 ┬╖ nagpur 0"]
    e2["e2 at Nashik, after reading e1<br/>pune 1 ┬╖ nashik 1 ┬╖ nagpur 0"]
    e3["e3 at Nagpur, saw nobody<br/>pune 0 ┬╖ nashik 0 ┬╖ nagpur 1"]
    e1 -->|"note: e1 before e2"| e2
    c["тЪб e2 vs e3: concurrent<br/>a real conflict to resolve"]
    e2 --- c
    e3 --- c

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/distributed-systems/lesson-diagrams.html#l03

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг concurrent writes рд╕рд╛рдареА "рд╢реЗрд╡рдЯреА рдХреЛрдгрддрд╛ write рдЖрд▓рд╛?" рдпрд╛ рдкреНрд░рд╢реНрдирд╛рд▓рд╛ рдЙрддреНрддрд░рдЪ рдирд╛рд╣реА. рдЬреА system time stamp рдиреБрд╕рд╛рд░ рдПрдХ рдирд┐рд╡рдбрддреЗ рддреА рджреБрд╕рд░рд╛ рдЧреБрдкрдЪреВрдк рдЧрдорд╛рд╡рддреЗ. Vector clocks рдЕрд╕рд▓реЗрд▓реА system рд╣рд╛ рдлрд░рдХ рдкрд╛рд╣реВ рд╢рдХрддреЗ: "рдРрд╢реНрд╡рд░реНрдпрд╛рдЪреНрдпрд╛ рдмрджрд▓рд╛рдиреЗ рдХрддрд░рд┐рдирд╛рдЪреНрдпрд╛ рдмрджрд▓рд╛рдЪреА рдЬрд╛рдЧрд╛ рдШреЗрддрд▓реА" (before тЖТ рдирд╡рд╛ рдареЗрд╡рд╛) рдЖрдгрд┐ "рдРрд╢реНрд╡рд░реНрдпрд╛ рдЖрдгрд┐ рджреАрдкрд┐рдХрд╛ рджреЛрдШреАрдВрдиреА рди рдХрд│рддрд╛ рдмрджрд▓рд▓реЗ" (concurrent тЖТ рджреЛрдиреНрд╣реА рдареЗрд╡рд╛, merge рдХрд░рд╛ рдХрд┐рдВрд╡рд╛ рд╡рд┐рдЪрд╛рд░рд╛). Conflict рджрд┐рд╕рдгреЗ рд╣реА data рди рдЧрдорд╛рд╡рдгреНрдпрд╛рдЪреА рдкрд╣рд┐рд▓реА рдкрд╛рдпрд░реА рдЖрд╣реЗ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

dist/sim.py рдордзрд▓реЗ VectorClock(me, nodes) рдкреНрд░рддреНрдпреЗрдХ рд╢рд╛рдЦреЗрд╕рд╛рдареА рдПрдХ counter рдЕрд╕рд▓реЗрд▓реА dict рдареЗрд╡рддреЗ. tick() рд╕реНрд╡рддрдГрдЪреНрдпрд╛ entry рдордзреНрдпреЗ 1 рдорд┐рд│рд╡рддреЗ. recv(other) рдкреНрд░рддреНрдпреЗрдХ entry рдЪрд╛ maximum рдШреЗрддреЗ, рдЖрдгрд┐ рдордЧ tick рдХрд░рддреЗ. compare(a, b) рдкреНрд░рддреНрдпреЗрдХ key рд╕рд╛рдареА a[k] <= b[k] рдЖрдгрд┐ a[k] >= b[k] рддрдкрд╛рд╕реВрди 'same', 'before', 'after' рдХрд┐рдВрд╡рд╛ 'concurrent' рдкрд░рдд рджреЗрддреЗ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 dist/demo.py ordering
python3 - <<'EOF'
import sys; sys.path.insert(0, "dist"); from sim import VectorClock, compare
B = ["pune", "nashik", "nagpur", "kolhapur"]
vp, vn, vg = VectorClock("pune", B), VectorClock("nashik", B), VectorClock("nagpur", B)
e1 = vp.tick(); e2 = vn.recv(e1); e3 = vg.recv(e2)     # this time Nagpur reads Nashik's note first
print("e3 =", e3)
print("e1 vs e3:", compare(e1, e3), "┬╖ e2 vs e3:", compare(e2, e3), "┬╖ e3 vs e1:", compare(e3, e1))
x = vp.tick(); y = vg.tick()                            # both write again without talking
print("x =", x); print("y =", y); print("x vs y:", compare(x, y))
EOF

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

ordering рд╣реЗ print рдХрд░рддреЗ:

тФАтФА vector clocks: e1 at Pune {'pune': 1, 'nashik': 0, 'nagpur': 0, 'kolhapur': 0}
   e2 at Nashik after reading e1 {'pune': 1, 'nashik': 1, 'nagpur': 0, 'kolhapur': 0}
   e3 at Nagpur, unaware of both {'pune': 0, 'nashik': 0, 'nagpur': 1, 'kolhapur': 0}
   e1 vs e2: before
   e2 vs e3: concurrent
   e1 vs e3: concurrent

рддреБрдордЪрд╛ snippet рд╣реЗ print рдХрд░рддреЛ:

e3 = {'pune': 1, 'nashik': 1, 'nagpur': 1, 'kolhapur': 0}
e1 vs e3: before ┬╖ e2 vs e3: before ┬╖ e3 vs e1: after
x = {'pune': 2, 'nashik': 0, 'nagpur': 0, 'kolhapur': 0}
y = {'pune': 1, 'nashik': 1, 'nagpur': 2, 'kolhapur': 0}
x vs y: concurrent

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рдирд╛рдЧрдкреВрд░рдЪрд╛ рддреЛрдЪ write demo рдордзреНрдпреЗ "concurrent" рдЖрд╣реЗ рдЖрдгрд┐ рддреБрдордЪреНрдпрд╛ snippet рдордзреНрдпреЗ "after". рдПрдХрдореЗрд╡ рдлрд░рдХ: рддреБрдордЪреНрдпрд╛ snippet рдордзреНрдпреЗ рдирд╛рдЧрдкреВрд░рдиреЗ рдЖрдзреА рдЪрд┐рдареНрдареА рд╡рд╛рдЪрд▓реА. Causality рдореНрд╣рдгрдЬреЗ рд▓рд┐рд╣рд┐рдгрд╛рд▒реНрдпрд╛рд▓рд╛ рдХрд╛рдп рдорд╛рд╣реАрдд рд╣реЛрддреЗ, рдШрдбреНрдпрд╛рд│рд╛рдиреЗ рддреНрдпрд╛рдиреЗ рдХрдзреА рд▓рд┐рд╣рд┐рд▓реЗ рдЕрд╕реЗ рд╕рд╛рдВрдЧрд┐рддрд▓реЗ рддреЗ рдирд╡реНрд╣реЗ. рдЖрдгрд┐ y рдЪреНрдпрд╛ рдмрд╣реБрддреЗрдХ рдЦрд╛рдиреНрдпрд╛рдВрдд рдореЛрдареЗ рдЖрдХрдбреЗ рдЕрд╕реВрдирд╣реА x рд╡рд┐рд░реБрджреНрдз y concurrent рдЖрд╣реЗ тАФ рдкреБрдгреЗ рдЦрд╛рдиреНрдпрд╛рдд x рдореЛрдард╛ рдЖрд╣реЗ, рддреНрдпрд╛рдореБрд│реЗ рдХреЛрдгреАрдЪ рджреБрд╕рд▒реНрдпрд╛рдЪреЗ рдкрд╛рд╣рд┐рд▓реЗ рдирд╛рд╣реА.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

Kafka рдлрдХреНрдд рдПрдХрд╛ partition рдЪреНрдпрд╛ рдЖрддрдЪ рдХреНрд░рдо рдареЗрд╡рддреЛ. рдПрдХрд╛ topic рдордзреНрдпреЗ рдЕрдиреЗрдХ partitions рдЕрд╕рддрд╛рдд, рдЖрдгрд┐ consumers рддреЗ рд╕рдорд╛рдВрддрд░ рд╡рд╛рдЪрддрд╛рдд. рдПрдХрд╛рдЪ key рдЪреЗ messages рдПрдХрд╛рдЪ partition рдордзреНрдпреЗ рдЬрд╛рддрд╛рдд, рддреНрдпрд╛рдореБрд│реЗ рддреЗ рдХреНрд░рдорд╛рдиреЗ рд░рд╛рд╣рддрд╛рдд; рд╡реЗрдЧрд╡реЗрдЧрд│реНрдпрд╛ keys рдЪреНрдпрд╛ messages рдордзреНрдпреЗ рдХреЛрдгрддрд╛рд╣реА рдХреНрд░рдо рдирд╕рддреЛ. On a real account тАФ рдПрдХрд╛ рд╡рд░реНрдЧрд╛рдЪреЗ timetable рдмрджрд▓ рд╡рд░реНрдЧрд╛рд▓рд╛ key рдореНрд╣рдгреВрди рдкрд╛рдард╡рд╛:

kafka-console-producer.sh --bootstrap-server localhost:9092 --topic timetable \
    --property parse.key=true --property key.separator=:
# then type lines such as:
# class-3A:exam moved to Tuesday
# class-3A:exam room is 12

рджреЛрдиреНрд╣реА class-3A рдУрд│реА рдПрдХрд╛рдЪ partition рдордзреНрдпреЗ, рддреНрдпрд╛рдЪ рдХреНрд░рдорд╛рдиреЗ рдЬрд╛рддрд╛рдд. class-4B рдЪреА рдУрд│ рддреНрдпрд╛рдВрдЪреНрдпрд╛ рдЖрдзреА рдХрд┐рдВрд╡рд╛ рдирдВрддрд░ рд╡рд╛рдЪрд▓реА рдЬрд╛рдК рд╢рдХрддреЗ.

Dynamo-style stores тАФ рдореВрд│ Amazon Dynamo paper (2007) vector clocks рд╡рд╛рдкрд░рдд рдЕрд╕реЗ рдЖрдгрд┐ рд╕рдЧрд│реНрдпрд╛ concurrent versions merge рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА application рд▓рд╛ рдкрд░рдд рджреЗрдд рдЕрд╕реЗ (shopping cart рджреЛрдиреНрд╣реА versions рдордзрд▓реА рдкреНрд░рддреНрдпреЗрдХ item рдареЗрд╡рдд рдЕрд╕реЗ). allow_mult рдЪрд╛рд▓реВ рдЕрд╕реЗрд▓ рддрд░ Riak concurrent writes siblings рдореНрд╣рдгреВрди рд╕рд╛рдард╡рддреЗ, dotted version vectors рдиреЗ track рдХрд░реВрди. рдЗрддрд░ рдЕрдиреЗрдХ systems (Cassandra, DynamoDB global tables) рддреНрдпрд╛рдРрд╡рдЬреА time stamp рдиреБрд╕рд╛рд░ last-writer-wins рд╡рд╛рдкрд░рддрд╛рдд тАФ рд╕реЛрдкреЗ, рдЖрдгрд┐ рддреЗ рджреЛрди concurrent writes рдкреИрдХреА рдПрдХ рдЯрд╛рдХреВрди рджреЗрддреЗ.

CRDTs (conflict-free replicated data types) тАФ рдЖрдкреЛрдЖрдк merge рд╣реЛрдгрд╛рд░реЗ counters, sets рдЖрдгрд┐ text types; Redis Enterprise active-active databases рдордзреНрдпреЗ рдЖрдгрд┐ collaborative editors рдордзреНрдпреЗ (Automerge, Yjs) рд╡рд╛рдкрд░рд▓реЗ рдЬрд╛рддрд╛рдд.

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рджреЛрди рдард┐рдХрд╛рдгреА рд▓рд┐рд╣рд┐рддрд╛ рдпреЗрдгрд╛рд▒реНрдпрд╛ data рдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рддреБрдХрдбреНрдпрд╛рд╕рд╛рдареА рдЖрдзреАрдЪ рдард░рд╡рд╛: рдХреЛрдгрддреА key рддреНрдпрд╛рдЪреЗ рдмрджрд▓ рдХреНрд░рдорд╛рдиреЗ рдареЗрд╡рддреЗ, рдЖрдгрд┐ рджреЛрди рдмрджрд▓ concurrent рдЕрд╕рддреАрд▓ рддрд░ рдХрд╛рдп рд╣реЛрддреЗ тАФ рджреЛрдиреНрд╣реА рдареЗрд╡рд╛рдпрдЪреЗ, merge рдХрд░рд╛рдпрдЪреЗ, рдХреА рдЬрд╛рдгреВрдирдмреБрдЬреВрди рдПрдХ рдЯрд╛рдХрд╛рдпрдЪрд╛.

тПня╕П рдкреБрдвреЗ

рдЖрддреНрддрд╛рдкрд░реНрдпрдВрдд рдЧрдкреНрдк рд╢рд╛рдЦрд╛ рд╣рд│реВ рдЕрд╕реВ рд╢рдХрддреЗ рдХрд┐рдВрд╡рд╛ рдмрдВрдж рдкрдбрд▓реЗрд▓реА. рддреБрдореНрд╣реА рдард░рд╡рддрд╛ рдХрд╕реЗ? Heartbeats рдЖрдгрд┐ timeouts тАФ рдЖрдгрд┐ рддреЛ рдирд┐рд░реНрдгрдп рдХрдзреАрдЪ рдЦрд╛рддреНрд░реАрдЪрд╛ рдХрд╛ рдирд╕рддреЛ.

git checkout lesson-04-failure-detection

ЁЯФА Lesson 03 тАФ Ordering & causality: before, after, or at the same time

ЁЯУН You are here: Lesson 03 of 12 ┬╖ Previous: lesson-02-clocks ┬╖ Next: lesson-04-failure-detection


ЁЯУж What's in this branch

Lessons 01тАУ02, plus vector clocks: one counter per branch, carried on every note. With them, two events are either before, after, the same, or concurrent тАФ and "concurrent" means a real conflict, not a delay. ordering() in dist/demo.py and VectorClock + compare() in dist/sim.py.

ЁЯзТ Explain like I'm 5

Each branch now keeps a small card with four boxes: Pune, Nashik, Nagpur, Kolhapur. ЁЯЧВя╕П Each box counts "how many things from that branch I have seen".

Now compare two cards. If every box on card A is less than or equal to card B, then A happened before B тАФ B's writer had seen A.

But Dipika in Nagpur wrote something without reading any note. Her card says "Nagpur 1" and zero everywhere else. Aishwarya's card says "Pune 1, Nashik 1, Nagpur 0". Each card has a box that is bigger than the other's. Neither saw the other. They are concurrent тАФ two people changed the same thing at the same time, and someone must decide what to keep.

ЁЯЧ║я╕П Diagram

flowchart LR
    e1["e1 at Pune<br/>pune 1 ┬╖ nashik 0 ┬╖ nagpur 0"]
    e2["e2 at Nashik, after reading e1<br/>pune 1 ┬╖ nashik 1 ┬╖ nagpur 0"]
    e3["e3 at Nagpur, saw nobody<br/>pune 0 ┬╖ nashik 0 ┬╖ nagpur 1"]
    e1 -->|"note: e1 before e2"| e2
    c["тЪб e2 vs e3: concurrent<br/>a real conflict to resolve"]
    e2 --- c
    e3 --- c

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/distributed-systems/lesson-diagrams.html#l03

тЭУ What

ЁЯдФ Why

Because "which write came last?" has no answer for concurrent writes. A system that picks one by time stamp silently loses the other. A system with vector clocks can see the difference between "Aishwarya's change replaced Katrina's" (before тЖТ keep the newer) and "Aishwarya and Dipika both changed it without knowing" (concurrent тЖТ keep both, merge or ask). Seeing the conflict is the first step to not losing data.

ЁЯФз How (in this repo)

VectorClock(me, nodes) in dist/sim.py holds a dict with one counter per branch. tick() adds 1 to its own entry. recv(other) takes the maximum of each entry, then ticks. compare(a, b) returns 'same', 'before', 'after' or 'concurrent' by checking a[k] <= b[k] and a[k] >= b[k] for every key.

ЁЯзк Try it

python3 dist/demo.py ordering
python3 - <<'EOF'
import sys; sys.path.insert(0, "dist"); from sim import VectorClock, compare
B = ["pune", "nashik", "nagpur", "kolhapur"]
vp, vn, vg = VectorClock("pune", B), VectorClock("nashik", B), VectorClock("nagpur", B)
e1 = vp.tick(); e2 = vn.recv(e1); e3 = vg.recv(e2)     # this time Nagpur reads Nashik's note first
print("e3 =", e3)
print("e1 vs e3:", compare(e1, e3), "┬╖ e2 vs e3:", compare(e2, e3), "┬╖ e3 vs e1:", compare(e3, e1))
x = vp.tick(); y = vg.tick()                            # both write again without talking
print("x =", x); print("y =", y); print("x vs y:", compare(x, y))
EOF

тЬЕ Verify тАФ what you should see

ordering prints:

тФАтФА vector clocks: e1 at Pune {'pune': 1, 'nashik': 0, 'nagpur': 0, 'kolhapur': 0}
   e2 at Nashik after reading e1 {'pune': 1, 'nashik': 1, 'nagpur': 0, 'kolhapur': 0}
   e3 at Nagpur, unaware of both {'pune': 0, 'nashik': 0, 'nagpur': 1, 'kolhapur': 0}
   e1 vs e2: before
   e2 vs e3: concurrent
   e1 vs e3: concurrent

Your snippet prints:

e3 = {'pune': 1, 'nashik': 1, 'nagpur': 1, 'kolhapur': 0}
e1 vs e3: before ┬╖ e2 vs e3: before ┬╖ e3 vs e1: after
x = {'pune': 2, 'nashik': 0, 'nagpur': 0, 'kolhapur': 0}
y = {'pune': 1, 'nashik': 1, 'nagpur': 2, 'kolhapur': 0}
x vs y: concurrent

ЁЯПБ What you just proved

The same Nagpur write is "concurrent" in the demo and "after" in your snippet. The only difference: in your snippet Nagpur read the note first. Causality is about what a writer knew, not about when the clock said it wrote. And x vs y is concurrent even though y has bigger numbers in most boxes тАФ x is bigger in the Pune box, so neither saw the other.

тЪая╕П Common mistakes

ЁЯПн In production

Kafka keeps order only inside one partition. A topic has many partitions, and consumers read them in parallel. Messages with the same key go to the same partition, so they stay in order; messages with different keys have no order between them. On a real account тАФ send the timetable changes for one class with the class as the key:

kafka-console-producer.sh --bootstrap-server localhost:9092 --topic timetable \
    --property parse.key=true --property key.separator=:
# then type lines such as:
# class-3A:exam moved to Tuesday
# class-3A:exam room is 12

Both class-3A lines land in one partition, in that order. A class-4B line may be read before or after them.

Dynamo-style stores тАФ the original Amazon Dynamo paper (2007) used vector clocks and returned all concurrent versions to the application to merge (a shopping cart kept every item from both versions). Riak stores concurrent writes as siblings, tracked with dotted version vectors, when allow_mult is on. Many other systems (Cassandra, DynamoDB global tables) use last-writer-wins by time stamp instead тАФ simple, and it drops one of two concurrent writes.

CRDTs (conflict-free replicated data types) тАФ counters, sets and text types that merge automatically; used in Redis Enterprise active-active databases and in collaborative editors (Automerge, Yjs).

ЁЯПн Why this matters in production: for each piece of data that two places can write, decide in advance: which key keeps its changes in order, and what happens when two changes are concurrent тАФ keep both, merge, or knowingly drop one.

тПня╕П Next

So far a silent branch might be slow or dead. How do you decide? Heartbeats and timeouts тАФ and why the decision is never certain.

git checkout lesson-04-failure-detection
тЖР PreviousclocksNext тЖТfailure detection

This page is the lesson's README from the lesson-03-ordering branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.