Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Στο άρθρο θα σας πω πώς προσεγγίσαμε το θέμα της ανοχής σφαλμάτων PostgreSQL, γιατί έγινε σημαντικό για εμάς και τι έγινε τελικά.

Έχουμε μια πολύ φορτωμένη υπηρεσία: 2,5 εκατομμύρια χρήστες παγκοσμίως, 50+ ενεργοί χρήστες κάθε μέρα. Οι διακομιστές βρίσκονται στο Amazone σε μια περιοχή της Ιρλανδίας: 100+ διαφορετικοί διακομιστές λειτουργούν συνεχώς, εκ των οποίων σχεδόν οι 50 είναι με βάσεις δεδομένων.

Ολόκληρο το backend είναι μια μεγάλη μονολιθική κρατική εφαρμογή Java που διατηρεί μια σταθερή σύνδεση websocket με τον πελάτη. Όταν πολλοί χρήστες εργάζονται στον ίδιο πίνακα ταυτόχρονα, βλέπουν όλοι τις αλλαγές σε πραγματικό χρόνο, επειδή γράφουμε κάθε αλλαγή στη βάση δεδομένων. Έχουμε περίπου 10 χιλιάδες αιτήματα ανά δευτερόλεπτο στις βάσεις δεδομένων μας. Σε φορτίο αιχμής στο Redis, γράφουμε 80-100 αιτήματα ανά δευτερόλεπτο.
Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Γιατί αλλάξαμε από το Redis σε PostgreSQL

Αρχικά, η υπηρεσία μας συνεργάστηκε με το Redis, έναν χώρο αποθήκευσης βασικών τιμών που αποθηκεύει όλα τα δεδομένα στη μνήμη RAM του διακομιστή.

Πλεονεκτήματα του Redis:

  1. Υψηλή ταχύτητα απόκρισης, γιατί όλα είναι αποθηκευμένα στη μνήμη.
  2. Ευκολία δημιουργίας αντιγράφων ασφαλείας και αναπαραγωγής.

Μειονεκτήματα του Redis για εμάς:

  1. Δεν υπάρχουν πραγματικές συναλλαγές. Προσπαθήσαμε να τα προσομοιώσουμε στο επίπεδο της εφαρμογής μας. Δυστυχώς, αυτό δεν λειτουργούσε πάντα καλά και απαιτούσε τη σύνταξη πολύ περίπλοκου κώδικα.
  2. Η ποσότητα των δεδομένων περιορίζεται από την ποσότητα της μνήμης. Καθώς αυξάνεται ο όγκος των δεδομένων, η μνήμη θα μεγαλώνει και, στο τέλος, θα συναντήσουμε τα χαρακτηριστικά της επιλεγμένης παρουσίας, η οποία στο AWS απαιτεί τη διακοπή της υπηρεσίας μας για να αλλάξετε τον τύπο της παρουσίας.
  3. Είναι απαραίτητο να διατηρείται συνεχώς ένα χαμηλό επίπεδο καθυστέρησης, γιατί. έχουμε πολύ μεγάλο αριθμό αιτημάτων. Το βέλτιστο επίπεδο καθυστέρησης για εμάς είναι 17-20 ms. Σε επίπεδο 30-40 ms, λαμβάνουμε μεγάλες απαντήσεις σε αιτήματα από την εφαρμογή μας και υποβάθμιση της υπηρεσίας. Δυστυχώς, αυτό συνέβη σε εμάς τον Σεπτέμβριο του 2018, όταν μία από τις περιπτώσεις με το Redis για κάποιο λόγο έλαβε καθυστέρηση 2 φορές περισσότερο από το συνηθισμένο. Για να επιλύσουμε το πρόβλημα, διακόψαμε την υπηρεσία το μεσημέρι λόγω μη προγραμματισμένης συντήρησης και αντικαταστήσαμε την προβληματική παρουσία Redis.
  4. Είναι εύκολο να λάβετε ασυνέπεια δεδομένων ακόμη και με μικρά σφάλματα στον κώδικα και στη συνέχεια να αφιερώσετε πολύ χρόνο γράφοντας κώδικα για να διορθώσετε αυτά τα δεδομένα.

Λάβαμε υπόψη τα μειονεκτήματα και συνειδητοποιήσαμε ότι έπρεπε να προχωρήσουμε σε κάτι πιο βολικό, με κανονικές συναλλαγές και λιγότερη εξάρτηση από την καθυστέρηση. Διεξήγαγε έρευνα, ανέλυσε πολλές επιλογές και επέλεξε την PostgreSQL.

Μεταφερόμαστε σε μια νέα βάση δεδομένων εδώ και 1,5 χρόνο ήδη και έχουμε μετακινήσει μόνο ένα μικρό μέρος των δεδομένων, οπότε τώρα εργαζόμαστε ταυτόχρονα με το Redis και το PostgreSQL. Περισσότερες πληροφορίες σχετικά με τα στάδια μετακίνησης και εναλλαγής δεδομένων μεταξύ βάσεων δεδομένων περιλαμβάνονται στο άρθρο του συναδέλφου μου.

Όταν ξεκινήσαμε για πρώτη φορά να μετακινούμαστε, η εφαρμογή μας δούλευε απευθείας με τη βάση δεδομένων και είχε πρόσβαση στο κύριο Redis και PostgreSQL. Το σύμπλεγμα PostgreSQL αποτελούνταν από ένα κύριο και ένα αντίγραφο με ασύγχρονη αναπαραγωγή. Έτσι φαινόταν το σχήμα της βάσης δεδομένων:
Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Εφαρμογή του PgBouncer

Ενώ μετακινούμασταν, το προϊόν αναπτυσσόταν επίσης: ο αριθμός των χρηστών και ο αριθμός των διακομιστών που δούλευαν με την PostgreSQL αυξήθηκαν και αρχίσαμε να μην έχουμε συνδέσεις. Η PostgreSQL δημιουργεί μια ξεχωριστή διαδικασία για κάθε σύνδεση και καταναλώνει πόρους. Μπορείτε να αυξήσετε τον αριθμό των συνδέσεων μέχρι ένα ορισμένο σημείο, διαφορετικά υπάρχει πιθανότητα να έχετε μη βέλτιστη απόδοση βάσης δεδομένων. Η ιδανική επιλογή σε μια τέτοια κατάσταση θα ήταν να επιλέξετε έναν διαχειριστή σύνδεσης που θα στέκεται μπροστά από τη βάση.

Είχαμε δύο επιλογές για τον διαχειριστή σύνδεσης: Pgpool και PgBouncer. Αλλά το πρώτο δεν υποστηρίζει τη λειτουργία συναλλαγής με τη βάση δεδομένων, έτσι επιλέξαμε το PgBouncer.

Έχουμε δημιουργήσει το ακόλουθο σχήμα εργασίας: η εφαρμογή μας έχει πρόσβαση σε ένα PgBouncer, πίσω από το οποίο βρίσκονται Masters PostgreSQL, και πίσω από κάθε master υπάρχει ένα αντίγραφο με ασύγχρονη αναπαραγωγή.
Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Ταυτόχρονα, δεν μπορούσαμε να αποθηκεύσουμε ολόκληρο τον όγκο δεδομένων στο PostgreSQL και η ταχύτητα εργασίας με τη βάση δεδομένων ήταν σημαντική για εμάς, οπότε ξεκινήσαμε να μοιράζουμε την PostgreSQL σε επίπεδο εφαρμογής. Το σχήμα που περιγράφεται παραπάνω είναι σχετικά βολικό για αυτό: όταν προσθέτετε ένα νέο θραύσμα PostgreSQL, αρκεί να ενημερώσετε τη διαμόρφωση του PgBouncer και η εφαρμογή μπορεί να λειτουργήσει αμέσως με το νέο θραύσμα.

Αποτυχία PgBouncer

Αυτό το σχήμα λειτούργησε μέχρι τη στιγμή που πέθανε το μοναδικό παράδειγμα PgBouncer. Βρισκόμαστε στο AWS, όπου όλες οι περιπτώσεις εκτελούνται σε υλικό που πεθαίνει περιοδικά. Σε τέτοιες περιπτώσεις, η παρουσία απλώς μετακινείται σε νέο υλικό και λειτουργεί ξανά. Αυτό συνέβη με το PgBouncer, αλλά δεν ήταν διαθέσιμο. Αποτέλεσμα αυτής της πτώσης ήταν η μη διαθεσιμότητα της υπηρεσίας μας για 25 λεπτά. Η AWS συνιστά τη χρήση πλεονασμού από την πλευρά του χρήστη για τέτοιες καταστάσεις, η οποία δεν εφαρμόστηκε στη χώρα μας εκείνη την εποχή.

Μετά από αυτό, σκεφτήκαμε σοβαρά την ανοχή σφαλμάτων των συμπλεγμάτων PgBouncer και PostgreSQL, επειδή μια παρόμοια κατάσταση θα μπορούσε να συμβεί με οποιαδήποτε παρουσία στον λογαριασμό μας AWS.

Δημιουργήσαμε το σχήμα ανοχής σφαλμάτων PgBouncer ως εξής: όλοι οι διακομιστές εφαρμογών έχουν πρόσβαση στο Network Load Balancer, πίσω από το οποίο υπάρχουν δύο PgBouncer. Κάθε PgBouncer κοιτάζει τον ίδιο κύριο PostgreSQL κάθε θραύσματος. Εάν συμβεί ξανά ένα σφάλμα παρουσίας AWS, όλη η κίνηση ανακατευθύνεται μέσω ενός άλλου PgBouncer. Η ανακατεύθυνση του Network Load Balancer παρέχεται από το AWS.

Αυτό το σχήμα διευκολύνει την προσθήκη νέων διακομιστών PgBouncer.
Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Δημιουργήστε ένα σύμπλεγμα ανακατεύθυνσης PostgreSQL

Κατά την επίλυση αυτού του προβλήματος, εξετάσαμε διάφορες επιλογές: αυτογραφικό failover, repmgr, AWS RDS, Patroni.

Αυτογραφικά σενάρια

Μπορούν να παρακολουθούν την εργασία του master και, σε περίπτωση αποτυχίας του, να προωθήσουν το αντίγραφο στο master και να ενημερώσουν τη διαμόρφωση του PgBouncer.

Τα πλεονεκτήματα αυτής της προσέγγισης είναι η μέγιστη απλότητα, επειδή γράφετε μόνοι σας σενάρια και κατανοείτε ακριβώς πώς λειτουργούν.

Μειονεκτήματα:

  • Ο κύριος μπορεί να μην έχει πεθάνει, αντίθετα μπορεί να έχει συμβεί μια αποτυχία δικτύου. Το Failover, χωρίς να το γνωρίζει αυτό, θα προωθήσει το αντίγραφο στον κύριο, ενώ ο παλιός κύριος θα συνεχίσει να εργάζεται. Ως αποτέλεσμα, θα έχουμε δύο διακομιστές σε ρόλο κύριου και δεν θα γνωρίζουμε ποιος από αυτούς έχει τα πιο πρόσφατα ενημερωμένα δεδομένα. Αυτή η κατάσταση ονομάζεται επίσης split-brain.
  • Μείναμε χωρίς ανταπόκριση. Στη διαμόρφωσή μας, το κύριο και ένα αντίγραφο, μετά την εναλλαγή, το αντίγραφο μετακινείται στο κύριο και δεν έχουμε πλέον αντίγραφα, επομένως πρέπει να προσθέσουμε χειροκίνητα ένα νέο αντίγραφο.
  • Χρειαζόμαστε επιπλέον παρακολούθηση της λειτουργίας ανακατεύθυνσης, ενώ έχουμε 12 θραύσματα PostgreSQL, που σημαίνει ότι πρέπει να παρακολουθούμε 12 συμπλέγματα. Με την αύξηση του αριθμού των θραυσμάτων, πρέπει επίσης να θυμάστε να ενημερώσετε το failover.

Το αυτογραφικό failover φαίνεται πολύ περίπλοκο και απαιτεί μη τετριμμένη υποστήριξη. Με ένα μόνο σύμπλεγμα PostgreSQL, αυτή θα ήταν η πιο εύκολη επιλογή, αλλά δεν κλιμακώνεται, επομένως δεν είναι κατάλληλη για εμάς.

Repmgr

Replication Manager για συμπλέγματα PostgreSQL, που μπορεί να διαχειριστεί τη λειτουργία ενός συμπλέγματος PostgreSQL. Ταυτόχρονα, δεν διαθέτει αυτόματο failover out of the box, οπότε για εργασία θα χρειαστεί να γράψετε το δικό σας "περιτύλιγμα" πάνω από την τελική λύση. Έτσι, όλα μπορούν να αποδειχθούν ακόμα πιο περίπλοκα από ό,τι με τα σενάρια που γράφτηκαν μόνοι μας, οπότε δεν δοκιμάσαμε καν το Repmgr.

AWS RDS

Υποστηρίζει όλα όσα χρειαζόμαστε, ξέρει πώς να δημιουργεί αντίγραφα ασφαλείας και διατηρεί μια ομάδα συνδέσεων. Διαθέτει αυτόματη εναλλαγή: όταν πεθάνει ο κύριος, το αντίγραφο γίνεται το νέο κύριο και το AWS αλλάζει την εγγραφή dns σε νέο κύριο, ενώ τα αντίγραφα μπορούν να βρίσκονται σε διαφορετικά AZ.

Τα μειονεκτήματα περιλαμβάνουν την έλλειψη λεπτών προσαρμογών. Ως παράδειγμα λεπτής ρύθμισης: οι παρουσίες μας έχουν περιορισμούς για συνδέσεις tcp, οι οποίοι, δυστυχώς, δεν μπορούν να γίνουν στο RDS:

net.ipv4.tcp_keepalive_time=10
net.ipv4.tcp_keepalive_intvl=1
net.ipv4.tcp_keepalive_probes=5
net.ipv4.tcp_retries2=3

Επιπλέον, το AWS RDS είναι σχεδόν διπλάσιο από την τιμή του κανονικού στιγμιότυπου, που ήταν ο κύριος λόγος για την εγκατάλειψη αυτής της λύσης.

Πατρώνη

Αυτό είναι ένα πρότυπο python για τη διαχείριση της PostgreSQL με καλή τεκμηρίωση, αυτόματη ανακατεύθυνση και πηγαίο κώδικα στο github.

Πλεονεκτήματα του Patroni:

  • Κάθε παράμετρος διαμόρφωσης περιγράφεται, είναι σαφές πώς λειτουργεί.
  • Αυτόματη ανακατεύθυνση λειτουργεί έξω από το κουτί.
  • Γραπτό σε python, και δεδομένου ότι εμείς οι ίδιοι γράφουμε πολλά σε python, θα είναι ευκολότερο για εμάς να αντιμετωπίσουμε προβλήματα και, ίσως, ακόμη και να βοηθήσουμε στην ανάπτυξη του έργου.
  • Διαχειρίζεται πλήρως την PostgreSQL, σας επιτρέπει να αλλάξετε τη διαμόρφωση σε όλους τους κόμβους του συμπλέγματος ταυτόχρονα και εάν το σύμπλεγμα πρέπει να επανεκκινηθεί για να εφαρμοστεί η νέα διαμόρφωση, τότε αυτό μπορεί να γίνει ξανά χρησιμοποιώντας το Patroni.

Μειονεκτήματα:

  • Δεν είναι σαφές από την τεκμηρίωση πώς να εργαστείτε σωστά με το PgBouncer. Αν και είναι δύσκολο να το ονομάσουμε μείον, επειδή η αποστολή του Patroni είναι να διαχειρίζεται το PostgreSQL και το πώς θα πάνε οι συνδέσεις με το Patroni είναι ήδη το πρόβλημά μας.
  • Ελάχιστα είναι τα παραδείγματα υλοποίησης του Patroni σε μεγάλους όγκους, ενώ υπάρχουν πολλά παραδείγματα υλοποίησης από την αρχή.

Ως αποτέλεσμα, επιλέξαμε το Patroni για να δημιουργήσουμε ένα σύμπλεγμα ανακατεύθυνσης.

Διαδικασία Υλοποίησης Patroni

Πριν από την Patroni, είχαμε 12 θραύσματα PostgreSQL σε μια διαμόρφωση ενός κύριου και ενός αντιγράφου με ασύγχρονη αναπαραγωγή. Οι διακομιστές εφαρμογών είχαν πρόσβαση στις βάσεις δεδομένων μέσω του Network Load Balancer, πίσω από το οποίο βρίσκονταν δύο περιπτώσεις με το PgBouncer, και πίσω από αυτές ήταν όλοι οι διακομιστές PostgreSQL.
Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Για να εφαρμόσουμε το Patroni, χρειάστηκε να επιλέξουμε μια διαμόρφωση συμπλέγματος κατανεμημένης αποθήκευσης. Η Patroni συνεργάζεται με συστήματα αποθήκευσης κατανεμημένων ρυθμίσεων όπως etcd, Zookeeper, Consul. Έχουμε απλώς ένα πλήρες σύμπλεγμα Consul στην αγορά, το οποίο λειτουργεί σε συνδυασμό με το Vault και δεν το χρησιμοποιούμε πλέον. Ένας πολύ καλός λόγος για να αρχίσετε να χρησιμοποιείτε το Consul για τον προορισμό του.

Πώς συνεργάζεται ο Patroni με τον Πρόξενο

Έχουμε ένα σύμπλεγμα Consul, το οποίο αποτελείται από τρεις κόμβους, και ένα σύμπλεγμα Patroni, το οποίο αποτελείται από έναν αρχηγό και ένα αντίγραφο (στην Πατρώνη, ο κύριος λέγεται αρχηγός συστάδας και οι σκλάβοι ονομάζονται αντίγραφα). Κάθε στιγμιότυπο του συμπλέγματος Patroni στέλνει συνεχώς πληροφορίες για την κατάσταση του συμπλέγματος στον Πρόξενο. Επομένως, από το Consul μπορείτε πάντα να μάθετε την τρέχουσα διαμόρφωση του συμπλέγματος Patroni και ποιος είναι ο ηγέτης αυτή τη στιγμή.

Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Για να συνδέσετε το Patroni με το Consul, αρκεί να μελετήσετε την επίσημη τεκμηρίωση, η οποία λέει ότι πρέπει να καθορίσετε έναν κεντρικό υπολογιστή σε μορφή http ή https, ανάλογα με τον τρόπο με τον οποίο συνεργαζόμαστε με το Consul και το σχήμα σύνδεσης, προαιρετικά:

host: the host:port for the Consul endpoint, in format: http(s)://host:port
scheme: (optional) http or https, defaults to http

Φαίνεται απλό, αλλά εδώ αρχίζουν οι παγίδες. Με το Consul, εργαζόμαστε σε μια ασφαλή σύνδεση μέσω https και η διαμόρφωση της σύνδεσής μας θα μοιάζει με αυτό:

consul:
  host: https://server.production.consul:8080 
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

Αλλά αυτό δεν λειτουργεί. Κατά την εκκίνηση, το Patroni δεν μπορεί να συνδεθεί με το Consul, επειδή προσπαθεί να περάσει από το http ούτως ή άλλως.

Ο πηγαίος κώδικας του Patroni βοήθησε στην αντιμετώπιση του προβλήματος. Ευτυχώς που είναι γραμμένο σε python. Αποδεικνύεται ότι η παράμετρος κεντρικού υπολογιστή δεν αναλύεται με κανέναν τρόπο και το πρωτόκολλο πρέπει να καθοριστεί σε σχήμα. Έτσι φαίνεται για εμάς το λειτουργικό μπλοκ διαμόρφωσης για την εργασία με το Consul:

consul:
  host: server.production.consul:8080
  scheme: https
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

πρόξενος-πρότυπο

Έτσι, επιλέξαμε τον χώρο αποθήκευσης για τη διαμόρφωση. Τώρα πρέπει να καταλάβουμε πώς το PgBouncer θα αλλάξει τη διαμόρφωσή του κατά την αλλαγή του ηγέτη στο σύμπλεγμα Patroni. Δεν υπάρχει απάντηση σε αυτή την ερώτηση στην τεκμηρίωση, γιατί. εκεί, κατ 'αρχήν, η εργασία με το PgBouncer δεν περιγράφεται.

Αναζητώντας μια λύση, βρήκαμε ένα άρθρο (δυστυχώς δεν θυμάμαι τον τίτλο) όπου έγραφε ότι το Сonsul-template βοήθησε πολύ στη σύζευξη του PgBouncer και του Patroni. Αυτό μας ώθησε να διερευνήσουμε πώς λειτουργεί το Consul-template.

Αποδείχθηκε ότι το Consul-template παρακολουθεί συνεχώς τη διαμόρφωση του συμπλέγματος PostgreSQL στο Consul. Όταν αλλάζει ο οδηγός, ενημερώνει τη διαμόρφωση του PgBouncer και στέλνει μια εντολή για να το φορτώσει ξανά.

Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Ένα μεγάλο πλεονέκτημα του προτύπου είναι ότι αποθηκεύεται ως κώδικας, οπότε όταν προσθέτετε ένα νέο θραύσμα, αρκεί να κάνετε μια νέα δέσμευση και να ενημερώσετε το πρότυπο αυτόματα, υποστηρίζοντας την αρχή της Υποδομής ως κώδικα.

Νέα αρχιτεκτονική με Πατρώνη

Ως αποτέλεσμα, πήραμε το ακόλουθο πρόγραμμα εργασίας:
Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Όλοι οι διακομιστές εφαρμογών έχουν πρόσβαση στο balancer → υπάρχουν δύο περιπτώσεις PgBouncer πίσω από αυτό → σε κάθε περίπτωση, εκκινείται το Consul-template, το οποίο παρακολουθεί την κατάσταση κάθε συμπλέγματος Patroni και παρακολουθεί τη συνάφεια της διαμόρφωσης PgBouncer, η οποία στέλνει αιτήματα στον τρέχοντα ηγέτη κάθε συστάδας.

Χειροκίνητη δοκιμή

Εκτελέσαμε αυτό το σχήμα πριν το εκκινήσουμε σε ένα μικρό περιβάλλον δοκιμής και ελέγξαμε τη λειτουργία της αυτόματης εναλλαγής. Άνοιξαν τον πίνακα, μετακίνησαν το αυτοκόλλητο και εκείνη τη στιγμή «σκότωσαν» τον αρχηγό του συμπλέγματος. Στο AWS, αυτό είναι τόσο απλό όσο ο τερματισμός της παρουσίας μέσω της κονσόλας.

Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Το αυτοκόλλητο επέστρεψε μέσα σε 10-20 δευτερόλεπτα και μετά άρχισε να κινείται ξανά κανονικά. Αυτό σημαίνει ότι το σύμπλεγμα Patroni λειτούργησε σωστά: άλλαξε τον αρχηγό, έστειλε τις πληροφορίες στο Сonsul και το Сonsul-template πήρε αμέσως αυτές τις πληροφορίες, αντικατέστησε τη διαμόρφωση του PgBouncer και έστειλε την εντολή για επαναφόρτωση.

Πώς να επιβιώσετε κάτω από υψηλό φορτίο και να διατηρήσετε ελάχιστο τον χρόνο διακοπής λειτουργίας;

Όλα λειτουργούν τέλεια! Αλλά υπάρχουν νέα ερωτήματα: Πώς θα λειτουργήσει υπό υψηλό φορτίο; Πώς να κυκλοφορήσετε γρήγορα και με ασφάλεια τα πάντα στην παραγωγή;

Το περιβάλλον δοκιμής στο οποίο πραγματοποιούμε δοκιμές φορτίου μας βοηθά να απαντήσουμε στην πρώτη ερώτηση. Είναι εντελώς πανομοιότυπο με την παραγωγή όσον αφορά την αρχιτεκτονική και έχει δημιουργήσει δεδομένα δοκιμών που είναι περίπου ίσα σε όγκο με την παραγωγή. Αποφασίζουμε απλώς να «σκοτώσουμε» έναν από τους κύριους της PostgreSQL κατά τη διάρκεια της δοκιμής και να δούμε τι θα συμβεί. Αλλά πριν από αυτό, είναι σημαντικό να ελέγξετε την αυτόματη κύλιση, επειδή σε αυτό το περιβάλλον έχουμε πολλά θραύσματα PostgreSQL, επομένως θα έχουμε εξαιρετική δοκιμή των σεναρίων διαμόρφωσης πριν από την παραγωγή.

Και οι δύο εργασίες φαίνονται φιλόδοξες, αλλά έχουμε την PostgreSQL 9.6. Μπορούμε να αναβαθμίσουμε άμεσα σε 11.2;

Αποφασίζουμε να το κάνουμε σε 2 βήματα: πρώτα αναβάθμιση σε 11.2 και μετά εκκίνηση του Patroni.

Ενημέρωση PostgreSQL

Για γρήγορη ενημέρωση της έκδοσης PostgreSQL, χρησιμοποιήστε την επιλογή -k, στο οποίο δημιουργούνται σκληροί σύνδεσμοι στο δίσκο και δεν υπάρχει ανάγκη αντιγραφής των δεδομένων σας. Σε βάσεις 300-400 GB, η ενημέρωση διαρκεί 1 δευτερόλεπτο.

Έχουμε πολλά θραύσματα, οπότε η ενημέρωση πρέπει να γίνει αυτόματα. Για να γίνει αυτό, γράψαμε ένα βιβλίο παιχνιδιού Ansible που χειρίζεται ολόκληρη τη διαδικασία ενημέρωσης για εμάς:

/usr/lib/postgresql/11/bin/pg_upgrade 
<b>--link </b>
--old-datadir='' --new-datadir='' 
 --old-bindir=''  --new-bindir='' 
 --old-options=' -c config_file=' 
 --new-options=' -c config_file='

Είναι σημαντικό να σημειώσετε εδώ ότι πριν ξεκινήσετε την αναβάθμιση, πρέπει να την εκτελέσετε με την παράμετρο --έλεγχοςγια να βεβαιωθείτε ότι μπορείτε να κάνετε αναβάθμιση. Το σενάριό μας κάνει επίσης την αντικατάσταση των ρυθμίσεων για τη διάρκεια της αναβάθμισης. Το σενάριό μας ολοκληρώθηκε σε 30 δευτερόλεπτα, το οποίο είναι ένα εξαιρετικό αποτέλεσμα.

Εκκίνηση Patroni

Για να λύσετε το δεύτερο πρόβλημα, απλώς δείτε τη διαμόρφωση Patroni. Το επίσημο αποθετήριο έχει ένα παράδειγμα διαμόρφωσης με το initdb, το οποίο είναι υπεύθυνο για την προετοιμασία μιας νέας βάσης δεδομένων κατά την πρώτη εκκίνηση του Patroni. Αλλά επειδή έχουμε ήδη μια έτοιμη βάση δεδομένων, απλώς αφαιρέσαμε αυτήν την ενότητα από τη διαμόρφωση.

Όταν ξεκινήσαμε να εγκαθιστούμε το Patroni σε ένα ήδη υπάρχον σύμπλεγμα PostgreSQL και να το εκτελούμε, αντιμετωπίσαμε ένα νέο πρόβλημα: και οι δύο διακομιστές ξεκίνησαν ως ηγέτης. Ο Patroni δεν γνωρίζει τίποτα για την πρώιμη κατάσταση του συμπλέγματος και προσπαθεί να ξεκινήσει και τους δύο διακομιστές ως δύο ξεχωριστά συμπλέγματα με το ίδιο όνομα. Για να λύσετε αυτό το πρόβλημα, πρέπει να διαγράψετε τον κατάλογο με δεδομένα στον εξαρτημένο:

rm -rf /var/lib/postgresql/

Αυτό πρέπει να γίνει μόνο στον δούλο!

Όταν συνδέεται ένα καθαρό αντίγραφο, ο Patroni δημιουργεί έναν αρχηγό δημιουργίας αντιγράφων ασφαλείας βάσης και τον επαναφέρει στο αντίγραφο και, στη συνέχεια, προσεγγίζει την τρέχουσα κατάσταση σύμφωνα με τα wal log.

Μια άλλη δυσκολία που συναντήσαμε είναι ότι όλα τα συμπλέγματα PostgreSQL ονομάζονται κύρια από προεπιλογή. Όταν κάθε σύμπλεγμα δεν γνωρίζει τίποτα για το άλλο, αυτό είναι φυσιολογικό. Αλλά όταν θέλετε να χρησιμοποιήσετε το Patroni, τότε όλα τα συμπλέγματα πρέπει να έχουν ένα μοναδικό όνομα. Η λύση είναι να αλλάξετε το όνομα του συμπλέγματος στη διαμόρφωση PostgreSQL.

δοκιμή φορτίου

Ξεκινήσαμε μια δοκιμή που προσομοιώνει την εμπειρία χρήστη σε πίνακες. Όταν το φορτίο έφτασε στη μέση ημερήσια τιμή μας, επαναλάβαμε ακριβώς την ίδια δοκιμή, απενεργοποιήσαμε μια παρουσία με τον PostgreSQL leader. Το αυτόματο failover λειτούργησε όπως περιμέναμε: ο Patroni άλλαξε τον αρχηγό, το Consul-template ενημέρωσε τη διαμόρφωση του PgBouncer και έστειλε μια εντολή για επαναφόρτωση. Σύμφωνα με τα γραφήματα μας στη Γραφάνα, ήταν σαφές ότι υπάρχουν καθυστερήσεις 20-30 δευτερολέπτων και μικρός αριθμός σφαλμάτων από τους διακομιστές που σχετίζονται με τη σύνδεση με τη βάση δεδομένων. Αυτή είναι μια φυσιολογική κατάσταση, τέτοιες τιμές είναι αποδεκτές για το failover μας και είναι σίγουρα καλύτερες από το χρόνο διακοπής της υπηρεσίας.

Φέρνοντας τον Patroni στην παραγωγή

Ως αποτέλεσμα, καταλήξαμε στο ακόλουθο σχέδιο:

  • Αναπτύξτε το πρότυπο Consul σε διακομιστές PgBouncer και εκκινήστε.
  • Ενημερώσεις PostgreSQL στην έκδοση 11.2.
  • Αλλάξτε το όνομα του συμπλέγματος.
  • Έναρξη του Patroni Cluster.

Ταυτόχρονα, το σχήμα μας μας επιτρέπει να κάνουμε το πρώτο σημείο σχεδόν ανά πάσα στιγμή, μπορούμε να αφαιρέσουμε κάθε PgBouncer από την εργασία με τη σειρά και να αναπτύξουμε και να εκτελέσουμε το consul-template σε αυτό. Έτσι κάναμε.

Για γρήγορη ανάπτυξη, χρησιμοποιήσαμε το Ansible, καθώς έχουμε ήδη δοκιμάσει όλα τα βιβλία αναπαραγωγής σε περιβάλλον δοκιμής και ο χρόνος εκτέλεσης του πλήρους σεναρίου ήταν από 1,5 έως 2 λεπτά για κάθε θραύσμα. Θα μπορούσαμε να απλώσουμε τα πάντα με τη σειρά σε κάθε θραύσμα χωρίς να σταματήσουμε την υπηρεσία μας, αλλά θα έπρεπε να απενεργοποιήσουμε κάθε PostgreSQL για αρκετά λεπτά. Σε αυτήν την περίπτωση, οι χρήστες των οποίων τα δεδομένα βρίσκονται σε αυτό το θραύσμα δεν θα μπορούσαν να λειτουργήσουν πλήρως αυτήν τη στιγμή και αυτό είναι απαράδεκτο για εμάς.

Η διέξοδος από αυτή την κατάσταση ήταν η προγραμματισμένη συντήρηση, η οποία πραγματοποιείται κάθε 3 μήνες. Αυτό είναι ένα παράθυρο για προγραμματισμένη εργασία, όταν τερματίζουμε εντελώς την υπηρεσία μας και αναβαθμίζουμε τις παρουσίες της βάσης δεδομένων μας. Έμενε μία εβδομάδα μέχρι το επόμενο παράθυρο και αποφασίσαμε να περιμένουμε και να προετοιμαστούμε περαιτέρω. Κατά τη διάρκεια του χρόνου αναμονής, ασφαλιστήκαμε επιπλέον: για κάθε θραύσμα PostgreSQL, δημιουργήσαμε ένα εφεδρικό αντίγραφο σε περίπτωση αποτυχίας διατήρησης των πιο πρόσφατων δεδομένων και προσθέσαμε ένα νέο παράδειγμα για κάθε θραύσμα, το οποίο θα πρέπει να γίνει νέο αντίγραφο στο σύμπλεγμα Patroni. ώστε να μην εκτελεστεί εντολή διαγραφής δεδομένων . Όλα αυτά βοήθησαν στην ελαχιστοποίηση του κινδύνου λάθους.
Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Επανεκκινήσαμε την υπηρεσία μας, όλα λειτουργούσαν όπως έπρεπε, οι χρήστες συνέχισαν να εργάζονται, αλλά στα γραφήματα παρατηρήσαμε ασυνήθιστα υψηλό φορτίο στους διακομιστές Consul.
Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Γιατί δεν το είδαμε αυτό στο δοκιμαστικό περιβάλλον; Αυτό το πρόβλημα δείχνει πολύ καλά ότι είναι απαραίτητο να ακολουθήσουμε την αρχή της Υποδομής ως κώδικα και να βελτιώσουμε ολόκληρη την υποδομή, από τα περιβάλλοντα δοκιμής έως την παραγωγή. Διαφορετικά, είναι πολύ εύκολο να αντιμετωπίσουμε το πρόβλημα που αντιμετωπίσαμε. Τι συνέβη? Το Consul εμφανίστηκε αρχικά στην παραγωγή και στη συνέχεια σε περιβάλλοντα δοκιμών, ως αποτέλεσμα, σε περιβάλλοντα δοκιμής, η έκδοση του Consul ήταν υψηλότερη από ό,τι στην παραγωγή. Μόλις σε μία από τις εκδόσεις, επιλύθηκε μια διαρροή CPU κατά την εργασία με το consul-template. Επομένως, απλώς ενημερώσαμε το Consul, λύνοντας έτσι το πρόβλημα.

Επανεκκινήστε το σύμπλεγμα Patroni

Ωστόσο, αντιμετωπίσαμε ένα νέο πρόβλημα, το οποίο ούτε καν υποψιαζόμασταν. Κατά την ενημέρωση του Consul, απλώς αφαιρούμε τον κόμβο Consul από το σύμπλεγμα χρησιμοποιώντας την εντολή consul leave → Patroni συνδέεται με άλλο διακομιστή Consul → όλα λειτουργούν. Αλλά όταν φτάσαμε στην τελευταία εμφάνιση του συμπλέγματος Consul και στείλαμε την εντολή consul leave σε αυτό, όλα τα συμπλέγματα Patroni απλά επανεκκινήθηκαν και στα αρχεία καταγραφής είδαμε το ακόλουθο σφάλμα:

ERROR: get_cluster
Traceback (most recent call last):
...
RetryFailedError: 'Exceeded retry deadline'
ERROR: Error communicating with DCS
<b>LOG: database system is shut down</b>

Το σύμπλεγμα Patroni δεν μπόρεσε να ανακτήσει πληροφορίες σχετικά με το σύμπλεγμα του και ξεκίνησε ξανά.

Για να βρούμε μια λύση, επικοινωνήσαμε με τους συγγραφείς Patroni μέσω ενός ζητήματος στο github. Πρότειναν βελτιώσεις στα αρχεία διαμόρφωσής μας:

consul:
 consul.checks: []
bootstrap:
 dcs:
   retry_timeout: 8

Μπορέσαμε να αναπαράγουμε το πρόβλημα σε ένα δοκιμαστικό περιβάλλον και δοκιμάσαμε αυτές τις επιλογές εκεί, αλλά δυστυχώς δεν λειτούργησαν.

Το πρόβλημα παραμένει ακόμη άλυτο. Σκοπεύουμε να δοκιμάσουμε τις παρακάτω λύσεις:

  • Χρησιμοποιήστε Consul-agent σε κάθε περίπτωση ομάδας Patroni.
  • Διορθώστε το πρόβλημα στον κώδικα.

Καταλαβαίνουμε πού προέκυψε το σφάλμα: το πρόβλημα είναι πιθανώς η χρήση του προεπιλεγμένου χρονικού ορίου, το οποίο δεν παρακάμπτεται μέσω του αρχείου διαμόρφωσης. Όταν ο τελευταίος διακομιστής Consul αφαιρεθεί από το σύμπλεγμα, ολόκληρο το σύμπλεγμα Consul μένει για περισσότερο από ένα δευτερόλεπτο, εξαιτίας αυτού, ο Patroni δεν μπορεί να λάβει την κατάσταση του συμπλέγματος και επανεκκινεί πλήρως ολόκληρο το σύμπλεγμα.

Ευτυχώς, δεν αντιμετωπίσαμε άλλα λάθη.

Αποτελέσματα χρήσης Patroni

Μετά την επιτυχημένη κυκλοφορία του Patroni, προσθέσαμε ένα επιπλέον αντίγραφο σε κάθε σύμπλεγμα. Τώρα σε κάθε σύμπλεγμα υπάρχει μια φαινομενικά απαρτία: ένας αρχηγός και δύο αντίγραφα, για δίχτυ ασφαλείας σε περίπτωση διαίρεσης εγκεφάλου κατά την εναλλαγή.
Failover Cluster PostgreSQL + Patroni. Εμπειρία υλοποίησης

Ο Patroni εργάζεται πάνω από τρεις μήνες στην παραγωγή. Κατά τη διάρκεια αυτής της περιόδου, έχει ήδη καταφέρει να μας βοηθήσει. Πρόσφατα, ο αρχηγός ενός από τα συμπλέγματα πέθανε στο AWS, η αυτόματη ανακατεύθυνση λειτούργησε και οι χρήστες συνέχισαν να εργάζονται. Η Πατρώνη εκπλήρωσε το κύριο καθήκον της.

Μια μικρή περίληψη της χρήσης του Patroni:

  • Ευκολία στις αλλαγές διαμόρφωσης. Αρκεί να αλλάξετε τη διαμόρφωση σε μία περίπτωση και θα τραβηχτεί σε ολόκληρο το σύμπλεγμα. Εάν απαιτείται επανεκκίνηση για την εφαρμογή της νέας διαμόρφωσης, τότε η Patroni θα σας ενημερώσει. Το Patroni μπορεί να επανεκκινήσει ολόκληρο το σύμπλεγμα με μία μόνο εντολή, η οποία είναι επίσης πολύ βολική.
  • Το αυτόματο failover λειτουργεί και έχει ήδη καταφέρει να μας βοηθήσει.
  • Ενημέρωση PostgreSQL χωρίς χρόνο διακοπής λειτουργίας της εφαρμογής. Πρέπει πρώτα να ενημερώσετε τα αντίγραφα στη νέα έκδοση, στη συνέχεια να αλλάξετε τον αρχηγό στο σύμπλεγμα Patroni και να ενημερώσετε τον παλιό αρχηγό. Σε αυτήν την περίπτωση, πραγματοποιείται ο απαραίτητος έλεγχος της αυτόματης ανακατεύθυνσης.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο