Κατανεμημένες κλειδαριές
1) Γιατί (και πότε) χρειάζονται κατανεμημένες κλειδαριές
Το κατανεμημένο μπλοκάρισμα είναι ένας μηχανισμός που εγγυάται τον αμοιβαίο αποκλεισμό για ένα κρίσιμο τμήμα μεταξύ διαφόρων κόμβων συμπλέγματος. Τυπικά καθήκοντα:- Εκλογή ηγέτη για το έργο υποβάθρου/σκιέρ.
- Περιορισμός ενός μόνο εκτελεστή σε έναν κοινό πόρο (κίνηση αρχείων, μετανάστευση σχημάτων, στάδιο αποκλειστικής πληρωμής).
- Διαδοχική επεξεργασία του αθροίσματος (πορτοφόλι/σειρά) εάν είναι αδύνατο να επιτευχθεί ταυτότητα/παραγγελία διαφορετικά.
- Αν μπορείτε να κάνετε μια idempotent upsert, CAS (συγκρίνετε-και-set) ή ανά-κλειδί παραγγελία.
- Αν ο πόρος επιτρέπει μεταθετικές πράξεις (CRDT, μετρητές).
- Εάν το πρόβλημα επιλύεται με συναλλαγή σε ένα κατάστημα.
2) Μοντέλο και ιδιότητες απειλής
Βλάβες και επιπλοκές:- Δίκτυο: καθυστερήσεις, κατάτμηση, απώλεια πακέτων.
- Διαδικασίες: παύση GC, διακοπή του κόσμου, σύγκρουση μετά τη σύλληψη κλειδώματος.
- Χρόνος: Παρέκκλιση ρολογιού και διάρρηξη μετατόπισης TTL προσεγγίσεις.
- Κατάσχεση: Η διαδικασία «ζόμπι» μετά το δίχτυ μπορεί να νομίζει ότι εξακολουθεί να κατέχει το κάστρο.
- Ασφάλεια: μόνο ένας έγκυρος ιδιοκτήτης (ασφάλεια).
- Επιβιωσιμότητα: η κλειδαριά απελευθερώνεται όταν ο ιδιοκτήτης αποτύχει (ζωντάνια).
- Δικαιοσύνη: Δεν υπάρχει νηστεία.
- Ανεξαρτησία ρολογιού: η ορθότητα δεν εξαρτάται από το ρολόι τοίχου (ή αντισταθμίζεται από μάρκες ξιφασκίας).
3) Κύρια μοντέλα
3. 1 Μίσθωση (κλειδαριά ενοικίασης)
Η κλειδαριά εκδίδεται με TTL. Ο ιδιοκτήτης υποχρεούται να το ανανεώσει πριν από τη λήξη της (καρδιακός παλμός/κλειδαριά).
Επαγγελματίες: Συντριβή αυτοαπορρόφησης.
Κίνδυνοι: εάν ο ιδιοκτήτης είναι «κολλημένος» και συνεχίσει να εργάζεται, αλλά έχει χάσει την παράταση, μπορεί να προκύψει διπλή ιδιοκτησία.
3. 2 Σύμβολο περίφραξης
Με κάθε επιτυχή σύλληψη, εκδίδεται ένας μονότονα αυξανόμενος αριθμός. Οι καταναλωτές πόρων (βάση δεδομένων, σειρά αναμονής, αποθήκευση αρχείων) ελέγχουν τη μάρκα και απορρίπτουν τις πράξεις με τον παλιό αριθμό.
Αυτό είναι εξαιρετικά σημαντικό για τα τμήματα TTL/μίσθωσης και δικτύου - προστατεύει από τον «παλαιό» ιδιοκτήτη.
3. 3 Κλειδαριές απαρτίας (συστήματα CP)
Χρησιμοποιείται κατανεμημένη συναίνεση (Raft/Paxos; etcd/ZooKeeper/Πρόξενος), το αρχείο συνδέεται με ένα αρχείο καταγραφής συναίνεσης → δεν υπάρχει διαχωρισμός εγκεφάλου με τους περισσότερους κόμβους.
Συν: ισχυρές εγγυήσεις ασφάλειας.
Μείον: ευαισθησία στην απαρτία (όταν χάνεται, η επιβίωση είναι κουτσή).
3. 4 κλειδαριές AP (in-memory/cache + αναπαραγωγή)
Για παράδειγμα, ένα σμήνος Redis. Υψηλή διαθεσιμότητα και ταχύτητα, αλλά χωρίς ισχυρές εγγυήσεις ασφαλείας για τα χωρίσματα δικτύου. Απαιτείται ξιφασκία στο πλάι του μώλωπα.
4) Πλατφόρμες και πρότυπα
4. 1 etcd/ZooKeeper/Πρόξενος (συνιστάται για ισχυρές κλειδαριές)
Εφήμεροι κόμβοι (ZK) ή συνεδρίες/μισθώσεις (etcd): το κλειδί υπάρχει ενώ η συνεδρία είναι ζωντανή.
Ενθάρρυνση συνεδρίας. απώλεια απαρτίας → λήξει η συνεδρία → απελευθερωθεί η κλειδαριά.
Κόμβοι ακολουθίας (ZK 'EPHEMERAL _ SEQUENTIAL') για την αναμονή αναμονής → fair.
go cli, _:= clientv3. New(...)
lease, _:= cli. Grant(ctx, 10) // 10s lease sess, _:= concurrency. NewSession(cli, concurrency. WithLease(lease. ID))
m:= concurrency. NewMutex(sess, "/locks/orders/42")
if err:= m. Lock(ctx); err!= nil { / handle / }
defer m. Unlock(ctx)
4. 2 Redis (καθαρό)
Classic - 'SET key value NX PX ttl'.
Προβλήματα:- Η αντιγραφή/feilover μπορεί να επιτρέψει την ταυτόχρονη χρήση ιδιοκτητών.
- Redlock από πολλαπλές περιπτώσεις μειώνει τον κίνδυνο, αλλά δεν εξαλείφει? είναι αμφιλεγόμενο σε περιβάλλοντα με αναξιόπιστο δίκτυο.
Είναι ασφαλέστερο να χρησιμοποιείται το Redis ως ένα ταχύ επίπεδο συντονισμού, αλλά πάντα να συμπληρώνεται η ένδειξη της περίφραξης στον πόρο-στόχο.
Παράδειγμα (Lua-ξεκλείδωμα):lua
-- release only if value matches if redis. call("GET", KEYS[1]) == ARGV[1] then return redis. call("DEL", KEYS[1])
else return 0 end
4. Κλειδαριές 3 DB
Συμβουλευτικές κλειδαριές PostgreSQL: κλειδαριά εντός του συμπλέγματος Postgres (διαδικασία/συνεδρία).
Είναι καλό όταν όλα τα κρίσιμα τμήματα βρίσκονται ήδη στην ίδια βάση δεδομένων.
sql
SELECT pg_try_advisory_lock(42); -- take
SELECT pg_advisory_unlock(42); -- let go
4. 4 Κλειδαριές αρχείου/νέφους
+ κλειδαριά μεταδεδομένων αντικειμένου με συνθήκες 'If-Match' (ETag) ουσιαστικά CAS.
Κατάλληλο για εφεδρείες/μεταναστεύσεις.
5) Σχεδιασμός κλειδαριών ασφαλείας
5. 1 Ταυτότητα ιδιοκτήτη
Αποθήκευση 'owner _ i (# process # pid # start _ time node) + τυχαίο σύμβολο για επαλήθευση ξεκλειδώματος.
Το επαναλαμβανόμενο ξεκλείδωμα δεν πρέπει να αφαιρεί την κλειδαριά κάποιου άλλου.
5. 2 TTL και επέκταση
TTL <T_fail_detect (χρόνος ανίχνευσης σφαλμάτων) και p99 ≥ λειτουργίας κρίσιμης διατομής × εφεδρικό.
Ανανέωση - περιοδικά (για παράδειγμα, κάθε «TTL/3»), με προθεσμία.
5. 3 Σύμβολο ξιφασκίας σε μώλωπα
Το τμήμα που τροποποιεί τον εξωτερικό πόρο πρέπει να περάσει «ξιφασκία _ μάρκα».
Ο νεροχύτης (DB/cache/storage) αποθηκεύει τελευταία _ token 'και απορρίπτει μικρότερα:sql
UPDATE wallet
SET balance = balance +:delta, last_token =:token
WHERE id =:id AND:token > last_token;
5. Αναμονή Αναμονής και Δικαιοσύνης
Σε ZK - 'EPHEMERAL _ SEQUENTIAL' και παρατηρητές: ο πελάτης περιμένει την απελευθέρωση του πλησιέστερου προκατόχου.
In etcd - κλειδιά με αναθεώρηση/έκδοση; διαταγή «mod _ revision».
5. 5 Συμπεριφορά διαχωρισμού-εγκεφάλου
Προσέγγιση CP: χωρίς απαρτία, δεν μπορείτε να κλειδώσετε - είναι καλύτερο να σταθείτε όρθιοι παρά να σπάσετε την ασφάλεια.
Προσέγγιση AP: επιτυγχάνεται πρόοδος στα διαιρεμένα νησιά → απαιτείται ξιφασκία.
6) Εκλογές ηγετών
In etcd/ZK, ο «ηγέτης» είναι αποκλειστικό επεμερικό κλειδί. τα υπόλοιπα υπογράφονται για αλλαγές.
Ο Leader γράφει καρδιακούς παλμούς. απώλεια - επανεκλογή.
Συνοδεύει όλες τις επιχειρήσεις επικεφαλής με δείγμα περίφραξης (αριθμός εποχής/αναθεώρησης).
7) Σφάλματα και επεξεργασία τους
Ο πελάτης πήρε την κλειδαριά, αλλά συντριβή για να λειτουργήσει → τον κανόνα, κανείς δεν θα υποφέρει? Το TTL/συνεδρία θα κυκλοφορήσει.
Η κλειδαριά έληξε στη μέση της εργασίας:- Υποχρεωτικός φύλακας: εάν η επέκταση αποτύχει, διακόψτε το κρίσιμο τμήμα και αναποδογυρίστε/αντισταθμίστε.
- Όχι «τελειώστε αργότερα»: χωρίς κλειδαριά, το κρίσιμο τμήμα δεν μπορεί να συνεχιστεί.
Μια μακρά παύση (GC/stop-the-world) → η επέκταση δεν συνέβη, η άλλη πήρε το κλείδωμα. Η ροή εργασίας πρέπει να ανιχνεύει την απώλεια ιδιοκτησίας (δίαυλος φύλαξης) και την ματαίωση.
8) Dedloki, προτεραιότητες και αντιστροφή
Το Ντεντλόκι σε έναν κατανεμημένο κόσμο είναι σπάνιο (υπάρχει συνήθως ένα κάστρο), αλλά αν υπάρχουν αρκετά κάστρα, ακολουθήστε μία μόνο σειρά λήψης (παραγγελία κλειδώματος).
Αντιστροφή προτεραιότητας: Ένας ιδιοκτήτης χαμηλής προτεραιότητας κατέχει έναν πόρο ενώ εκείνοι υψηλής προτεραιότητας περιμένουν. Λύσεις: όρια TTL, πρόληψη (εάν το επιτρέπει η επιχείρηση), διαμόρφωση του πόρου.
Νηστεία: Χρησιμοποιήστε ουρές αναμονής (κόμβοι υπο-παραγγελίας ZK) για να είστε δίκαιοι.
9) Παρατηρησιμότητα
Μετρήσεις:- 'lock _ acquire _ total {status = ok' timeout 'error}'
- 'lock _ hold _ seconds {p50, p95, p99}'
- 'fining _ token _ value' (μονοτονία)
- «μίσθωση _ ανανέωση _ αποτυχία _ σύνολο»
- 'split _ brain _ prevented _ total' (αριθμός απόπειρων που απορρίφθηκαν λόγω έλλειψης απαρτίας)
- 'pretemptions _ total', 'wait _ queue _ len'
- 'lock _ name', 'ιδιοκτήτης _ i ,' tken ',' ttl ',' προσπάθεια ',' wait _ time _ m , 'path' ( ZK), 'mod _ revision' (etcd).
- «Αποκτήστε → κρίσιμο τμήμα → απελευθέρωσης» με το αποτέλεσμα.
- Ανάπτυξη 'μίσθωση _ ανανέωση _ αποτυχία _ σύνολο'.
- 'lock _ hold _ seconds {p99}'> SLO.
- «Ορφανές» κλειδαριές (χωρίς καρδιακούς παλμούς).
- Φουσκωμένες λίστες αναμονής.
10) Περιπτωσιολογικές μελέτες
10. 1 Ασφαλής κλειδαριά Redis με ξιφασκία (ψευδο)
1. Αποθηκεύουμε το συμβολικό μετρητή σε ένα αξιόπιστο κατάστημα (για παράδειγμα, Postgres/etcd).
2. Αν το 'SET NX PX' είναι επιτυχημένο, διαβάζουμε/αυξάνουμε το σύμβολο και κάνουμε όλες τις αλλαγές στον πόρο με το σύμβολο να ελέγχεται στη βάση δεδομένων/υπηρεσία.
python acquire token = db. next_token ("locks/orders/42") # monotone ok = redis. set("locks:orders:42", owner, nx=True, px=ttl_ms)
if not ok:
raise Busy()
critical op guarded by token db. exec("UPDATE orders SET... WHERE id=:id AND:token > last_token",...)
release (compare owner)
10. 2 etcd Mutex + watchdog (Go)
go ctx, cancel:= context. WithCancel(context. Background())
sess, _:= concurrency. NewSession(cli, concurrency. WithTTL(10))
m:= concurrency. NewMutex(sess, "/locks/job/cleanup")
if err:= m. Lock(ctx); err!= nil { /... / }
// Watchdog go func() {
<-sess. Done ()//loss of session/quorum cancel ()//stop working
}()
doCritical (ctx )//must respond to ctx. Done()
_ = m. Unlock(context. Background())
_ = sess. Close()
10. 3 Ηγεσία στη ΖΚ (Java, Επιμελητής)
java
LeaderSelector selector = new LeaderSelector(client, "/leaders/cron", listener);
selector. autoRequeue();
selector. start(); // listener. enterLeadership() с try-finally и heartbeat
10. 4 Postgres συμβουλευτική κλειδαριά με προθεσμία (SQL + εφαρμογή)
sql
SELECT pg_try_advisory_lock(128765); -- attempt without blocking
-- if false --> return via backoff + jitter
11) Test playbooks (Ημέρες παιχνιδιού)
Απώλεια απαρτίας: απενεργοποίηση 1-2 etcd κόμβων → η προσπάθεια λήψης της κλειδαριάς δεν πρέπει να περάσει.
GC-pause/stop-the-world: τεχνητά καθυστερεί τη ροή του ιδιοκτήτη → ελέγξτε ότι ο φύλακας διακόπτει τις εργασίες.
Split-brain: εξομοίωση του διαχωρισμού του δικτύου μεταξύ του ιδιοκτήτη και της πλευράς του κάστρου → ο νέος ιδιοκτήτης παίρνει μια υψηλότερη ένδειξη ξιφασκίας, το παλιό απορρίπτεται από το μπλε.
Ρολόι skew/drift: αφαιρέστε το ρολόι από τον ιδιοκτήτη (για Redis/μίσθωση) → βεβαιωθείτε ότι η ορθότητα εξασφαλίζεται με μάρκες/ελέγχους.
Πρόσκρουση πριν την απελευθέρωση: η κλειδαριά → διεργασίας απελευθερώνεται μέσω TTL/συνεδρίας.
12) Αντι-μοτίβα
Καθαρισμός κλειδώματος TTL χωρίς ξιφασκία κατά την πρόσβαση σε εξωτερικό πόρο.
Βασιστείτε στην τοπική ώρα για ορθότητα (χωρίς HLC/ξιφασκία).
Κατανομή κλειδαριών μέσω ενός Redis master σε ένα περιβάλλον με feilover και χωρίς επιβεβαίωση των αντιγράφων.
Απεριόριστη κρίσιμη ενότητα (TTL «για τις ηλικίες»).
Αφαίρεση της κλειδαριάς κάποιου άλλου χωρίς έλεγχο 'ιδιοκτήτη _ id '/μάρκας.
Έλλειψη οπισθοδρόμησης + καταιγίδα απόπειρας.
Ένα ενιαίο παγκόσμιο κλείδωμα «για τα πάντα» - μια σακούλα συγκρούσεων. Η συγκράτηση κλειδιών είναι καλύτερη.
13) Κατάλογος ελέγχου εφαρμογής
- Τύπος πόρων που ορίζεται και μπορεί να απαλλαγεί από CAS/σειρά αναμονής/ταυτότητα.
- Επιλεγμένος μηχανισμός: etcd/ZK/πρόξενος για CP. Redis/cache - μόνο με ξιφασκία.
- Εφαρμόστηκε: 'ιδιοκτήτης _ id', επέκταση TTL +, φύλακας, σωστό ξεκλείδωμα.
- Ο εξωτερικός πόρος ελέγχει την ένδειξη περίφραξης (μονοτονία).
- Υπάρχει στρατηγική ηγεσίας και αποτυχία.
- Διαμορφωμένες μετρήσεις, ειδοποιήσεις, μάρκες καταγραφής και αναθεωρήσεις.
- Παρέχονται backoff + jitter και αποκτούν timeouts.
- Ημέρες παιχνιδιού: απαρτία, split-brain, GC παύσεις, ρολόι skew.
- Τεκμηρίωση της διαδικασίας λήψης πολλών κλειδαριών (εάν απαιτείται).
- σχέδιο brownout - τι να κάνετε όταν η κλειδαριά δεν είναι διαθέσιμη.
14) ΣΥΧΝΈΣ ΕΡΩΤΉΣΕΙΣ
Q: Είναι αρκετά κλειδωμένο το 'SET NX PX' Redis
A: Μόνο εάν ο πόρος ελέγχει το δείγμα περίφραξης. Διαφορετικά, με την κατάτμηση του δικτύου, είναι δυνατοί δύο ιδιοκτήτες.
Ε: Τι να επιλέξετε «εξ ορισμού»
A: Για αυστηρές εγγυήσεις - etcd/ZooKeeper/Πρόξενος (CP). Για εύκολες εργασίες μέσα σε μια βάση δεδομένων - συμβουλευτικές κλειδαριές Postgres. Redis - μόνο με ξιφασκία.
Ε: Ποιο TTL θα τοποθετήσει
A: 'TTL ≥ p99 κρίσιμη διάρκεια διατομής × 2' και αρκετά σύντομη ώστε να καθαρίσει γρήγορα "ζόμπι. "Ανανέωση - κάθε 'TTL/3'.
Ε: Πώς να αποφευχθεί η νηστεία
A: Αναμονή σε σειρά (ακολουθία ZK) ή αλγόριθμος δίκαιης μεταχείρισης. περιορισμός των προσπαθειών και δίκαιος προγραμματισμός.
Ε: Χρειάζομαι συγχρονισμό χρόνου
A: Για ορθότητα - όχι (χρήση ξιφασκίας). Για λειτουργική προβλεψιμότητα, ναι (NTP/PTP), αλλά μην βασίζεστε στο ρολόι τοίχου για τη λογική κλειδώματος.
15) Σύνολα
Αξιόπιστες κατανεμημένες κλειδαριές είναι χτισμένες σε επίπεδα απαρτίας (etcd/ZK/πρόξενος) με μίσθωση + φυλλοβόλο, και συμπληρώνονται απαραίτητα με ένδειξη ξιφασκίας στο επίπεδο του πόρου που αλλάζει. Κάθε προσέγγιση TTL/Redis χωρίς ξιφασκία αποτελεί κίνδυνο διαχωρισμού του εγκεφάλου. Σκεφτείτε πρώτα την αιτιότητα και την ιδεότητα, χρησιμοποιήστε κλειδαριές όπου είναι αδύνατο χωρίς αυτές, μετρήστε, δοκιμάστε τρόπους αποτυχίας - και τα «κρίσιμα τμήματα» σας θα παραμείνουν κρίσιμα μόνο κατά την έννοια, όχι στον αριθμό των συμβάντων.