ЁЯФП рдзрдбрд╛ 10 тАФ Locks, leases & fencing: рд╕рдВрдкрдгрд╛рд░реЗ рдХреБрд▓реВрдк
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 10 ┬╖ рдорд╛рдЧреЗ: lesson-09-raft ┬╖ рдкреБрдвреЗ: lesson-11-exactly-once
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ09, рдЖрдгрд┐ distributed locks: machines рдкрд▓реАрдХрдбрдЪреЗ lock lease рдХрд╛ рдЕрд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
(рддреЗ рд╕рдВрдкрддреЗ), holder рдерд╛рдВрдмрд▓рд╛ рддрд░ рдлрдХреНрдд lease рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд╛ рдирд╛рд╣реА, рдЖрдгрд┐ рддреНрдпрд╛рд╡рд░рдЪрд╛
рдЙрдкрд╛рдп тАФ storage рддрдкрд╛рд╕рддреЗ рддреЛ fencing token. рд╣реЗ Martin Kleppmann рдпрд╛рдВрдЪреЗ
рд╕реБрдкреНрд░рд╕рд┐рджреНрдз рдЙрджрд╛рд╣рд░рдг рдЖрд╣реЗ. dist/demo.py рдордзреАрд▓ locks() рдЖрдгрд┐ dist/sim.py рдордзреАрд▓ LockService +
Storage.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдПрдХрд╛ рд╡реЗрд│реА рдлрдХреНрдд рдПрдХрдЪ рд╡реНрдпрдХреНрддреА timetable рдмрджрд▓реВ рд╢рдХрддреЗ. рдореНрд╣рдгреВрди рдореБрдЦреНрдп office рдордзреНрдпреЗ рдПрдХ рдХрд┐рд▓реНрд▓реА ЁЯФС рдЕрд╕рддреЗ.
рдкрдг рдХрддрд░рд┐рдирд╛рдиреЗ рдХрд┐рд▓реНрд▓реА рдШреЗрддрд▓реА рдЖрдгрд┐ рдордЧ рддреА рдЖрдард╡рдбрд╛рднрд░ рдЭреЛрдкреВрди рдЧреЗрд▓реА рддрд░? рдХреЛрдгреАрдЪ timetable рдмрджрд▓реВ рд╢рдХрдгрд╛рд░ рдирд╛рд╣реА. рдореНрд╣рдгреВрди рдХрд┐рд▓реНрд▓реА рдореНрд╣рдгрдЬреЗ рдПрдХ lease: рддреА 1 second рдЪрд╛рд▓рддреЗ, рдордЧ рддреА рддрд┐рдЪреА рдорд╛рдирд▓реА рдЬрд╛рдд рдирд╛рд╣реА. ЁЯХР
рдХрддрд░рд┐рдирд╛ рдХрд┐рд▓реНрд▓реА рдШреЗрддреЗ. рдореБрдЦреНрдп office рддреНрдпрд╛рд╡рд░ рдПрдХ рдХреНрд░рдорд╛рдВрдХ рд▓рд┐рд╣рд┐рддреЗ: token 1. рдордЧ рдХрддрд░рд┐рдирд╛ 2 seconds рд╕рд╛рдареА рдЧреЛрдарддреЗ (рддрд┐рдЪрд╛ computer memory рд╕рд╛рдл рдХрд░рдгреНрдпрд╛рдд рд╡реНрдпрд╕реНрдд рдЖрд╣реЗ тАФ рдПрдХ рд▓рд╛рдВрдм рдерд╛рдВрдмрд╛). рдЖрдкрдг рдЧреЛрдард▓реЛ рд╣реЛрддреЛ рд╣реЗ рддрд┐рд▓рд╛ рдХрд│рдд рдирд╛рд╣реА.
1.5 seconds рд▓рд╛ рддрд┐рдЪреА lease рд╕рдВрдкрд▓реЗрд▓реА рдЕрд╕рддреЗ. рдРрд╢реНрд╡рд░реНрдпрд╛ рдХрд┐рд▓реНрд▓реА рдШреЗрддреЗ: token 2. рддреА timetable v2 рд▓рд┐рд╣рд┐рддреЗ.
2.0 seconds рд▓рд╛ рдХрддрд░рд┐рдирд╛ рдЬрд╛рдЧреА рд╣реЛрддреЗ. рддрд┐рдЪреНрдпрд╛ рдордирд╛рдд рдХрд╛рд╣реАрдЪ рд╡реЗрд│ рдЧреЗрд▓реЗрд▓рд╛ рдирд╛рд╣реА. рддрд┐рд▓рд╛ рд╡рд╛рдЯрддреЗ рдХрд┐рд▓реНрд▓реА рдЕрдЬреВрди рддрд┐рдЪреНрдпрд╛рдХрдбреЗрдЪ рдЖрд╣реЗ, рдЖрдгрд┐ рддреА timetable v1 рд▓рд┐рд╣рд┐рддреЗ. ЁЯШм
Timetable рд▓рд╛ рдХреЛрдг рд╡рд╛рдЪрд╡рддреЗ? рдХрдкрд╛рдЯ ЁЯЧДя╕П рддреНрдпрд╛рдиреЗ рдкрд╛рд╣рд┐рд▓реЗрд▓рд╛ рд╕рд░реНрд╡рд╛рдд рдореЛрдард╛ token рд▓рдХреНрд╖рд╛рдд рдареЗрд╡рддреЗ. рддреНрдпрд╛рдиреЗ 2 рдкрд╛рд╣рд┐рд▓рд╛ рдЖрд╣реЗ. рдХрддрд░рд┐рдирд╛ 1 рджрд╛рдЦрд╡рддреЗ. рдХрдкрд╛рдЯ рдореНрд╣рдгрддреЗ: "рдирд╛рд╣реА. рддреВ рдЦреВрдк рдЬреБрдиреА рдЖрд╣реЗрд╕."
ЁЯЧ║я╕П рдЖрдХреГрддреА
sequenceDiagram
participant K as Katrina
participant L as Lock service
participant A as Aishwarya
participant S as Storage
K->>L: acquire at 0 s
L-->>K: lease 1 s, token 1
Note over K: long pause, 2 s
A->>L: acquire at 1.5 s, lease expired
L-->>A: token 2
A->>S: write v2 with token 2
S-->>A: wrote, highest token is 2
K->>S: write v1 with token 1 at 2.0 s
S-->>K: refused, already saw 2
ЁЯЧ║я╕П рд░реЗрдЦрд╛рдЯрд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/distributed-systems/lesson-diagrams.html#l10
тЭУ рдХрд╛рдп
- Distributed lock тАФ machines рдкрд▓реАрдХрдбреЗ "рдПрдХрд╛ рд╡реЗрд│реА рдлрдХреНрдд рдПрдХрдЪ node X рдХрд░реВ рд╢рдХрддреЗ": рдПрдХ leader, рдПрдХрд╛ file рдЪрд╛ рдПрдХ writer, рдПрдХ job runner.
- Lease тАФ рд╡реЗрд│реЗрдЪреА рдорд░реНрдпрд╛рджрд╛ рдЕрд╕рд▓реЗрд▓реЗ lock. Holder crash рдЭрд╛рд▓рд╛ рддрд░ lease рд╕рдВрдкрддреЗ рдЖрдгрд┐ рджреБрд╕рд░реЗ рдХреЛрдгреА рддреА рдШреЗрдК рд╢рдХрддреЗ. рд╕рдВрдкрдгреНрдпрд╛рдЪреА рд╕реЛрдп рдирд╕реЗрд▓ рддрд░ crash рдЭрд╛рд▓реЗрд▓рд╛ holder рд╕рдЧрд│реНрдпрд╛рдВрдирд╛ рдХрд╛рдпрдордЪреЗ рдЕрдбрд╡рддреЛ.
- Leases рдЪреА рдЕрдбрдЪрдг тАФ рддреНрдпрд╛рдЪрд╛ write рдкреЛрд╣реЛрдЪрддреЛ рддреНрдпрд╛ рдХреНрд╖рдгреА рдЖрдкрд▓реА lease рдЕрдЬреВрди рд╡реИрдз рдЖрд╣реЗ рдпрд╛рдЪреА holder рд▓рд╛ рдЦрд╛рддреНрд░реА рдЕрд╕реВ рд╢рдХрдд рдирд╛рд╣реА. "рдореА рдорд╛рдЭреА lease рддрдкрд╛рд╕рд▓реА" рдЖрдгрд┐ "рдорд╛рдЭрд╛ write рдкреЛрд╣реЛрдЪрд▓рд╛" рдпрд╛рдВрдЪреНрдпрд╛ рджрд░рдореНрдпрд╛рди process pause (garbage collection, virtual machine suspend рд╣реЛрдгреЗ, operating system рдиреЗ memory disk рд╡рд░ swap рдХрд░рдгреЗ) рдХрд┐рдВрд╡рд╛ рд╣рд│реВ network рдпреЗрдК рд╢рдХрддреЛ. Seconds рдЪреЗ рдерд╛рдВрдмреЗ рдШрдбрддрд╛рдд.
- рдШрдбреНрдпрд╛рд│рд╛рдВрдмрджреНрджрд▓рдЪреА рдЧреГрд╣реАрддрдХреЗ тАФ lease рдШрдбреНрдпрд╛рд│рд╛рдВрдиреА рдореЛрдЬрд▓реА рдЬрд╛рддреЗ: lock service рдЪреЗ рдШрдбреНрдпрд╛рд│ рд╕рдВрдкрдгреНрдпрд╛рдЪреА рд╡реЗрд│ рдард░рд╡рддреЗ, рдЖрдгрд┐ holder рдХрд┐рддреА рд╡реЗрд│ рдЙрд░рд▓рд╛ рдпрд╛рдЪрд╛ рдЕрдВрджрд╛рдЬ рдЖрдкрд▓реНрдпрд╛ рдШрдбреНрдпрд╛рд│рд╛рдиреЗ рд▓рд╛рд╡рддреЛ. рдПрдЦрд╛рджреЗ рдШрдбреНрдпрд╛рд│ рдкреБрдвреЗ рдкрд│рд╛рд▓реЗ рдХрд┐рдВрд╡рд╛ рдЙрдбреА рдорд╛рд░рд▓реА (рдзрдбрд╛ 02), рддрд░ "рд╕рдВрдкрд▓реЗ" рдпрд╛рдмрджреНрджрд▓ рддреНрдпрд╛рдВрдЪреНрдпрд╛ рдХрд▓реНрдкрдирд╛ рд╡реЗрдЧрд│реНрдпрд╛ рд╣реЛрддрд╛рдд. Leases рдлрдХреНрдд рдорд░реНрдпрд╛рджрд┐рдд pauses, network delays рдЖрдгрд┐ clock drift рдЕрд╕рддрд╛рдирд╛рдЪ рд╕реБрд░рдХреНрд╖рд┐рдд рдЕрд╕рддрд╛рдд тАФ рд╣реА рдЧреГрд╣реАрддрдХреЗ рдЖрд╣реЗрдд, рддрдереНрдпреЗ рдирд╡реНрд╣реЗрдд.
- Fencing token тАФ lock service рдкреНрд░рддреНрдпреЗрдХ рд╡реЗрд│реА lock рджреЗрддрд╛рдирд╛ рджреЗрддреЗ рддреЛ рдХреНрд░рдорд╛рдВрдХ; рддреЛ рдлрдХреНрдд рд╡рд╛рдврдд рдЬрд╛рддреЛ (1, 2, 3 тАж). Holder рддреЛ рдкреНрд░рддреНрдпреЗрдХ write рд╕реЛрдмрдд рдкрд╛рдард╡рддреЛ. Storage рдЖрдкрдг рд╕реНрд╡реАрдХрд╛рд░рд▓реЗрд▓рд╛ рд╕рд░реНрд╡рд╛рдд рдореЛрдард╛ token рд▓рдХреНрд╖рд╛рдд рдареЗрд╡рддреЗ рдЖрдгрд┐ рддреНрдпрд╛рд╣реВрди рд▓рд╣рд╛рди token рдЕрд╕рд▓реЗрд▓рд╛ рдХреЛрдгрддрд╛рд╣реА write рдирд╛рдХрд╛рд░рддреЗ. рдЖрддрд╛ рдЬреБрдирд╛ holder рдЙрд╢рд┐рд░рд╛ рдЬрд╛рдЧрд╛ рдЭрд╛рд▓рд╛ рддрд░реА рдХрд╛рд╣реА рдиреБрдХрд╕рд╛рди рдХрд░реВ рд╢рдХрдд рдирд╛рд╣реА.
- Kleppmann рдпрд╛рдВрдЪреЗ рдЙрджрд╛рд╣рд░рдг ("How to do distributed locking", 2016, рдЖрдгрд┐ Designing Data-Intensive Applications рдпрд╛ рдкреБрд╕реНрддрдХрд╛рддреВрди): client 1 lease рдШреЗрддреЛ, garbage collection рд╕рд╛рдареА рдерд╛рдВрдмрддреЛ, lease рд╕рдВрдкрддреЗ, client 2 lease рдШреЗрддреЛ рдЖрдгрд┐ token 34 рд╕рд╣ рд▓рд┐рд╣рд┐рддреЛ, рдордЧ client 1 рдЬрд╛рдЧрд╛ рд╣реЛрддреЛ рдЖрдгрд┐ token 33 рд╕рд╣ рд▓рд┐рд╣рд┐рддреЛ тАФ storage 33 рдирд╛рдХрд╛рд░рддреЗ. рдЗрдерд▓рд╛ рдзрдбрд╛ tokens 1 рдЖрдгрд┐ 2 рд╡рд╛рдкрд░рддреЛ.
- рдореБрдЦреНрдп рдореБрджреНрджрд╛ тАФ рд╣реА рддрдкрд╛рд╕рдгреА storage рд╡рд░рдЪ (рдЬреНрдпрд╛рдЪреЗ рд╕рдВрд░рдХреНрд╖рдг рдХрд░рд╛рдпрдЪреЗ рддреНрдпрд╛ рдЧреЛрд╖реНрдЯреАрд╡рд░) рд╡реНрд╣рд╛рдпрд▓рд╛ рд╣рд╡реА. Holder рд╕реНрд╡рддрдГрд▓рд╛ рддрдкрд╛рд╕реВ рд╢рдХрдд рдирд╛рд╣реА, рдХрд╛рд░рдг рдерд╛рдВрдмрд▓реЗрд▓реНрдпрд╛ process рд▓рд╛ рдЖрдкрдг рдерд╛рдВрдмрд▓реЛ рд╣реЛрддреЛ рд╣реЗ рдХрд│рдд рдирд╛рд╣реА.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг locks рд╕рд╣рд╕рд╛ рдмрд░реЛрдмрд░рдкрдгрд╛рд╕рд╛рдареА рд╡рд╛рдкрд░рд▓реЗ рдЬрд╛рддрд╛рдд: "рдХрдзреАрдЪ рджреЛрди writers рдирдХреЛрдд". рдЬреЗ lock рдлрдХреНрдд рдмрд╣реБрддреЗрдХ рд╡реЗрд│рд╛ exclusive рдЕрд╕рддреЗ рддреЗ рдХрд╛рд░реНрдпрдХреНрд╖рдорддреЗрд╕рд╛рдареА рдареАрдХ рдЖрд╣реЗ (рддреЗрдЪ рдХрд╛рдо рджреЛрдирджрд╛ рдЯрд╛рд│рдгреЗ) рдЖрдгрд┐ рдмрд░реЛрдмрд░рдкрдгрд╛рд╕рд╛рдареА рдзреЛрдХрд╛рджрд╛рдпрдХ рдЖрд╣реЗ (data рдмрд┐рдШрдбрддреЛ). Fencing token "рдмрд╣реБрддреЗрдХ рд╡реЗрд│рд╛" рдЪреЗ "рдиреЗрд╣рдореА" рдХрд░рддреЛ, рдЬреЛрдкрд░реНрдпрдВрдд storage рддреЛ рддрдкрд╛рд╕рддреЗ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
dist/sim.py рдордзреАрд▓ LockService(lease_ms) acquire(who, now) рдордзреНрдпреЗ lock
рддреЗрд╡реНрд╣рд╛рдЪ рджреЗрддреЗ рдЬреЗрд╡реНрд╣рд╛ рддреЗ рдХреЛрдгрд╛рдХрдбреЗрдЪ рдирд╕рддреЗ рдХрд┐рдВрд╡рд╛ lease рд╕рдВрдкрд▓реЗрд▓реА рдЕрд╕рддреЗ (now >= expires);
рдкреНрд░рддреНрдпреЗрдХ рд╡реЗрд│реА lock рджреЗрддрд╛рдирд╛ рддреЗ token рдордзреНрдпреЗ 1 рдорд┐рд│рд╡рддреЗ рдЖрдгрд┐ рддреЛ рдкрд░рдд рдХрд░рддреЗ (рдХрд┐рдВрд╡рд╛ lock рдЖрдзреАрдЪ рдШреЗрддрд▓реЗрд▓реЗ рдЕрд╕реЗрд▓ рддрд░ None).
Storage.write(token, value, fencing=True) рддреНрдпрд╛рдиреЗ рдкрд╛рд╣рд┐рд▓реЗрд▓реНрдпрд╛ рд╕рд░реНрд╡рд╛рдд рдореЛрдареНрдпрд╛ token рдкреЗрдХреНрд╖рд╛ рд▓рд╣рд╛рди token
рдирд╛рдХрд╛рд░рддреЗ; fencing=False рдЕрд╕реЗрд▓ рддрд░ рддреЗ рдХрд╛рд╣реАрд╣реА рд╕реНрд╡реАрдХрд╛рд░рддреЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 dist/demo.py locks
python3 - <<'EOF'
import sys; sys.path.insert(0, "dist"); from sim import LockService, Storage
for lease in (1000, 3000):
ls, st = LockService(lease_ms=lease), Storage()
t1 = ls.acquire("katrina", 0)
t2 = ls.acquire("aishwarya", 1500)
print(f"lease {lease} ms: Katrina token {t1}, Aishwarya at 1.5 s тЖТ {t2}")
ls, st = LockService(1000), Storage()
t1 = ls.acquire("katrina", 0); t2 = ls.acquire("aishwarya", 1500); t3 = ls.acquire("dipika", 2600)
print("tokens:", t1, t2, t3)
for tok, who in ((t3, "dipika"), (t2, "aishwarya"), (t1, "katrina")):
print(f" {who} writes with token {tok} тЖТ {st.write(tok, who + ' timetable')}")
print(" final value:", st.value)
EOF
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
locks рд╣реЗ print рдХрд░рддреЗ:
тФАтФА Katrina takes the timetable lock, lease 1 s, fencing token 1 тАФ then pauses for 2 s (a long GC)
at 1.5 s the lease has expired; Aishwarya takes the lock тЖТ token 2 and writes тЖТ wrote 'timetable v2'
Katrina wakes at 2.0 s, still thinks she holds the lock, writes with token 1 тЖТ refused token 1 (already saw 2)
without fencing tokens тЖТ wrote 'timetable v1' тАФ newer work silently overwritten
a lease alone is not enough; the storage must check the token
рддреБрдордЪрд╛ snippet рд╣реЗ print рдХрд░рддреЛ:
lease 1000 ms: Katrina token 1, Aishwarya at 1.5 s тЖТ 2
lease 3000 ms: Katrina token 1, Aishwarya at 1.5 s тЖТ None
tokens: 1 2 3
dipika writes with token 3 тЖТ wrote 'dipika timetable'
aishwarya writes with token 2 тЖТ refused token 2 (already saw 3)
katrina writes with token 1 тЖТ refused token 1 (already saw 3)
final value: dipika timetable
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рд▓рд╛рдВрдм lease (3 s) рдЕрдбрдЪрдг рдлрдХреНрдд рдкреБрдвреЗ рдврдХрд▓рддреЗ: рдРрд╢реНрд╡рд░реНрдпрд╛рд▓рд╛ рдерд╛рдВрдмрд╛рд╡реЗ рд▓рд╛рдЧрддреЗ, рдЖрдгрд┐ 4-second рдЪрд╛ pause рддреА рдкреБрдиреНрд╣рд╛ рдореЛрдбреЗрд▓. рдкреНрд░рддреНрдпреЗрдХ pause рд╕рд╛рдареА рдкреБрд░реЗрд╢реА рд▓рд╛рдВрдм рдЕрд╢реА рдХреЛрдгрддреАрд╣реА lease рдирд╛рд╣реА. рддреАрди holders рд╕рд░реНрд╡рд╛рдд рд╡рд╛рдИрдЯ рдХреНрд░рдорд╛рдиреЗ рдЙрд╢рд┐рд░рд╛ рдЖрд▓реЗ рддрд░реА storage рдиреЗ рдлрдХреНрдд рд╕рд░реНрд╡рд╛рдд рдирд╡реНрдпрд╛ holder рдЪреЗрдЪ рдХрд╛рдо рдареЗрд╡рд▓реЗ тАФ token рдард░рд╡рддреЛ, рдкреЛрд╣реЛрдЪрдгреНрдпрд╛рдЪрд╛ рдХреНрд░рдо рдирд╡реНрд╣реЗ рдЖрдгрд┐ рдХреЛрдгрд╛рдЪреЗ рдШрдбреНрдпрд╛рд│рд╣реА рдирд╡реНрд╣реЗ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- рдХрдзреАрдЪ overwrite рд╣реЛрдК рдирдпреЗ рдЕрд╢рд╛ data рдЪреЗ рд╕рдВрд░рдХреНрд╖рдг fencing token рдирд╕рд▓реЗрд▓реНрдпрд╛ lease рдиреЗ рдХрд░рдгреЗ
- рд▓рд┐рд╣рд┐рдгреНрдпрд╛рдЪреНрдпрд╛ рдЕрдЧрджреА рдЖрдзреА client рдордзреНрдпреЗ lease рддрдкрд╛рд╕рдгреЗ ("рддреЗ рдЕрдЬреВрди рдорд╛рдЭреНрдпрд╛рдХрдбреЗ рдЖрд╣реЗ") тАФ pause рддрдкрд╛рд╕рдгреАрдирдВрддрд░ рд▓рдЧреЗрдЪ рдпреЗрдК рд╢рдХрддреЛ
- token рдХрдбреЗ рджреБрд░реНрд▓рдХреНрд╖ рдХрд░рдгрд╛рд░реЗ storage, рддреНрдпрд╛рдореБрд│реЗ token рдХрд╢рд╛рдЪреЗрдЪ рд╕рдВрд░рдХреНрд╖рдг рдХрд░рдд рдирд╛рд╣реА
- рд╕рдВрдкрдгреНрдпрд╛рдЪреА рд╕реЛрдп рдирд╕рд▓реЗрд▓реЗ lock тАФ рдПрдХ crash рдЭрд╛рд▓реЗрд▓рд╛ holder рд╕рдЧрд│реНрдпрд╛рдВрдирд╛ рдЕрдбрд╡рддреЛ
- рдЬрд┐рдереЗ idempotent write (рдзрдбрд╛ 11) рдХрд┐рдВрд╡рд╛ conditional update рд▓рд╛ lock рдЪреА рдЧрд░рдЬрдЪ рдирд╕рддреА рддрд┐рдереЗ lock рд╡рд╛рдкрд░рдгреЗ
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
Redis locks тАФ single-instance pattern рдореНрд╣рдгрдЬреЗ NX (рдлрдХреНрдд рдирд╕реЗрд▓ рддрд░) рдЖрдгрд┐
expiry рд╕рд╣ SET. On a real account:
redis-cli SET lock:timetable 9f2c41d7 NX PX 30000 # OK = you hold it for 30 s; (nil) = someone else does
Value рдЕрдЬреВрди рддреБрдордЪреАрдЪ рдЕрд╕реЗрд▓ рддрд░рдЪ рддреЗ рд╕реЛрдбрд╛ (рдПрдХ рдЫреЛрдЯреА Lua script рддреБрд▓рдирд╛ рдХрд░рддреЗ, рдордЧ delete рдХрд░рддреЗ). Redlock рд╣реЗрдЪ рдЕрдиреЗрдХ рд╕реНрд╡рддрдВрддреНрд░ Redis servers рд╡рд░ рдкреБрдиреНрд╣рд╛ рдХрд░рддреЗ рдЖрдгрд┐ рдмрд╣реБрдордд рдореЛрдЬрддреЗ. Kleppmann рдпрд╛рдВрдЪреА рдЯреАрдХрд╛: Redlock рдЪреА рд╕реБрд░рдХреНрд╖рд┐рддрддрд╛ timing рдЧреГрд╣реАрддрдХрд╛рдВрд╡рд░ (рдорд░реНрдпрд╛рджрд┐рдд pauses, рдорд░реНрдпрд╛рджрд┐рдд clock drift) рдЕрд╡рд▓рдВрдмреВрди рдЖрд╣реЗ, рдЖрдгрд┐ рддреЗ рдХреЛрдгрддрд╛рд╣реА fencing token рддрдпрд╛рд░ рдХрд░рдд рдирд╛рд╣реА. Redis locks рдХрд╛рд░реНрдпрдХреНрд╖рдорддреЗрд╕рд╛рдареА рд╡рд╛рдкрд░рд╛ (duplicate рдХрд╛рдо рдЯрд╛рд│рдгреЗ); рдмрд░реЛрдмрд░рдкрдгрд╛рд╕рд╛рдареА, token рджреЗрдгрд╛рд░реЗ lock рдЖрдгрд┐ рддреЛ рддрдкрд╛рд╕рдгрд╛рд░реЗ storage рд╡рд╛рдкрд░рд╛.
etcd тАФ lease рдЖрдгрд┐ lock; рдкреНрд░рддреНрдпреЗрдХ key рд▓рд╛ рдПрдХ revision рдХреНрд░рдорд╛рдВрдХ рдЕрд╕рддреЛ рдЬреЛ рд╕рдВрдкреВрд░реНрдг store рдордзреНрдпреЗ рдлрдХреНрдд рд╡рд╛рдврдд рдЬрд╛рддреЛ, рддреНрдпрд╛рдореБрд│реЗ lock key рдЪреА revision fencing token рдореНрд╣рдгреВрди рд╡рд╛рдкрд░рддрд╛ рдпреЗрддреЗ:
etcdctl lease grant 10 # lease 694d7b1c2f0e4a1b granted with TTL(10s)
etcdctl lock timetable ./edit-timetable.sh # runs the command while holding the lock
ZooKeeper тАФ рдПрдХ ephemeral sequential node рддрдпрд╛рд░ рдХрд░рд╛; рд╕рд░реНрд╡рд╛рдд рд▓рд╣рд╛рди рдХреНрд░рдорд╛рдВрдХрд╛рдХрдбреЗ lock рдЕрд╕рддреЗ,
рдЖрдгрд┐ holder рдЪреЗ session рд╕рдВрдкрд▓реНрдпрд╛рд╡рд░ рддреА node рдирд╛рд╣реАрд╢реА рд╣реЛрддреЗ. рддрд┐рдЪрд╛ sequence number (рдХрд┐рдВрд╡рд╛
transaction ID zxid) fencing token рдореНрд╣рдгреВрди рдХрд╛рдо рдХрд░рддреЛ:
zkCli.sh create -e -s /locks/timetable- katrina # Created /locks/timetable-0000000007
Kubernetes controllers Lease object рд╡рд╛рдкрд░реВрди leader рдирд┐рд╡рдбрддрд╛рдд
(coordination.k8s.io): holderIdentity, leaseDurationSeconds, renewTime.
kubectl get lease -n kube-system # kube-controller-manager, kube-scheduler тАж
Fencing рдЪреА storage рдмрд╛рдЬреВ тАФ рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде SQL рдордзреНрдпреЗ, write рдлрдХреНрдд рдирд╡реНрдпрд╛ token рд╕рд╣ рд╕реНрд╡реАрдХрд╛рд░рд╛:
UPDATE timetable SET body = $1, fence = $2
WHERE id = 'term-2' AND fence < $2; -- 0 rows updated тЖТ a stale holder; stop
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдкреНрд░рддреНрдпреЗрдХ lock рд╕рд╛рдареА рджреЛрди рдкреНрд░рд╢реНрди рд╡рд┐рдЪрд╛рд░рд╛: "holder 30 seconds рдерд╛рдВрдмрд▓рд╛ рддрд░ рдХрд╛рдп рд╣реЛрдИрд▓?" рдЖрдгрд┐ "token рдХреБрдареЗ рддрдкрд╛рд╕рд▓рд╛ рдЬрд╛рддреЛ?". рджреБрд╕рд▒реНрдпрд╛ рдкреНрд░рд╢реНрдирд╛рдЪреЗ рдЙрддреНрддрд░ "рдХреБрдареЗрдЪ рдирд╛рд╣реА" рдЕрд╕реЗрд▓, рддрд░ рддреЗ lock рдлрдХреНрдд рдХрд╛рд░реНрдпрдХреНрд╖рдорддреЗрдЪреЗ рд╕рдВрд░рдХреНрд╖рдг рдХрд░рддреЗ, рдмрд░реЛрдмрд░рдкрдгрд╛рдЪреЗ рдирд╡реНрд╣реЗ.
тПня╕П рдкреБрдвреЗ
Locks рджреЛрди writers рдирд╛ рдерд╛рдВрдмрд╡рддрд╛рдд. Retries рдПрдХ рд╡реЗрдЧрд│реАрдЪ рдЕрдбрдЪрдг рдирд┐рд░реНрдорд╛рдг рдХрд░рддрд╛рдд: рддреЛрдЪ message рджреЛрдирджрд╛ рд╣рд╛рддрд╛рд│рд▓рд╛ рдЬрд╛рдгреЗ. рдкреБрдвреЗ: exactly-once рдЪреЗ рдорд┐рдердХ.
git checkout lesson-11-exactly-once