RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα

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

Ας δούμε τις στρατηγικές ανοχής σφαλμάτων, συνέπειας και υψηλής διαθεσιμότητας (HA) και τις ανταλλαγές που κάνει κάθε στρατηγική. Το RabbitMQ μπορεί να τρέξει σε ένα σύμπλεγμα κόμβων - και στη συνέχεια ταξινομείται ως κατανεμημένο σύστημα. Όταν πρόκειται για κατανεμημένα συστήματα, μιλάμε συχνά για συνέπεια και διαθεσιμότητα.

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

Θα δούμε ότι η συνέπεια και η διαθεσιμότητα βρίσκονται σε αντίθετα άκρα του φάσματος και πρέπει να επιλέξετε ποιον τρόπο θα βελτιστοποιήσετε. Τα καλά νέα είναι ότι με το RabbitMQ αυτή η επιλογή είναι δυνατή. Διαθέτετε τέτοιου είδους «σπασμωδικούς» μοχλούς για να αλλάξετε την ισορροπία προς μεγαλύτερη συνέπεια ή μεγαλύτερη προσβασιμότητα.

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

Single Node Resilience Primitives

Ανθεκτική ουρά/δρομολόγηση

Υπάρχουν δύο τύποι ουρών στο RabbitMQ: ανθεκτικές και μη ανθεκτικές. Όλες οι ουρές αποθηκεύονται στη βάση δεδομένων Mnesia. Οι ανθεκτικές ουρές διαφημίζονται εκ νέου κατά την εκκίνηση του κόμβου και έτσι επιβιώνουν από επανεκκινήσεις, σφάλματα συστήματος ή σφάλματα διακομιστή (εφόσον τα δεδομένα διατηρούνται). Αυτό σημαίνει ότι εφόσον δηλώσετε ότι η δρομολόγηση (ανταλλαγή) και η ουρά είναι ανθεκτικές, η υποδομή ουράς/δρομολόγησης θα επανέλθει στο διαδίκτυο.

Οι ασταθείς ουρές και η δρομολόγηση αφαιρούνται όταν ο κόμβος επανεκκινείται.

Επίμονα μηνύματα

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

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 1. Πίνακας βιωσιμότητας

Ομαδοποίηση με κατοπτρισμό ουρών

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

Κατοπτρισμός ουράς:

  • μία κύρια ουρά (κύρια), η οποία λαμβάνει όλες τις εντολές εγγραφής και ανάγνωσης
  • έναν ή περισσότερους καθρέφτες που λαμβάνουν όλα τα μηνύματα και τα μεταδεδομένα από την κύρια ουρά. Αυτοί οι καθρέφτες δεν υπάρχουν για κλιμάκωση, αλλά καθαρά για πλεονασμό.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 2. Καθρεφτισμός ουράς

Το mirroring ορίζεται από την κατάλληλη πολιτική. Σε αυτό μπορείτε να επιλέξετε τον συντελεστή αναπαραγωγής και ακόμη και τους κόμβους στους οποίους θα πρέπει να βρίσκεται η ουρά. Παραδείγματα:

  • ha-mode: all
  • ha-mode: exactly, ha-params: 2 (ένας κύριος και ένας καθρέφτης)
  • ha-mode: nodes, ha-params: rabbit@node1, rabbit@node2

Επιβεβαίωση εκδότη

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

Ουρά ανακατεύθυνσης

Όταν ένας μεσίτης αποχωρεί ή κολλάει, όλοι οι ηγέτες της ουράς (κύριοι) σε αυτόν τον κόμβο συντρίβονται μαζί του. Στη συνέχεια, το σύμπλεγμα επιλέγει τον παλαιότερο καθρέφτη κάθε πλοιάρχου και τον προωθεί ως νέο κύριο.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 3. Πολλαπλές αντικατοπτρισμένες ουρές και οι πολιτικές τους

Το Broker 3 πέφτει. Σημειώστε ότι ο καθρέφτης της ουράς C στο Broker 2 προωθείται σε κύριο. Σημειώστε επίσης ότι έχει δημιουργηθεί ένας νέος καθρέφτης για την ουρά C στο Broker 1. Το RabbitMQ προσπαθεί πάντα να διατηρήσει τον παράγοντα αναπαραγωγής που καθορίζεται στις πολιτικές σας.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 4. Ο μεσίτης 3 αποτυγχάνει, προκαλώντας αποτυχία της ουράς C

Το επόμενο Broker 1 πέφτει! Έχουμε μόνο έναν μεσίτη. Ο καθρέφτης της ουράς Β προωθείται σε κύριο.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Σχήμα. 5

Επιστρέψαμε το Broker 1. Ανεξάρτητα από το πόσο καλά επιβιώνουν τα δεδομένα από την απώλεια και την ανάκτηση του μεσίτη, όλα τα αντικατοπτρισμένα μηνύματα ουράς απορρίπτονται κατά την επανεκκίνηση. Αυτό είναι σημαντικό να σημειωθεί γιατί θα υπάρξουν συνέπειες. Θα εξετάσουμε αυτές τις συνέπειες σύντομα. Έτσι, ο Broker 1 είναι πλέον μέλος του συμπλέγματος και το σύμπλεγμα προσπαθεί να συμμορφωθεί με τις πολιτικές και ως εκ τούτου δημιουργεί καθρέφτες στο Broker 1.

Σε αυτή την περίπτωση, η απώλεια του Broker 1 ήταν πλήρης, όπως και τα δεδομένα, έτσι η ουρά Β που δεν είχε αντικατοπτριστεί χάθηκε εντελώς.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 6. Ο Μεσίτης 1 επιστρέφει στην υπηρεσία

Το Broker 3 είναι και πάλι συνδεδεμένο, επομένως οι ουρές Α και Β παίρνουν πίσω τους καθρέφτες που δημιουργήθηκαν σε αυτό για να ικανοποιήσουν τις πολιτικές τους HA. Αλλά τώρα όλες οι κύριες ουρές είναι σε έναν κόμβο! Αυτό δεν είναι ιδανικό, μια ομοιόμορφη κατανομή μεταξύ των κόμβων είναι καλύτερη. Δυστυχώς, δεν υπάρχουν πολλές επιλογές εδώ για την εξισορρόπηση των κυρίων. Θα επανέλθουμε σε αυτό το ζήτημα αργότερα γιατί πρέπει πρώτα να εξετάσουμε τον συγχρονισμό ουράς.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 7. Ο μεσίτης 3 επιστρέφει στην υπηρεσία. Όλες οι κύριες ουρές σε έναν κόμβο!

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

Συγχρονισμός

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

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

Έχουμε δύο καθρέφτες ουρές. Η ουρά Α συγχρονίζεται αυτόματα και η ουρά Β συγχρονίζεται χειροκίνητα. Και οι δύο ουρές περιέχουν δέκα μηνύματα.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 8. Δύο ουρές με διαφορετικούς τρόπους συγχρονισμού

Τώρα χάνουμε το Broker 3.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 9. Ο μεσίτης 3 έπεσε

Ο Broker 3 επιστρέφει στην υπηρεσία. Το σύμπλεγμα δημιουργεί έναν καθρέφτη για κάθε ουρά στον νέο κόμβο και συγχρονίζει αυτόματα τη νέα ουρά Α με την κύρια. Ωστόσο, ο καθρέφτης του νέου Queue B παραμένει κενός. Με αυτόν τον τρόπο έχουμε πλήρη πλεονασμό στην ουρά Α και μόνο έναν καθρέφτη για υπάρχοντα μηνύματα της ουράς Β.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 10. Ο νέος καθρέφτης της ουράς Α λαμβάνει όλα τα υπάρχοντα μηνύματα, αλλά ο νέος καθρέφτης της ουράς Β όχι.

Δέκα ακόμη μηνύματα φτάνουν και στις δύο ουρές. Στη συνέχεια, το Broker 2 κολλάει και η ουρά Α επιστρέφει στον παλαιότερο καθρέφτη, που βρίσκεται στο Broker 1. Δεν υπάρχει απώλεια δεδομένων όταν αποτύχει. Στην ουρά Β, υπάρχουν είκοσι μηνύματα στο κύριο και μόνο δέκα στον καθρέφτη, επειδή αυτή η ουρά δεν αναπαρήγαγε ποτέ τα αρχικά δέκα μηνύματα.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 11. Η ουρά Α επιστρέφει στο Broker 1 χωρίς να χαθούν μηνύματα

Δέκα ακόμη μηνύματα φτάνουν και στις δύο ουρές. Τώρα κολλάει το Broker 1. Η ουρά Α μεταβαίνει εύκολα στον καθρέφτη χωρίς να χάνει μηνύματα. Ωστόσο, η ουρά Β αντιμετωπίζει προβλήματα. Σε αυτό το σημείο μπορούμε να βελτιστοποιήσουμε είτε τη διαθεσιμότητα είτε τη συνέπεια.

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

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 12. Η ουρά Α επιστρέφει στο Broker 3 χωρίς να χαθούν μηνύματα. Η ουρά Β επιστρέφει στο Broker 3 με δέκα μηνύματα χαμένα

Μπορούμε επίσης να εγκαταστήσουμε ha-promote-on-failure σε νόημα when-synced. Σε αυτήν την περίπτωση, αντί να επιστρέψει στον καθρέφτη, η ουρά θα περιμένει έως ότου ο Broker 1 με τα δεδομένα του επιστρέψει σε λειτουργία online. Αφού επιστρέψει, η κύρια ουρά επιστρέφει στο Broker 1 χωρίς απώλεια δεδομένων. Η διαθεσιμότητα θυσιάζεται για την ασφάλεια των δεδομένων. Αλλά αυτή είναι μια επικίνδυνη λειτουργία που μπορεί να οδηγήσει ακόμη και σε πλήρη απώλεια δεδομένων, την οποία θα εξετάσουμε σύντομα.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 13. Η ουρά Β παραμένει μη διαθέσιμη μετά την απώλεια του Broker 1

Μπορείτε να ρωτήσετε, "Είναι καλύτερα να μην χρησιμοποιείτε ποτέ τον αυτόματο συγχρονισμό;" Η απάντηση είναι ότι ο συγχρονισμός είναι μια λειτουργία αποκλεισμού. Κατά τη διάρκεια του συγχρονισμού, η κύρια ουρά δεν μπορεί να εκτελέσει λειτουργίες ανάγνωσης ή εγγραφής!

Ας δούμε ένα παράδειγμα. Τώρα έχουμε πολύ μεγάλες ουρές. Πώς μπορούν να μεγαλώσουν σε τέτοιο μέγεθος; Για διάφορους λόγους:

  • Οι ουρές δεν χρησιμοποιούνται ενεργά
  • Αυτές είναι ουρές υψηλής ταχύτητας και αυτή τη στιγμή οι καταναλωτές είναι αργοί
  • Είναι ουρές υψηλής ταχύτητας, υπήρξε πρόβλημα και οι καταναλωτές προλαβαίνουν

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 14. Δύο μεγάλες ουρές με διαφορετικούς τρόπους συγχρονισμού

Τώρα πέφτει το Broker 3.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 15. Ο Broker 3 πέφτει, αφήνοντας ένα master και mirror σε κάθε ουρά

Το Broker 3 επιστρέφει στο διαδίκτυο και δημιουργούνται νέοι καθρέφτες. Η κύρια ουρά Α αρχίζει να αναπαράγει υπάρχοντα μηνύματα στο νέο καθρέφτη και κατά τη διάρκεια αυτής της περιόδου η ουρά δεν είναι διαθέσιμη. Χρειάζονται δύο ώρες για την αναπαραγωγή των δεδομένων, με αποτέλεσμα δύο ώρες διακοπής λειτουργίας για αυτήν την ουρά!

Ωστόσο, η ουρά Β παραμένει διαθέσιμη καθ' όλη τη διάρκεια της περιόδου. Θυσίασε κάποιο πλεονασμό για την προσβασιμότητα.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 16. Η ουρά παραμένει μη διαθέσιμη κατά τον συγχρονισμό

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

Ενημερώσεις

Αυτή η συμπεριφορά αποκλεισμού κατά τον συγχρονισμό καθιστά δύσκολη την ενημέρωση συμπλεγμάτων με πολύ μεγάλες ουρές. Σε κάποιο σημείο, ο κύριος κόμβος πρέπει να επανεκκινηθεί, πράγμα που σημαίνει είτε αλλαγή σε καθρέφτη είτε απενεργοποίηση της ουράς ενώ ο διακομιστής αναβαθμίζεται. Εάν επιλέξουμε τη μετάβαση, θα χάσουμε μηνύματα εάν οι καθρέφτες δεν είναι συγχρονισμένοι. Από προεπιλογή, κατά τη διάρκεια διακοπής λειτουργίας μεσίτη, δεν εκτελείται failover σε μη συγχρονισμένο καθρέφτη. Αυτό σημαίνει ότι μόλις επιστρέψει ο μεσίτης, δεν χάνουμε κανένα μήνυμα, η μόνη ζημιά ήταν μια απλή ουρά. Οι κανόνες συμπεριφοράς όταν ένας μεσίτης αποσυνδέεται ορίζονται από την πολιτική ha-promote-on-shutdown. Μπορείτε να ορίσετε μία από τις δύο τιμές:

  • always= η μετάβαση σε μη συγχρονισμένους καθρέφτες είναι ενεργοποιημένη
  • when-synced= μετάβαση μόνο σε συγχρονισμένο καθρέφτη, διαφορετικά η ουρά γίνεται μη αναγνώσιμη και άγραφη. Η ουρά επιστρέφει στην υπηρεσία μόλις επιστρέψει ο μεσίτης

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

Όταν η διαθεσιμότητα βελτιώνει την ασφάλεια δεδομένων

Υπάρχει μια ακόμη επιπλοκή που πρέπει να εξετάσετε πριν λάβετε μια απόφαση. Ενώ ο αυτόματος συγχρονισμός είναι καλύτερος για πλεονασμό, πώς επηρεάζει την ασφάλεια των δεδομένων; Φυσικά, με καλύτερο πλεονασμό, το RabbitMQ είναι λιγότερο πιθανό να χάσει τα υπάρχοντα μηνύματα, αλλά τι γίνεται με τα νέα μηνύματα από εκδότες;

Εδώ πρέπει να λάβετε υπόψη τα εξής:

  • Θα μπορούσε ο εκδότης απλώς να επιστρέψει ένα σφάλμα και να ζητήσει από την υπηρεσία upstream ή τον χρήστη να προσπαθήσει ξανά αργότερα;
  • Μπορεί ο εκδότης να αποθηκεύσει το μήνυμα τοπικά ή σε μια βάση δεδομένων για να προσπαθήσει ξανά αργότερα;

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

Επομένως, πρέπει να αναζητηθεί μια ισορροπία και η λύση εξαρτάται από τη συγκεκριμένη κατάσταση.

Προβλήματα με το ha-promote-on-failure=when-synced

Ιδέα χα-προώθηση-σε-αποτυχία= όταν-συγχρονίζεται είναι ότι αποτρέπουμε τη μετάβαση σε μη συγχρονισμένο καθρέφτη και έτσι αποφεύγουμε την απώλεια δεδομένων. Η ουρά παραμένει μη αναγνώσιμη ή εγγράψιμη. Αντίθετα, προσπαθούμε να ανακτήσουμε τον μεσίτη που έχει καταρρεύσει με άθικτα τα δεδομένα του, ώστε να μπορεί να συνεχίσει να λειτουργεί ως κύριος χωρίς απώλεια δεδομένων.

Αλλά (και αυτό είναι μεγάλο αλλά) εάν ο μεσίτης έχει χάσει τα δεδομένα του, τότε έχουμε ένα μεγάλο πρόβλημα: η ουρά έχει χαθεί! Όλα τα δεδομένα έχουν χαθεί! Ακόμα κι αν έχετε καθρέφτες που φτάνουν ως επί το πλείστον με την κύρια ουρά, αυτοί οι καθρέφτες απορρίπτονται επίσης.

Για να προσθέσουμε ξανά έναν κόμβο με το ίδιο όνομα, λέμε στο σύμπλεγμα να ξεχάσει τον χαμένο κόμβο (με την εντολή rabbitmqctl forget_cluster_node) και ξεκινήστε έναν νέο μεσίτη με το ίδιο όνομα κεντρικού υπολογιστή. Ενώ το σύμπλεγμα θυμάται τον χαμένο κόμβο, θυμάται την παλιά ουρά και τους μη συγχρονισμένους καθρέφτες. Όταν σε ένα σύμπλεγμα λένε να ξεχάσει έναν ορφανό κόμβο, ξεχνιέται και αυτή η ουρά. Τώρα πρέπει να το ξαναδηλώσουμε. Χάσαμε όλα τα δεδομένα, αν και είχαμε καθρέφτες με μερικό σύνολο δεδομένων. Θα ήταν καλύτερα να μεταβείτε σε έναν μη συγχρονισμένο καθρέφτη!

Επομένως, ο χειροκίνητος συγχρονισμός (και η αποτυχία συγχρονισμού) σε συνδυασμό με ha-promote-on-failure=when-synced, κατά τη γνώμη μου, είναι αρκετά επικίνδυνο. Τα έγγραφα λένε ότι αυτή η επιλογή υπάρχει για την ασφάλεια των δεδομένων, αλλά είναι ένα μαχαίρι με δύο άκρες.

Master rebalancing

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

Η επανεξισορρόπηση των κυρίων μπορεί να είναι προβληματική για δύο λόγους:

  • Δεν υπάρχουν καλά εργαλεία για την επανεξισορρόπηση
  • Συγχρονισμός ουράς

Υπάρχει τρίτο μέρος για επανεξισορρόπηση plugin, το οποίο δεν υποστηρίζεται επίσημα. Σχετικά με τα πρόσθετα τρίτων στο εγχειρίδιο RabbitMQ λέγεται: «Η προσθήκη παρέχει ορισμένα πρόσθετα εργαλεία διαμόρφωσης και αναφοράς, αλλά δεν υποστηρίζεται ούτε επαληθεύεται από την ομάδα του RabbitMQ. Χρησιμοποιήστε το με δική σας ευθύνη."

Υπάρχει ένα άλλο κόλπο για να μετακινήσετε την κύρια ουρά μέσω των πολιτικών HA. Το εγχειρίδιο αναφέρει γραφή για αυτό. Δουλεύει κάπως έτσι:

  • Καταργεί όλους τους καθρέφτες χρησιμοποιώντας μια προσωρινή πολιτική που έχει υψηλότερη προτεραιότητα από την υπάρχουσα πολιτική HA.
  • Αλλάζει την προσωρινή πολιτική HA για χρήση της λειτουργίας κόμβου, καθορίζοντας τον κόμβο στον οποίο πρέπει να μεταφερθεί η κύρια ουρά.
  • Συγχρονίζει την ουρά για μετεγκατάσταση ώθησης.
  • Μετά την ολοκλήρωση της μετεγκατάστασης, διαγράφεται η προσωρινή πολιτική. Η αρχική πολιτική HA τίθεται σε ισχύ και δημιουργείται ο απαιτούμενος αριθμός κατόπτρων.

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

Τώρα ας δούμε πώς λειτουργούν τα συμπλέγματα RabbitMQ με κατατμήσεις δικτύου.

Απώλεια συνδεσιμότητας

Οι κόμβοι ενός κατανεμημένου συστήματος συνδέονται με συνδέσμους δικτύου και οι συνδέσεις δικτύου μπορούν και θα αποσυνδεθούν. Η συχνότητα των διακοπών εξαρτάται από την τοπική υποδομή ή την αξιοπιστία του επιλεγμένου νέφους. Σε κάθε περίπτωση, τα κατανεμημένα συστήματα πρέπει να είναι σε θέση να τα αντιμετωπίσουν. Για άλλη μια φορά έχουμε την επιλογή μεταξύ διαθεσιμότητας και συνέπειας, και πάλι τα καλά νέα είναι ότι το RabbitMQ παρέχει και τις δύο επιλογές (απλώς όχι ταυτόχρονα).

Με το RabbitMQ έχουμε δύο βασικές επιλογές:

  • Επιτρέψτε τη λογική διαίρεση (split-brain). Αυτό διασφαλίζει τη διαθεσιμότητα, αλλά μπορεί να προκαλέσει απώλεια δεδομένων.
  • Απενεργοποιήστε τον λογικό διαχωρισμό. Μπορεί να οδηγήσει σε βραχυπρόθεσμη απώλεια διαθεσιμότητας ανάλογα με τον τρόπο σύνδεσης των πελατών στο σύμπλεγμα. Μπορεί επίσης να οδηγήσει σε πλήρη μη διαθεσιμότητα σε ένα σύμπλεγμα δύο κόμβων.

Τι είναι όμως ο λογικός χωρισμός; Αυτό συμβαίνει όταν ένα σύμπλεγμα χωρίζεται στα δύο λόγω απώλειας συνδέσεων δικτύου. Σε κάθε πλευρά, οι καθρέφτες προωθούνται σε κύριο, έτσι ώστε τελικά να υπάρχουν αρκετοί κύριοι ανά ουρά.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 17. Κύρια ουρά και δύο καθρέφτες, το καθένα σε ξεχωριστό κόμβο. Στη συνέχεια παρουσιάζεται μια αποτυχία δικτύου και ένας καθρέφτης αποσπάται. Ο διαχωρισμένος κόμβος βλέπει ότι οι άλλοι δύο έχουν πέσει και προωθεί τους καθρέφτες του στον κύριο. Τώρα έχουμε δύο κύριες ουρές, εγγράψιμες και αναγνώσιμες.

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

Οι διαφορετικοί τρόποι λειτουργίας του RabbitMQ παρέχουν είτε διαθεσιμότητα είτε συνέπεια.

Λειτουργία παράβλεψης (προεπιλογή)

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

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 18. Τρεις εκδότες συνδέονται με τρεις μεσίτες. Εσωτερικά, το σύμπλεγμα δρομολογεί όλα τα αιτήματα στην κύρια ουρά στο Broker 2.

Τώρα χάνουμε το Broker 3. Βλέπει ότι άλλοι μεσίτες έχουν πέσει και προωθεί τον καθρέφτη του στον κύριο. Έτσι προκύπτει ένας λογικός διαχωρισμός.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 19. Λογική διαίρεση (split-brain). Οι εγγραφές μπαίνουν σε δύο κύριες ουρές και τα δύο αντίγραφα αποκλίνουν.

Η συνδεσιμότητα αποκαταστάθηκε, αλλά ο λογικός διαχωρισμός παραμένει. Ο διαχειριστής πρέπει να επιλέξει χειροκίνητα την πλευρά που χάνει. Στην παρακάτω περίπτωση, ο διαχειριστής κάνει επανεκκίνηση του Broker 3. Όλα τα μηνύματα που δεν κατάφερε να μεταδώσει χάνονται.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 20. Ο διαχειριστής απενεργοποιεί το Broker 3.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 21. Ο διαχειριστής ξεκινά το Broker 3 και ενώνεται στο σύμπλεγμα, χάνοντας όλα τα μηνύματα που είχαν απομείνει εκεί.

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

Λειτουργία αυτόματης θεραπείας

Λειτουργεί παρόμοια με τη λειτουργία Ignore, με τη διαφορά ότι το ίδιο το σύμπλεγμα επιλέγει αυτόματα την πλευρά που χάνει μετά τον διαχωρισμό και την αποκατάσταση της συνδεσιμότητας. Η χαμένη πλευρά επιστρέφει στο σύμπλεγμα κενή και η ουρά χάνει όλα τα μηνύματα που στάλθηκαν μόνο σε αυτήν την πλευρά.

Παύση λειτουργίας μειοψηφίας

Εάν δεν θέλουμε να επιτρέψουμε τη λογική κατάτμηση, τότε η μόνη μας επιλογή είναι να απορρίψουμε τις αναγνώσεις και τις γραφές στη μικρότερη πλευρά μετά το διαμέρισμα συμπλέγματος. Όταν ο μεσίτης δει ότι είναι στη μικρότερη πλευρά, αναστέλλει την εργασία, δηλαδή κλείνει όλες τις υπάρχουσες συνδέσεις και αρνείται τυχόν νέες. Μία φορά ανά δευτερόλεπτο ελέγχει για αποκατάσταση συνδεσιμότητας. Μόλις αποκατασταθεί η συνδεσιμότητα, συνεχίζει να λειτουργεί και εντάσσεται στο σύμπλεγμα.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 22. Τρεις εκδότες συνδέονται με τρεις μεσίτες. Εσωτερικά, το σύμπλεγμα δρομολογεί όλα τα αιτήματα στην κύρια ουρά στο Broker 2.

Στη συνέχεια, οι Brokers 1 και 2 χωρίζονται από το Broker 3. Αντί να προωθήσει το mirror τους σε master, το Broker 3 τίθεται σε αναστολή και καθίσταται μη διαθέσιμο.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 23. Το Broker 3 κάνει παύση, αποσυνδέει όλους τους πελάτες και απορρίπτει αιτήματα σύνδεσης.

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

Ας δούμε ένα άλλο παράδειγμα όπου η κύρια ουρά βρίσκεται στο Broker 3.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 24. Κύρια ουρά στο Broker 3.

Τότε συμβαίνει η ίδια απώλεια συνδεσιμότητας. Το Broker 3 κάνει παύση επειδή βρίσκεται στη μικρότερη πλευρά. Από την άλλη πλευρά, οι κόμβοι βλέπουν ότι το Broker 3 έχει πέσει, έτσι ο παλαιότερος καθρέφτης από τους Brokers 1 και 2 προωθείται σε master.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 25. Μετάβαση στο Broker 2 εάν το Broker 3 δεν είναι διαθέσιμο.

Όταν αποκατασταθεί η συνδεσιμότητα, το Broker 3 θα ενταχθεί στο σύμπλεγμα.

RabbitMQ vs Kafka: Ανοχή σφαλμάτων και υψηλή διαθεσιμότητα σε συμπλέγματα
Ρύζι. 26. Το σύμπλεγμα έχει επιστρέψει στην κανονική λειτουργία.

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

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

Εξασφάλιση συνδεσιμότητας πελατών

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

Οι επιλογές μας:

  • Η πρόσβαση στο σύμπλεγμα γίνεται με χρήση ενός εξισορροπητή φορτίου που απλώς περνάει στους κόμβους και οι πελάτες προσπαθούν να συνδεθούν ξανά μέχρι να πετύχουν. Εάν ένας κόμβος είναι εκτός λειτουργίας ή σε αναστολή, τότε οι προσπάθειες σύνδεσης με αυτόν τον κόμβο θα αποτύχουν, αλλά οι επόμενες προσπάθειες θα πάνε σε άλλους διακομιστές (με κυκλικό τρόπο). Αυτό είναι κατάλληλο για βραχυπρόθεσμη απώλεια συνδεσιμότητας ή διακοπή λειτουργίας διακομιστή που θα επανέλθει γρήγορα.
  • Αποκτήστε πρόσβαση στο σύμπλεγμα μέσω ενός εξισορροπητή φορτίου και αφαιρέστε τους κόμβους που έχουν τεθεί σε αναστολή/αποτυχία από τη λίστα μόλις εντοπιστούν. Εάν το κάνουμε αυτό γρήγορα και εάν οι πελάτες μπορέσουν να δοκιμάσουν ξανά τη σύνδεση, τότε θα επιτύχουμε σταθερή διαθεσιμότητα.
  • Δώστε σε κάθε πελάτη μια λίστα με όλους τους κόμβους και ο πελάτης επιλέγει τυχαία έναν από αυτούς κατά τη σύνδεση. Εάν λάβει κάποιο σφάλμα κατά την προσπάθεια σύνδεσης, μετακινείται στον επόμενο κόμβο της λίστας μέχρι να συνδεθεί.
  • Καταργήστε την κυκλοφορία από έναν αποτυχημένο/ανεσταλμένο κόμβο χρησιμοποιώντας DNS. Αυτό γίνεται χρησιμοποιώντας ένα μικρό TTL.

Ευρήματα

Η ομαδοποίηση RabbitMQ έχει τα πλεονεκτήματα και τα μειονεκτήματά της. Τα πιο σοβαρά μειονεκτήματα είναι ότι:

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

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

  • Αναξιόπιστο δίκτυο.
  • Αναξιόπιστη αποθήκευση.
  • Πολύ μεγάλες ουρές.

Όταν πρόκειται για ρυθμίσεις υψηλής διαθεσιμότητας, λάβετε υπόψη τα εξής:

  • ha-promote-on-failure=always
  • ha-sync-mode=manual
  • cluster_partition_handling=ignoreautoheal)
  • επίμονα μηνύματα
  • βεβαιωθείτε ότι οι πελάτες συνδέονται στον ενεργό κόμβο όταν κάποιος κόμβος αποτυγχάνει

Για συνέπεια (ασφάλεια δεδομένων), λάβετε υπόψη τις ακόλουθες ρυθμίσεις:

  • Επιβεβαιώσεις εκδότη και μη αυτόματες επιβεβαιώσεις από την πλευρά του καταναλωτή
  • ha-promote-on-failure=when-synced, εάν οι εκδότες μπορούν να προσπαθήσουν ξανά αργότερα και εάν έχετε πολύ αξιόπιστο χώρο αποθήκευσης! Αλλιώς βάλε =always.
  • ha-sync-mode=automatic (αλλά για μεγάλες ανενεργές ουρές μπορεί να απαιτείται χειροκίνητη λειτουργία. Επίσης, εξετάστε εάν η μη διαθεσιμότητα θα προκαλέσει την απώλεια μηνυμάτων)
  • Παύση λειτουργίας μειοψηφίας
  • επίμονα μηνύματα

Δεν έχουμε καλύψει ακόμα όλα τα θέματα ανοχής σφαλμάτων και υψηλής διαθεσιμότητας. για παράδειγμα, πώς να εκτελείτε με ασφάλεια διοικητικές διαδικασίες (όπως κυλιόμενες ενημερώσεις). Πρέπει επίσης να μιλήσουμε για την ομοσπονδία και το πρόσθετο Shovel.

Αν μου έχει διαφύγει κάτι άλλο, ενημερώστε με.

Δείτε επίσης το δικό μου post, όπου κάνω χάος σε ένα σύμπλεγμα RabbitMQ χρησιμοποιώντας Docker και Blockade για να δοκιμάσω ορισμένα από τα σενάρια απώλειας μηνυμάτων που περιγράφονται σε αυτό το άρθρο.

Προηγούμενα άρθρα της σειράς:
Νο. 1 - habr.com/ru/company/itsumma/blog/416629
Νο. 2 - habr.com/ru/company/itsumma/blog/418389
Νο. 3 - habr.com/ru/company/itsumma/blog/437446

Πηγή: www.habr.com

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