Elasticsearch cluster 200 TB+

Elasticsearch cluster 200 TB+

Πολλοί άνθρωποι αγωνίζονται με το Elasticsearch. Τι συμβαίνει όμως όταν θέλετε να το χρησιμοποιήσετε για να αποθηκεύσετε αρχεία καταγραφής «σε ιδιαίτερα μεγάλο όγκο»; Και είναι επίσης ανώδυνο να βιώνεις την αποτυχία κάποιου από τα πολλά κέντρα δεδομένων; Τι είδους αρχιτεκτονική πρέπει να φτιάξετε και σε ποιες παγίδες θα σκοντάψετε;

Εμείς στην Odnoklassniki αποφασίσαμε να χρησιμοποιήσουμε το elasticsearch για να λύσουμε το ζήτημα της διαχείρισης κορμών και τώρα μοιραζόμαστε την εμπειρία μας με τη Habr: τόσο για την αρχιτεκτονική όσο και για τις παγίδες.

Είμαι ο Pyotr Zaitsev, εργάζομαι ως διαχειριστής συστήματος στην Odnoklassniki. Πριν από αυτό, ήμουν επίσης διαχειριστής, δούλευα με Manticore Search, Sphinx search, Elasticsearch. Ίσως, αν εμφανιστεί άλλη ...αναζήτηση, μάλλον θα το δουλέψω κι εγώ. Συμμετέχω επίσης σε μια σειρά από έργα ανοιχτού κώδικα σε εθελοντική βάση.

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

Απαιτήσεις

Οι απαιτήσεις του συστήματος διαμορφώθηκαν ως εξής:

  • Το Graylog επρόκειτο να χρησιμοποιηθεί ως frontend. Επειδή η εταιρεία είχε ήδη εμπειρία στη χρήση αυτού του προϊόντος, οι προγραμματιστές και οι δοκιμαστές το γνώριζαν, τους ήταν οικείο και βολικό.
  • Όγκος δεδομένων: κατά μέσο όρο 50-80 χιλιάδες μηνύματα ανά δευτερόλεπτο, αλλά αν κάτι σπάσει, τότε η κίνηση δεν περιορίζεται από τίποτα, μπορεί να είναι 2-3 εκατομμύρια γραμμές ανά δευτερόλεπτο
  • Έχοντας συζητήσει με τους πελάτες τις απαιτήσεις για την ταχύτητα επεξεργασίας των ερωτημάτων αναζήτησης, συνειδητοποιήσαμε ότι το τυπικό μοτίβο χρήσης ενός τέτοιου συστήματος είναι το εξής: οι άνθρωποι αναζητούν αρχεία καταγραφής της εφαρμογής τους τις τελευταίες δύο ημέρες και δεν θέλουν να περιμένουν περισσότερο από ένα δεύτερο για το αποτέλεσμα ενός διατυπωμένου ερωτήματος.
  • Οι διαχειριστές επέμειναν ότι το σύστημα μπορεί να κλιμακωθεί εύκολα εάν είναι απαραίτητο, χωρίς να τους απαιτείται να εμβαθύνουν στον τρόπο λειτουργίας του.
  • Έτσι, η μόνη εργασία συντήρησης που απαιτούν περιοδικά αυτά τα συστήματα είναι η αλλαγή κάποιου υλικού.
  • Επιπλέον, η Odnoklassniki έχει μια εξαιρετική τεχνική παράδοση: οποιαδήποτε υπηρεσία που λανσάρουμε πρέπει να επιβιώσει από μια βλάβη του κέντρου δεδομένων (ξαφνική, απρογραμμάτιστη και απολύτως ανά πάσα στιγμή).

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

Τετάρτη

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

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

Σημαντικό χαρακτηριστικό: το σύμπλεγμα ξεκινά σε δοχεία Πόντμαν όχι σε φυσικές μηχανές, αλλά σε δικό του προϊόν cloud one-cloud. Τα κοντέινερ είναι εγγυημένα 2 πυρήνων, παρόμοια με τα 2.0 Ghz v4, με δυνατότητα ανακύκλωσης των υπόλοιπων πυρήνων εάν είναι αδρανείς.

Με άλλα λόγια:

Elasticsearch cluster 200 TB+

Τοπολογία

Αρχικά είδα τη γενική μορφή της λύσης ως εξής:

  • 3-4 VIP βρίσκονται πίσω από το A-record του τομέα Graylog, αυτή είναι η διεύθυνση στην οποία αποστέλλονται τα αρχεία καταγραφής.
  • κάθε VIP είναι εξισορροπητής LVS.
  • Μετά από αυτό, τα αρχεία καταγραφής πηγαίνουν στην μπαταρία Graylog, μερικά από τα δεδομένα είναι σε μορφή GELF, μερικά σε μορφή syslog.
  • Στη συνέχεια, όλα αυτά γράφονται σε μεγάλες παρτίδες σε μια μπαταρία συντονιστών Elasticsearch.
  • Και αυτοί, με τη σειρά τους, στέλνουν αιτήματα εγγραφής και ανάγνωσης στους σχετικούς κόμβους δεδομένων.

Elasticsearch cluster 200 TB+

Λεξιλόγιο

Ίσως δεν καταλαβαίνουν όλοι την ορολογία λεπτομερώς, οπότε θα ήθελα να σταθώ λίγο σε αυτήν.

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

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

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

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

graylog
Αυτό είναι κάτι σαν fusion του Kibana με το Logstash σε μια στοίβα ELK. Το Graylog συνδυάζει τόσο μια διεπαφή χρήστη όσο και μια διοχέτευση επεξεργασίας αρχείων καταγραφής. Κάτω από την κουκούλα, η Graylog τρέχει το Kafka και το Zookeeper, τα οποία παρέχουν συνδεσιμότητα στο Graylog ως σύμπλεγμα. Το Graylog μπορεί να αποθηκεύσει προσωρινά αρχεία καταγραφής (Kafka) σε περίπτωση που το Elasticsearch δεν είναι διαθέσιμο και να επαναλάβει ανεπιτυχή αιτήματα ανάγνωσης και εγγραφής, να ομαδοποιήσει και να σημειώσει αρχεία καταγραφής σύμφωνα με καθορισμένους κανόνες. Όπως και το Logstash, το Graylog έχει τη δυνατότητα να τροποποιεί σειρές πριν τις εγγράψει στο Elasticsearch.

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

Οπτικά μοιάζει κάπως έτσι:

Elasticsearch cluster 200 TB+

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

Индексы

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

Στο παραπάνω διάγραμμα, αυτό είναι το χαμηλότερο επίπεδο: Κόμβοι δεδομένων Elasticsearch.

Ένα ευρετήριο είναι μια μεγάλη εικονική οντότητα που αποτελείται από θραύσματα Elasticsearch. Από μόνο του, καθένα από τα θραύσματα δεν είναι παρά ένας δείκτης Lucene. Και κάθε ευρετήριο Lucene, με τη σειρά του, αποτελείται από ένα ή περισσότερα τμήματα.

Elasticsearch cluster 200 TB+

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

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

Αρχικά καθορίσαμε τον χρόνο αποθήκευσης ως 30 ημέρες.

Η κατανομή των θραυσμάτων μπορεί να αναπαρασταθεί γραφικά ως εξής:

Elasticsearch cluster 200 TB+

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

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

Elasticsearch cluster 200 TB+

Εναλλαγή δεικτών, δηλ. δημιουργώντας ένα νέο ευρετήριο και διαγράφοντας το παλαιότερο, το κάναμε ίσο με 48 ώρες (σύμφωνα με το πρότυπο χρήσης του ευρετηρίου: οι τελευταίες 48 ώρες αναζητούνται συχνότερα).

Αυτό το διάστημα περιστροφής του δείκτη οφείλεται στους ακόλουθους λόγους:

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

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

Για να παρέχουμε τον απαραίτητο λανθάνοντα χρόνο αναζήτησης, αποφασίσαμε να χρησιμοποιήσουμε έναν SSD. Για να επεξεργαστούν γρήγορα αιτήματα, τα μηχανήματα που φιλοξενούσαν αυτά τα κοντέινερ έπρεπε να έχουν τουλάχιστον 56 πυρήνες. Ο αριθμός 56 επιλέχθηκε ως μια υπό όρους επαρκής τιμή που καθορίζει τον αριθμό των νημάτων που θα δημιουργήσει το Elasticsearch κατά τη λειτουργία. Στην Elasitcsearch, πολλές παράμετροι της ομάδας νημάτων εξαρτώνται άμεσα από τον αριθμό των διαθέσιμων πυρήνων, ο οποίος με τη σειρά του επηρεάζει άμεσα τον απαιτούμενο αριθμό κόμβων στο σύμπλεγμα σύμφωνα με την αρχή "λιγότεροι πυρήνες - περισσότεροι κόμβοι".

Ως αποτέλεσμα, διαπιστώσαμε ότι κατά μέσο όρο ένα θραύσμα ζυγίζει περίπου 20 gigabyte και υπάρχουν 1 θραύσματα ανά ευρετήριο. Αντίστοιχα, αν τις περιστρέψουμε μία φορά κάθε 360 ώρες, τότε έχουμε 48 από αυτές. Κάθε ευρετήριο περιέχει δεδομένα για 15 ημέρες.

Κυκλώματα εγγραφής και ανάγνωσης δεδομένων

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

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

Ο συντονιστής, έχοντας λάβει ένα αίτημα από την Graylog, ρωτά τον πλοίαρχο: "Στο αίτημα ευρετηρίασης, καθορίσαμε συγκεκριμένα ένα ευρετήριο, αλλά σε ποιο θραύσμα να το γράψουμε δεν καθορίστηκε."

Ο κύριος απαντά: "Γράψτε αυτές τις πληροφορίες στον αριθμό θραύσματος 71", μετά από το οποίο αποστέλλονται απευθείας στον σχετικό κόμβο δεδομένων, όπου βρίσκεται ο αριθμός πρωτεύοντος θραύσματος 71.

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

Elasticsearch cluster 200 TB+

Φτάνει ένα αίτημα αναζήτησης από το Graylog στον συντονιστή. Ο συντονιστής το ανακατευθύνει σύμφωνα με το ευρετήριο, ενώ το Elasticsearch διανέμει τα αιτήματα μεταξύ του πρωτεύοντος θραύσματος και του αντιγράφου με τη χρήση της αρχής round-robin.

Elasticsearch cluster 200 TB+

Οι 180 κόμβοι ανταποκρίνονται άνισα και ενώ ανταποκρίνονται, ο συντονιστής συσσωρεύει πληροφορίες που έχουν ήδη «φτύσει» από ταχύτερους κόμβους δεδομένων. Μετά από αυτό, όταν είτε έχουν φθάσει όλες οι πληροφορίες είτε το αίτημα έχει φτάσει σε χρονικό όριο, τα δίνει όλα απευθείας στον πελάτη.

Ολόκληρο αυτό το σύστημα επεξεργάζεται κατά μέσο όρο ερωτήματα αναζήτησης για τις τελευταίες 48 ώρες σε 300-400 ms, εξαιρουμένων αυτών των ερωτημάτων με έναν κορυφαίο χαρακτήρα μπαλαντέρ.

Λουλούδια με Elasticsearch: Εγκατάσταση Java

Elasticsearch cluster 200 TB+

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

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

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

Αποδείχθηκε ότι οι συγχωνεύσεις του δείκτη Lucene συμβαίνουν έξω από το ισχίο. Και τα κοντέινερ είναι αρκετά αυστηρά περιορισμένα όσον αφορά τους πόρους που καταναλώνονται. Μόνο το σωρό μπορούσε να χωρέσει σε αυτούς τους πόρους (η τιμή heap.size ήταν περίπου ίση με τη μνήμη RAM) και ορισμένες λειτουργίες εκτός σωρού διακόπηκαν με σφάλμα εκχώρησης μνήμης, εάν για κάποιο λόγο δεν χωρούσαν στα ~500 MB που παρέμεναν πριν από το όριο.

Η επιδιόρθωση ήταν αρκετά ασήμαντη: η ποσότητα της διαθέσιμης μνήμης RAM για το κοντέινερ αυξήθηκε, μετά την οποία ξεχάσαμε ότι είχαμε ακόμη και τέτοια προβλήματα.

Πρόβλημα δεύτερο
4-5 ημέρες μετά την εκκίνηση του συμπλέγματος, παρατηρήσαμε ότι οι κόμβοι δεδομένων άρχισαν να πέφτουν περιοδικά από το σύμπλεγμα και να εισέρχονται σε αυτό μετά από 10-20 δευτερόλεπτα.

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

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

Η λύση ήταν η εξής: περιορίσαμε τη δυνατότητα της Java να χρησιμοποιεί το μεγαλύτερο μέρος της μνήμης εκτός του σωρού για αυτές τις λειτουργίες. Το περιορίσαμε στα 16 gigabyte (-XX:MaxDirectMemorySize=16g), διασφαλίζοντας ότι το ρητό GC καλούνταν πολύ πιο συχνά και επεξεργαζόταν πολύ πιο γρήγορα, με αποτέλεσμα να μην αποσταθεροποιείται πλέον το σύμπλεγμα.

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

Όταν διαμορφώσαμε την εργασία με ευρετήρια, επιλέξαμε mmapfs να μείωση του χρόνου αναζήτησης σε φρέσκα θραύσματα με μεγάλη κατάτμηση. Αυτό ήταν μια μεγάλη γκάφα, γιατί όταν χρησιμοποιείτε mmapfs το αρχείο αντιστοιχίζεται στη μνήμη RAM και στη συνέχεια εργαζόμαστε με το αντιστοιχισμένο αρχείο. Εξαιτίας αυτού, αποδεικνύεται ότι όταν το GC προσπαθεί να σταματήσει τα νήματα στην εφαρμογή, πηγαίνουμε στο ασφαλές σημείο για πολύ μεγάλο χρονικό διάστημα και στο δρόμο προς αυτό, η εφαρμογή σταματά να ανταποκρίνεται στα αιτήματα του πλοιάρχου σχετικά με το αν είναι ζωντανός . Κατά συνέπεια, ο κύριος πιστεύει ότι ο κόμβος δεν υπάρχει πλέον στο σύμπλεγμα. Μετά από αυτό, μετά από 5-10 δευτερόλεπτα, ο συλλέκτης σκουπιδιών λειτουργεί, ο κόμβος ζωντανεύει, εισέρχεται ξανά στο σύμπλεγμα και αρχίζει να προετοιμάζει τα θραύσματα. Έμοιαζε πολύ σαν «η παραγωγή που μας άξιζε» και δεν ήταν κατάλληλο για τίποτα σοβαρό.

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

Πρόβλημα τέταρτο
Στη συνέχεια, υπήρχε ένα άλλο πολύ ενδιαφέρον πρόβλημα που αντιμετωπίσαμε για χρόνο ρεκόρ. Το πιάσαμε 2-3 μήνες γιατί το μοτίβο του ήταν απολύτως ακατανόητο.

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

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

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

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

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

Εδώ τελείωσαν τα προβλήματα με την Java και άρχισαν τα προβλήματα εύρους ζώνης.

"Μούρα" με Elasticsearch: απόδοση

Elasticsearch cluster 200 TB+

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

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

Αυτό οφειλόταν στο γεγονός ότι το thread_pool.write.queue σε έναν κόμβο δεδομένων, μέχρι τη στιγμή που το Elasticsearch μπορέσει να επεξεργαστεί το αίτημα δημιουργίας ευρετηρίου και να ανεβάσει τις πληροφορίες στο θραύσμα στο δίσκο, μπορεί να αποθηκεύσει προσωρινά μόνο 200 αιτήματα από προεπιλογή. Και στο Τεκμηρίωση Elasticsearch Πολύ λίγα λέγονται για αυτήν την παράμετρο. Υποδεικνύεται μόνο ο μέγιστος αριθμός νημάτων και το προεπιλεγμένο μέγεθος.

Φυσικά, πήγαμε να στρίψουμε αυτήν την τιμή και ανακαλύψαμε τα εξής: συγκεκριμένα, στο setup μας, έως και 300 αιτήματα αποθηκεύονται αρκετά καλά στην προσωρινή μνήμη και μια υψηλότερη τιμή είναι γεμάτη με το γεγονός ότι πετάμε ξανά στο Full GC.

Επιπλέον, δεδομένου ότι πρόκειται για παρτίδες μηνυμάτων που φτάνουν εντός ενός αιτήματος, ήταν απαραίτητο να τροποποιήσετε το Graylog έτσι ώστε να μην γράφει συχνά και σε μικρές παρτίδες, αλλά σε τεράστιες παρτίδες ή μία φορά κάθε 3 δευτερόλεπτα εάν η παρτίδα εξακολουθεί να μην έχει ολοκληρωθεί. Σε αυτή την περίπτωση, αποδεικνύεται ότι οι πληροφορίες που γράφουμε στο Elasticsearch γίνονται διαθέσιμες όχι σε δύο δευτερόλεπτα, αλλά σε πέντε (που μας ταιριάζουν αρκετά), αλλά στον αριθμό των retrays που πρέπει να γίνουν για να προωθήσουμε ένα μεγάλο η στοίβα πληροφοριών μειώνεται.

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

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

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

Αλλά αυτό θα μπορούσε εν μέρει να παρακαμφθεί λόγω του γεγονότος ότι στις έκτη εκδόσεις του Elasticsearch, εμφανίστηκε ένας αλγόριθμος που σας επιτρέπει να διανέμετε ερωτήματα μεταξύ σχετικών κόμβων δεδομένων όχι σύμφωνα με την αρχή του τυχαίου round-robin (το κοντέινερ που κάνει ευρετηρίαση και κατέχει την κύρια -το θραύσμα μπορεί να είναι πολύ απασχολημένο, δεν θα υπάρχει τρόπος να απαντήσετε γρήγορα), αλλά για να προωθήσετε αυτό το αίτημα σε ένα λιγότερο φορτωμένο κοντέινερ με ένα αντίγραφο, το οποίο θα ανταποκριθεί πολύ πιο γρήγορα. Με άλλα λόγια, φτάσαμε στο use_adaptive_replica_selection: true.

Η εικόνα ανάγνωσης αρχίζει να μοιάζει με αυτό:

Elasticsearch cluster 200 TB+

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

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

Τι θέλαμε από το σύμπλεγμα αμέσως μετά την απώλεια της σύνδεσης με ένα DC:

  • Εάν έχουμε ένα τρέχον κύριο στο αποτυχημένο κέντρο δεδομένων, τότε θα επιλεχθεί ξανά και θα μετακινηθεί ως ρόλος σε έναν άλλο κόμβο σε άλλο DC.
  • Ο κύριος θα αφαιρέσει γρήγορα όλους τους μη προσβάσιμους κόμβους από το σύμπλεγμα.
  • Με βάση τα υπόλοιπα, θα καταλάβει: στο χαμένο κέντρο δεδομένων είχαμε τέτοια και τέτοια κύρια θραύσματα, θα προωθήσει γρήγορα συμπληρωματικά θραύσματα ρεπλίκα στα υπόλοιπα κέντρα δεδομένων και θα συνεχίσουμε να ευρετηριάζουμε τα δεδομένα.
  • Ως αποτέλεσμα αυτού, η απόδοση γραφής και ανάγνωσης του συμπλέγματος θα υποβαθμιστεί σταδιακά, αλλά γενικά όλα θα λειτουργούν, αν και αργά, αλλά σταθερά.

Όπως αποδείχθηκε, θέλαμε κάτι σαν αυτό:

Elasticsearch cluster 200 TB+

Και πήραμε τα εξής:

Elasticsearch cluster 200 TB+

Πώς συνέβη?

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

Γιατί;

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

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

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

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

Πραγματοποιήσαμε μετρήσεις και πριν από την έκδοση 6.4.0, όπου αυτό διορθώθηκε, αρκούσε να εξάγουμε ταυτόχρονα μόνο 10 κόμβους δεδομένων από τους 360, προκειμένου να κλείσουμε εντελώς το σύμπλεγμα.

Έμοιαζε κάπως έτσι:

Elasticsearch cluster 200 TB+

Μετά την έκδοση 6.4.0, όπου αυτό το τρομερό σφάλμα διορθώθηκε, οι κόμβοι δεδομένων σταμάτησαν να σκοτώνουν τον κύριο. Αλλά αυτό δεν τον έκανε «πιο έξυπνο». Δηλαδή: όταν εξάγουμε 2, 3 ή 10 (οποιονδήποτε αριθμό εκτός από έναν) κόμβους δεδομένων, ο κύριος λαμβάνει κάποιο πρώτο μήνυμα που λέει ότι ο κόμβος Α έχει αποχωρήσει και προσπαθεί να ενημερώσει τον κόμβο Β, τον κόμβο Γ σχετικά με αυτό, τον κόμβο D.

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

Κατ 'αρχήν, αυτό ταιριάζει στις απαιτήσεις που παρουσιάστηκαν αρχικά στο τελικό προϊόν ως μέρος του έργου, αλλά από την άποψη της "καθαρής επιστήμης" αυτό είναι ένα σφάλμα. Το οποίο, παρεμπιπτόντως, διορθώθηκε με επιτυχία από τους προγραμματιστές στην έκδοση 7.2.

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

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

Ως αποτέλεσμα, η λειτουργία απόσυρσης ενός κέντρου δεδομένων σήμερα μας παίρνει περίπου 5 λεπτά σε ώρα αιχμής. Για έναν τόσο μεγάλο και αδέξιο κολοσσό, αυτό είναι ένα αρκετά καλό αποτέλεσμα.

Ως αποτέλεσμα, καταλήξαμε στην ακόλουθη απόφαση:

  • Έχουμε 360 κόμβους δεδομένων με δίσκους 700 gigabyte.
  • 60 συντονιστές για τη δρομολόγηση της κυκλοφορίας μέσω αυτών των ίδιων κόμβων δεδομένων.
  • 40 masters που έχουμε αφήσει ως ένα είδος κληρονομιάς από τις εκδόσεις πριν από την 6.4.0 - για να επιβιώσουμε από την απόσυρση του κέντρου δεδομένων, ήμασταν διανοητικά προετοιμασμένοι να χάσουμε πολλά μηχανήματα για να εγγυηθούμε ότι θα έχουμε απαρτία πλοιάρχων ακόμα και σε το χειρότερο σενάριο
  • Οποιεσδήποτε προσπάθειες συνδυασμού ρόλων σε ένα κοντέινερ αντιμετωπίστηκαν με το γεγονός ότι αργά ή γρήγορα ο κόμβος θα έσπασε υπό φορτίο.
  • Ολόκληρο το σύμπλεγμα χρησιμοποιεί ένα heap.size 31 gigabyte: όλες οι προσπάθειες μείωσης του μεγέθους είχαν ως αποτέλεσμα είτε να σκοτωθούν ορισμένοι κόμβοι σε βαριά ερωτήματα αναζήτησης με τον κορυφαίο χαρακτήρα μπαλαντέρ είτε να αποκτήσουν τον διακόπτη κυκλώματος στο ίδιο το Elasticsearch.
  • Επιπλέον, για να διασφαλίσουμε την απόδοση αναζήτησης, προσπαθήσαμε να διατηρήσουμε τον αριθμό των αντικειμένων στο σύμπλεγμα όσο το δυνατόν μικρότερο, προκειμένου να επεξεργαστούμε όσο το δυνατόν λιγότερα συμβάντα στο σημείο συμφόρησης που είχαμε στο κύριο.

Τέλος για την παρακολούθηση

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

  • Κάθε κόμβος δεδομένων αναφέρει στο σύννεφο μας ότι υπάρχει και υπάρχουν τέτοια και τέτοια θραύσματα σε αυτόν. Όταν σβήνουμε κάτι κάπου, το σύμπλεγμα αναφέρει μετά από 2-3 δευτερόλεπτα ότι στο κέντρο Α σβήσαμε τους κόμβους 2, 3 και 4 - αυτό σημαίνει ότι σε άλλα κέντρα δεδομένων δεν μπορούμε σε καμία περίπτωση να σβήσουμε εκείνους τους κόμβους στους οποίους υπάρχει μόνο ένα θραύσμα αριστερά.
  • Γνωρίζοντας τη φύση της συμπεριφοράς του πλοιάρχου, εξετάζουμε πολύ προσεκτικά τον αριθμό των εκκρεμών εργασιών. Επειδή ακόμη και μια κολλημένη εργασία, εάν δεν λήξει εγκαίρως, θεωρητικά σε κάποια κατάσταση έκτακτης ανάγκης μπορεί να γίνει ο λόγος για τον οποίο, για παράδειγμα, η προώθηση ενός θραύσματος ρεπλίκα στο πρωτεύον δεν λειτουργεί, γι' αυτό η ευρετηρίαση θα σταματήσει να λειτουργεί.
  • Εξετάζουμε επίσης πολύ προσεκτικά τις καθυστερήσεις συλλογής σκουπιδιών, επειδή είχαμε ήδη μεγάλες δυσκολίες με αυτό κατά τη βελτιστοποίηση.
  • Απορρίπτει με νήμα για να καταλάβει εκ των προτέρων πού βρίσκεται το σημείο συμφόρησης.
  • Λοιπόν, τυπικές μετρήσεις όπως σωρό, RAM και I/O.

Κατά τη δημιουργία παρακολούθησης, πρέπει να λάβετε υπόψη τις δυνατότητες του Thread Pool στο Elasticsearch. Τεκμηρίωση Elasticsearch περιγράφει τις επιλογές διαμόρφωσης και τις προεπιλεγμένες τιμές για αναζήτηση και ευρετηρίαση, αλλά είναι εντελώς σιωπηλή σχετικά με το thread_pool.management. Αυτά τα νήματα επεξεργάζονται, συγκεκριμένα, ερωτήματα όπως _cat/shards και άλλα παρόμοια, τα οποία είναι βολικά στη χρήση κατά τη σύνταξη παρακολούθησης. Όσο μεγαλύτερο είναι το σύμπλεγμα, τόσο περισσότερα τέτοια αιτήματα εκτελούνται ανά μονάδα χρόνου και το προαναφερθέν thread_pool.management όχι μόνο δεν παρουσιάζεται στην επίσημη τεκμηρίωση, αλλά περιορίζεται επίσης από προεπιλογή σε 5 νήματα, τα οποία καταργούνται πολύ γρήγορα, μετά η οποία παρακολούθηση σταματά να λειτουργεί σωστά.

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

Ναι, αποδείχθηκε αρκετά περίπλοκο, αλλά, παρόλα αυτά, καταφέραμε να χωρέσουμε τις επιθυμίες μας σε υπάρχοντα προϊόντα, τα οποία δεν χρειάστηκε να επιδιορθώσουμε και να ξαναγράψουμε μόνοι μας.

Elasticsearch cluster 200 TB+

Πηγή: www.habr.com

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