Μετάβαση στο περιεχόμενο
EuroVPSEuroVPS
Περιοχή πελατών

Συνέπεια read-after-write σε cluster Galera

Ένα cluster Galera ή Percona XtraDB πιστοποιεί ένα write στο commit και το εφαρμόζει στους άλλους κόμβους λίγο αργότερα, και ένα read που δρομολογείται μέσα σε αυτό το κενό βλέπει το παρελθόν.

Από EuroVPS EngineeringΤο μηχανοστάσιο

6 λεπτά ανάγνωσης
Σε αυτό το άρθρο 6 ενότητες
Εν συντομία
  • Σε ένα cluster βασισμένο σε certification, commit σημαίνει ότι το write πιστοποιήθηκε σε κάθε κόμβο, όχι ότι κάθε κόμβος το εφάρμοσε. Η εφαρμογή γίνεται λίγο αργότερα, τυπικά από δεκάδες έως μερικές εκατοντάδες χιλιοστά του δευτερολέπτου.
  • Ένα read που ισορροπείται σε κόμβο που δεν έχει εφαρμόσει ακόμη το write επιστρέφει την παλιά γραμμή. Σε ένα CMS αυτό διαβάζεται ως χαμένη αλλαγή: ο συντάκτης αποθηκεύει, ανανεώνει, βλέπει το παλιό κείμενο, και αποθηκεύει ξανά πάνω από τη νεότερη έκδοση. Κανένα σφάλμα δεν εμφανίζεται πουθενά.
  • Το wsrep_sync_wait κλείνει το κενό κάνοντας ένα read να περιμένει μέχρι ο κόμβος του να φτάσει στο ρεύμα. Κοστίζει το apply lag στα reads που ακολουθούν ένα write, οπότε περιορίζεται στις συνεδρίες που το χρειάζονται και μένει κλειστό στις σελίδες που σερβίρει ένα edge cache.

Commit σημαίνει πιστοποιημένο, όχι εφαρμοσμένο

Ένα cluster Galera τρέχει μια συναλλαγή σε έναν κόμβο. Στο commit, αυτός ο κόμβος εκπέμπει το write set στο cluster, κάθε κόμβος το πιστοποιεί απέναντι στα write sets που βρίσκονται ήδη σε εξέλιξη, και το commit επιστρέφει στον client. Από εκείνη τη στιγμή το write είναι διαρκές στο cluster και διατεταγμένο πανομοιότυπα παντού.

Αυτό που δεν έχει συμβεί ακόμη είναι η εφαρμογή. Κάθε κόμβος παίρνει το πιστοποιημένο write set και το εφαρμόζει στο δικό του αντίγραφο των δεδομένων στα δικά του applier threads, λίγο μετά την επιστροφή του commit. Τρέχουν δύο ρολόγια: η πιστοποίηση είναι σε επίπεδο cluster και μέρος του commit, η εφαρμογή είναι τοπική και έρχεται μετά. Σε ένα υγιές cluster η απόσταση μεταξύ τους είναι από δεκάδες έως μερικές εκατοντάδες χιλιοστά του δευτερολέπτου. Μεγαλώνει σε εκρήξεις writes, μεγάλες συναλλαγές και αλλαγές σχήματος, και είναι ορατή ως μη μηδενικό wsrep_local_recv_queue στον κόμβο που είναι πίσω.

Πού πηγαίνει το read

Ένα cluster με ισορροπημένα reads στέλνει τα reads όπου αποφασίσει ο proxy. Ένα αίτημα γράφει στον κόμβο A. Το επόμενο αίτημα από τον ίδιο χρήστη, μερικές εκατοντάδες χιλιοστά αργότερα, διαβάζει στον κόμβο B. Αν ο κόμβος B έχει λάβει αλλά δεν έχει εφαρμόσει ακόμη το write set, απαντά με τη γραμμή όπως ήταν πριν από το write. Από τη σκοπιά του κόμβου B η απάντηση είναι σωστή: αυτή είναι η committed κατάστασή του. Τίποτα δεν καταγράφεται, τίποτα δεν χτυπάει συναγερμό, και το monitoring του lag μένει σιωπηλό γιατί είναι φτιαγμένο να πιάνει παρατεταμένο lag, όχι τα πρώτα εκατό χιλιοστά μετά από μία συναλλαγή.

Γι' αυτό το σύμπτωμα μοιάζει τυχαίο. Εξαρτάται από το ποιον κόμβο διάλεξε ο balancer, πόσο γρήγορα επέστρεψε ο χρήστης, και πόσο απασχολημένοι ήταν οι appliers εκείνη τη στιγμή.

Πώς φαίνεται σε μια εφαρμογή

Το μοτίβο είναι ένα write που ακολουθείται αμέσως από ένα read από τον ίδιο χρήστη, που προσγειώνεται σε διαφορετικό κόμβο. Σε ένα CMS είναι η παράγραφος που εξαφανίστηκε: αποθήκευση, ανανέωση, παλιό κείμενο, ξαναγράψιμο, αποθήκευση, και η δεύτερη αποθήκευση γράφει πάνω από την πρώτη. Σε ένα e-shop είναι μια παραγγελία που δεν υπάρχει στη σελίδα επιβεβαίωσης. Σε μια ροή αυθεντικοποίησης είναι ένα token που μόλις εκδόθηκε και δεν βρίσκεται.

Δύο άλλοι μηχανισμοί παράγουν παρόμοια ιστορία και αξίζει να αποκλειστούν πρώτοι. Το back-forward cache ενός browser μπορεί να επαναφέρει ένα παλιό αντίγραφο μιας φόρμας, και μια νέα αποθήκευση γράφει τότε αυτό το παλιό αντίγραφο. Ένα plugin μπορεί να κάνει read-modify-write στην ίδια γραμμή από δύο αιτήματα. Και τα δύο είναι πραγματικά και κανένα δεν είναι το cluster. Ένας βρόχος που γράφει μια χρονοσφραγίδα σε έναν κόμβο και τη διαβάζει πίσω από τους άλλους τα ξεχωρίζει σε ένα λεπτό.

Η ρύθμιση: wsrep_sync_wait

Το wsrep_sync_wait είναι bitmask. Με το bit 1 ενεργό, ένα SELECT περιμένει μέχρι ο κόμβος να έχει εφαρμόσει κάθε write set που έχει λάβει μέχρι εκείνη τη στιγμή πριν τρέξει. Το read τότε είναι εγγυημένο ότι βλέπει ό,τι έγινε commit οπουδήποτε στο cluster πριν ξεκινήσει. Μπορεί να οριστεί για μία συνεδρία, που είναι το σωστό εύρος για μια διαδρομή συντάκτη ή checkout, ή καθολικά όταν ολόκληρος ο φόρτος εργασίας είναι ευαίσθητος στο read-after-write.

TERMINAL
-- for one session: the request path that writes and then reads
SET SESSION wsrep_sync_wait = 1;

-- for the whole node: my.cnf, under [mysqld]
wsrep_sync_wait = 1

Η εναλλακτική είναι η δρομολόγηση: στείλτε τα reads που ακολουθούν ένα write στον κόμβο που έγραψε, με κανόνες query του proxy ή μέσα στην εφαρμογή. Δουλεύει για τις διαδρομές που καλύπτει. Μία διαδρομή κώδικα που κανείς δεν δρομολόγησε ξανανοίγει το κενό, και γι' αυτό η ρύθμιση προτιμάται όπου το κόστος μπορεί να πληρωθεί: αντιμετωπίζει τον μηχανισμό, όχι μία διαδρομή μέσα από αυτόν.

Τι κοστίζει και πού να το πληρώσετε

Ένα read υπό wsrep_sync_wait περιμένει τον τοπικό applier να φτάσει στο ρεύμα, οπότε πληρώνει το apply lag μία φορά ανά read που ακολουθεί ένα write. Σε ένα υγιές cluster αυτό είναι δεκάδες έως μερικές εκατοντάδες χιλιοστά του δευτερολέπτου. Οι συνδεδεμένες συνεδρίες, οι διαδρομές διαχείρισης και σύνταξης και το checkout είναι εκεί όπου αυτό το κόστος αγοράζει κάτι. Οι ανώνυμες σελίδες που σερβίρονται από edge cache δεν αγγίζουν τη βάση δεδομένων σε hit και δεν επηρεάζονται. Η ρύθμιση ενεργοποιείται στην επόμενη δήλωση και επανέρχεται με τον ίδιο τρόπο, οπότε μπορεί να μετρηθεί επί τόπου με τον πραγματικό φόρτο εργασίας αντί να εκτιμηθεί.

Πώς να ελέγξετε το δικό σας cluster

Τρεις μετρήσεις το κρίνουν. Αν τα reads περιμένουν καθόλου. Πόσο πίσω τρέχει ένας κόμβος σε μια έκρηξη writes. Και πόσο συχνά ένα read-after-write ανάμεσα σε κόμβους βλέπει πράγματι το παρελθόν, από έναν βρόχο που γράφει σε έναν κόμβο και διαβάζει στους άλλους.

TERMINAL
SHOW GLOBAL VARIABLES LIKE 'wsrep_sync_wait';        -- 0 means reads do not wait
SHOW GLOBAL STATUS LIKE 'wsrep_local_recv_queue';    -- received, not yet applied

Λειτουργούμε clusters Percona XtraDB με ισορροπημένα reads πίσω από ProxySQL και HAProxy και μπορούμε να απαντήσουμε και στα τρία για κάθε cluster που λειτουργούμε, μαζί με το τι κοστίζει η ρύθμιση σε εκείνον τον συγκεκριμένο φόρτο εργασίας.

Ευθείες απαντήσεις

Είναι το Galera replication σύγχρονο;+

Η πιστοποίηση είναι: το write πιστοποιείται σε κάθε κόμβο πριν επιστρέψει το commit. Η εφαρμογή σε κάθε κόμβο γίνεται λίγο αργότερα. Και τα δύο μισά μετράνε, και το δεύτερο είναι εκεί όπου ζουν τα προβλήματα read-after-write.

Γιατί το CMS μου χάνει αλλαγές σε cluster;+

Ένα read μετά από αποθήκευση δρομολογήθηκε σε κόμβο που είχε λάβει το write set αλλά δεν το είχε εφαρμόσει ακόμη. Ο συντάκτης είδε το παλιό περιεχόμενο, το ξανάγραψε και αποθήκευσε πάνω από τη νεότερη έκδοση. Δεν παράγεται σφάλμα, γι' αυτό μοιάζει διαλείπον.

Βοηθάει το άδειασμα του cache;+

Συνήθως όχι. Το cache αποθήκευσε ό,τι επέστρεψε η βάση, και για μια στιγμή η βάση επέστρεψε το παρελθόν. Διαγνώστε τη διαδρομή του read. Το cache εδώ μεταφέρει το σύμπτωμα, δεν είναι η αιτία.

Τι κοστίζει το wsrep_sync_wait;+

Το apply lag, που πληρώνεται στα reads που ακολουθούν ένα write, τυπικά δεκάδες έως μερικές εκατοντάδες χιλιοστά του δευτερολέπτου σε υγιές cluster. Οι σελίδες που σερβίρονται από edge cache δεν επηρεάζονται. Περιορίστε το ανά συνεδρία για να το πληρώνετε μόνο εκεί όπου μετράει.

Λειτουργείτε cluster με ισορροπημένα reads;

Μιλήστε με έναν μηχανικό για το αν το read-after-write είναι ενεργό και τι κοστίζει στο δικό σας.

Μιλήστε με έναν μηχανικό

Φτάσατε στο τέλος.

Βάλτε την ανάγνωση σε εφαρμογή

Τι τρέχετε;

Πείτε μας για τον φόρτο εργασίας, την κίνηση και τις απαιτήσεις ανάκαμψης. Ξεκινήστε από το εργαλείο διαμόρφωσης server ή συζητήστε τις λεπτομέρειες με έναν μηχανικό.

Γραμμένο από τους μηχανικούς που χτίζουν και λειτουργούν την υποδομή που περιγράφει.
Μιλήστε με έναν μηχανικό
XIn

6 λεπτά ακόμη