Bioyino - κατανεμημένος, κλιμακούμενος συσσωρευτής μετρήσεων

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

Bioyino - κατανεμημένος, κλιμακούμενος συσσωρευτής μετρήσεων

Από προηγούμενα άρθρα μας (1, 2) μπορείτε να μάθετε ότι μέχρι κάποιο χρονικό διάστημα συλλέγαμε βαθμούς χρησιμοποιώντας Μπρούμπεκ. Είναι γραμμένο σε C. Από την άποψη του κώδικα, είναι τόσο απλό όσο ένα βύσμα (αυτό είναι σημαντικό όταν θέλετε να συνεισφέρετε) και, το πιο σημαντικό, χειρίζεται τους όγκους μας των 2 εκατομμυρίων μετρήσεων ανά δευτερόλεπτο (MPS) στο μέγιστο χωρίς κανένα πρόβλημα. Η τεκμηρίωση αναφέρει υποστήριξη για 4 εκατομμύρια MPS με αστερίσκο. Αυτό σημαίνει ότι θα λάβετε τον αναφερόμενο αριθμό εάν ρυθμίσετε σωστά το δίκτυο στο Linux. (Δεν ξέρουμε πόσα MPS μπορείτε να πάρετε αν αφήσετε το δίκτυο ως έχει). Παρά αυτά τα πλεονεκτήματα, είχαμε αρκετά σοβαρά παράπονα για το μπρούμπεκ.

Αξίωση 1. Ο Github, ο προγραμματιστής του έργου, σταμάτησε να το υποστηρίζει: δημοσιεύει ενημερώσεις κώδικα και διορθώσεις, αποδέχεται τα δικά μας και (όχι μόνο τα δικά μας) PR. Τους τελευταίους μήνες (κάπου από τον Φεβρουάριο-Μάρτιο του 2018), η δραστηριότητα επανήλθε, αλλά πριν από αυτό υπήρχαν σχεδόν 2 χρόνια απόλυτης ηρεμίας. Επιπλέον, το έργο βρίσκεται σε εξέλιξη για εσωτερικές ανάγκες Gihub, το οποίο μπορεί να αποτελέσει σοβαρό εμπόδιο για την εισαγωγή νέων λειτουργιών.

Αξίωση 2. Ακρίβεια υπολογισμών. Το Brubeck συλλέγει συνολικά 65536 τιμές για συνάθροιση. Στην περίπτωσή μας, για ορισμένες μετρήσεις, κατά τη διάρκεια της περιόδου συγκέντρωσης (30 δευτερόλεπτα), μπορεί να φτάσουν πολύ περισσότερες τιμές (1 στην κορυφή). Ως αποτέλεσμα αυτής της δειγματοληψίας, οι μέγιστες και ελάχιστες τιμές φαίνονται άχρηστες. Για παράδειγμα, όπως αυτό:

Bioyino - κατανεμημένος, κλιμακούμενος συσσωρευτής μετρήσεων
Οπως ήταν

Bioyino - κατανεμημένος, κλιμακούμενος συσσωρευτής μετρήσεων
Πώς έπρεπε να ήταν

Για τον ίδιο λόγο, τα ποσά γενικά υπολογίζονται λανθασμένα. Προσθέστε εδώ ένα σφάλμα με υπερχείλιση float 32-bit, το οποίο γενικά στέλνει τον διακομιστή σε segfault όταν λαμβάνει μια φαινομενικά αθώα μέτρηση και όλα γίνονται υπέροχα. Το σφάλμα, παρεμπιπτόντως, δεν έχει διορθωθεί.

Και, τελικά, Αξίωση X. Τη στιγμή που γράφονται αυτές οι γραμμές, είμαστε έτοιμοι να το παρουσιάσουμε και στις 14 περισσότερο ή λιγότερο λειτουργικές υλοποιήσεις statsd που μπορέσαμε να βρούμε. Ας φανταστούμε ότι κάποια μεμονωμένη υποδομή έχει μεγαλώσει τόσο πολύ που η αποδοχή 4 εκατομμυρίων MPS δεν αρκεί πλέον. Ή ακόμα κι αν δεν έχει αυξηθεί ακόμα, αλλά οι μετρήσεις είναι ήδη τόσο σημαντικές για εσάς που ακόμη και σύντομες, 2-3 λεπτά πτώσεις στα γραφήματα μπορεί να γίνουν ήδη κρίσιμες και να προκαλέσουν κρίσεις ανυπέρβλητης κατάθλιψης μεταξύ των διευθυντών. Δεδομένου ότι η θεραπεία της κατάθλιψης είναι μια άχαρη εργασία, απαιτούνται τεχνικές λύσεις.

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

Επειδή είχαμε χώρο για κλιμάκωση, αποφασίσαμε να ξεκινήσουμε με την ανοχή σφαλμάτων. "ΣΧΕΤΙΚΑ ΜΕ! Ανοχή σε σφάλματα! Είναι απλό, μπορούμε να το κάνουμε», σκεφτήκαμε και ξεκινήσαμε 2 διακομιστές, σηκώνοντας ένα αντίγραφο του brubeck στον καθένα. Για να γίνει αυτό, έπρεπε να αντιγράψουμε την κυκλοφορία με μετρήσεις και στους δύο διακομιστές και ακόμη και να γράψουμε για αυτό μικρή χρησιμότητα. Λύσαμε το πρόβλημα ανοχής σφαλμάτων με αυτό, αλλά... όχι πολύ καλά. Στην αρχή όλα φαίνονταν υπέροχα: κάθε brubeck συλλέγει τη δική του έκδοση συνάθροισης, γράφει δεδομένα στο Graphite μία φορά κάθε 30 δευτερόλεπτα, αντικαθιστώντας το παλιό διάστημα (αυτό γίνεται στην πλευρά Graphite). Εάν ένας διακομιστής αποτύχει ξαφνικά, έχουμε πάντα έναν δεύτερο με το δικό του αντίγραφο των συγκεντρωτικών δεδομένων. Αλλά εδώ είναι το πρόβλημα: εάν ο διακομιστής αποτύχει, εμφανίζεται ένα "πριόνι" στα γραφήματα. Αυτό οφείλεται στο γεγονός ότι τα διαστήματα των 30 δευτερολέπτων του brubeck δεν συγχρονίζονται και τη στιγμή της συντριβής ένα από αυτά δεν αντικαθίσταται. Όταν ξεκινά ο δεύτερος διακομιστής, συμβαίνει το ίδιο. Αρκετά ανεκτό, αλλά θέλω καλύτερα! Το πρόβλημα της επεκτασιμότητας επίσης δεν έχει εξαφανιστεί. Όλες οι μετρήσεις εξακολουθούν να «πετούν» σε έναν μόνο διακομιστή και επομένως περιοριζόμαστε στα ίδια 2-4 εκατομμύρια MPS, ανάλογα με το επίπεδο δικτύου.

Εάν σκεφτείτε λίγο το πρόβλημα και ταυτόχρονα σκάβετε χιόνι με ένα φτυάρι, τότε μπορεί να σας έρθει στο μυαλό η εξής προφανής ιδέα: χρειάζεστε ένα statsd που μπορεί να λειτουργήσει σε κατανεμημένη λειτουργία. Δηλαδή, ένα που υλοποιεί συγχρονισμό μεταξύ κόμβων σε χρόνο και μετρήσεις. «Φυσικά, μια τέτοια λύση μάλλον υπάρχει ήδη», είπαμε και πήγαμε στο Google…. Και δεν βρήκαν τίποτα. Αφού διαβάσετε την τεκμηρίωση για διαφορετικά statsd (https://github.com/etsy/statsd/wiki#server-implementations από τις 11.12.2017 Δεκεμβρίου XNUMX), δεν βρήκαμε απολύτως τίποτα. Προφανώς, ούτε οι προγραμματιστές ούτε οι χρήστες αυτών των λύσεων έχουν αντιμετωπίσει ΤΟΣΕΣ πολλές μετρήσεις, διαφορετικά σίγουρα θα καταλήξουν σε κάτι.

Και μετά θυμηθήκαμε το «παιχνίδι» statsd - bioyino, το οποίο γράφτηκε στο Just for Fun hackathon (το όνομα του έργου δημιουργήθηκε από το σενάριο πριν από την έναρξη του hackathon) και συνειδητοποιήσαμε ότι χρειαζόμασταν επειγόντως το δικό μας statsd. Για τι?

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

Σε τι να γράψω; Φυσικά, στο Rust. Γιατί;

  • επειδή υπήρχε ήδη μια πρωτότυπη λύση,
  • επειδή ο συγγραφέας του άρθρου γνώριζε ήδη τον Rust εκείνη την εποχή και ήθελε να γράψει κάτι σε αυτό για παραγωγή με την ευκαιρία να το βάλει σε ανοιχτό κώδικα,
  • επειδή οι γλώσσες με GC δεν είναι κατάλληλες για εμάς λόγω της φύσης της λαμβανόμενης κίνησης (σχεδόν σε πραγματικό χρόνο) και οι παύσεις GC είναι πρακτικά απαράδεκτες,
  • γιατί χρειάζεστε μέγιστη απόδοση συγκρίσιμη με το C
  • γιατί το Rust μάς παρέχει άφοβο συγχρονισμό και αν ξεκινούσαμε να το γράφουμε σε C/C++, θα είχαμε ακόμα περισσότερα τρωτά σημεία, υπερχείλιση buffer, συνθήκες αγώνα και άλλες τρομακτικές λέξεις από το brubeck.

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

Η ώρα πέρασε...

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

Bioyino - κατανεμημένος, κλιμακούμενος συσσωρευτής μετρήσεων

Κάθε κόμβος λαμβάνει το δικό του σύνολο μετρήσεων και τις συσσωρεύει και δεν συγκεντρώνει μετρήσεις για εκείνους τους τύπους όπου απαιτείται το πλήρες σύνολο τους για την τελική συγκέντρωση. Οι κόμβοι συνδέονται μεταξύ τους με κάποιο είδος κατανεμημένου πρωτοκόλλου κλειδώματος, το οποίο σας επιτρέπει να επιλέξετε μεταξύ τους το μόνο (εδώ κλάψαμε) που αξίζει να στείλετε μετρήσεις στο Great One. Αυτό το πρόβλημα επιλύεται αυτήν τη στιγμή από Πρόξενος, αλλά στο μέλλον οι φιλοδοξίες του συγγραφέα επεκτείνονται σε τα δικά εκτέλεση Σχεδία, όπου ο πιο άξιος θα είναι, φυσικά, ο κόμβος ηγέτης της συναίνεσης. Εκτός από τη συναίνεση, οι κόμβοι αρκετά συχνά (μια φορά το δευτερόλεπτο από προεπιλογή) στέλνουν στους γείτονές τους εκείνα τα μέρη των προ-συγκεντρωμένων μετρήσεων που κατάφεραν να συλλέξουν σε αυτό το δευτερόλεπτο. Αποδεικνύεται ότι η κλιμάκωση και η ανοχή σφαλμάτων διατηρούνται - κάθε κόμβος εξακολουθεί να διατηρεί ένα πλήρες σύνολο μετρήσεων, αλλά οι μετρήσεις αποστέλλονται ήδη συγκεντρωμένες, μέσω TCP και κωδικοποιούνται σε ένα δυαδικό πρωτόκολλο, επομένως το κόστος αντιγραφής μειώνεται σημαντικά σε σύγκριση με το UDP. Παρά τον αρκετά μεγάλο αριθμό εισερχόμενων μετρήσεων, η συσσώρευση απαιτεί πολύ λίγη μνήμη και ακόμη λιγότερη CPU. Για τους εξαιρετικά συμπιεστούς δείκτες μας, αυτό είναι μόνο μερικές δεκάδες megabyte δεδομένων. Ως πρόσθετο μπόνους, δεν λαμβάνουμε περιττές επανεγγραφές δεδομένων στο Graphite, όπως συνέβη με το burbeck.

Τα πακέτα UDP με μετρήσεις δεν είναι ισορροπημένα μεταξύ των κόμβων στον εξοπλισμό δικτύου μέσω ενός απλού Round Robin. Φυσικά, το υλικό του δικτύου δεν αναλύει τα περιεχόμενα των πακέτων και επομένως μπορεί να τραβήξει πολύ περισσότερα από 4 εκατομμύρια πακέτα ανά δευτερόλεπτο, για να μην αναφέρουμε μετρήσεις για τις οποίες δεν γνωρίζει απολύτως τίποτα. Αν λάβουμε υπόψη ότι οι μετρήσεις δεν έρχονται μία κάθε φορά σε κάθε πακέτο, τότε δεν προβλέπουμε προβλήματα απόδοσης σε αυτό το μέρος. Εάν ένας διακομιστής διακοπεί, η συσκευή δικτύου γρήγορα (εντός 1-2 δευτερολέπτων) εντοπίζει αυτό το γεγονός και αφαιρεί από την περιστροφή τον διακομιστή που έχει καταρρεύσει. Ως αποτέλεσμα αυτού, οι παθητικοί κόμβοι (δηλαδή, οι μη αρχηγοί) μπορούν να ενεργοποιηθούν και να απενεργοποιηθούν πρακτικά χωρίς να παρατηρήσετε μειώσεις στα γραφήματα. Το μέγιστο που χάνουμε είναι μέρος των μετρήσεων που μπήκαν το τελευταίο δευτερόλεπτο. Μια ξαφνική απώλεια/τερματισμός/αλλαγή ενός ηγέτη θα εξακολουθεί να δημιουργεί μια μικρή ανωμαλία (το διάστημα των 30 δευτερολέπτων εξακολουθεί να είναι εκτός συγχρονισμού), αλλά εάν υπάρχει επικοινωνία μεταξύ των κόμβων, αυτά τα προβλήματα μπορούν να ελαχιστοποιηθούν, για παράδειγμα, στέλνοντας πακέτα συγχρονισμού .

Λίγα λόγια για την εσωτερική δομή. Η εφαρμογή είναι, φυσικά, πολυνηματική, αλλά η αρχιτεκτονική νήματος είναι διαφορετική από αυτή που χρησιμοποιείται στο brubeck. Τα νήματα στο μπρουμπέκ είναι τα ίδια - καθένα από αυτά είναι υπεύθυνο τόσο για τη συλλογή πληροφοριών όσο και για τη συγκέντρωση. Στο bioyino, οι εργαζόμενοι χωρίζονται σε δύο ομάδες: σε αυτούς που είναι υπεύθυνοι για το δίκτυο και σε αυτούς που είναι υπεύθυνοι για τη συγκέντρωση. Αυτή η διαίρεση σάς επιτρέπει να διαχειρίζεστε πιο ευέλικτα την εφαρμογή ανάλογα με τον τύπο των μετρήσεων: όπου απαιτείται εντατική συγκέντρωση, μπορείτε να προσθέσετε aggregators, όπου υπάρχει μεγάλη κίνηση δικτύου, μπορείτε να προσθέσετε τον αριθμό των ροών δικτύου. Αυτή τη στιγμή, στους διακομιστές μας εργαζόμαστε σε 8 ροές δικτύου και 4 αθροίσεις.

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

Πολύ περισσότερα προβλήματα κατά την ανάπτυξη προκλήθηκαν από το τμήμα δικτύου που είναι υπεύθυνο για τη λήψη μετρήσεων. Ο κύριος στόχος του διαχωρισμού των ροών δικτύου σε ξεχωριστές οντότητες ήταν η επιθυμία να μειωθεί ο χρόνος που ξοδεύει μια ροή όχι για να διαβάσετε δεδομένα από την πρίζα. Οι επιλογές που χρησιμοποιούν ασύγχρονο UDP και κανονικό recvmsg εξαφανίστηκαν γρήγορα: η πρώτη καταναλώνει πάρα πολύ χώρο CPU για την επεξεργασία συμβάντων, η δεύτερη απαιτεί πάρα πολλούς διακόπτες περιβάλλοντος. Επομένως χρησιμοποιείται τώρα recvmmsg με μεγάλα buffers (και τα buffer, κύριοι αξιωματικοί, δεν είναι τίποτα για εσάς!). Η υποστήριξη για κανονικό UDP προορίζεται για ελαφριές περιπτώσεις όπου δεν απαιτείται recvmmsg. Στη λειτουργία πολλαπλών μηνυμάτων, είναι δυνατό να επιτευχθεί το κύριο πράγμα: τη συντριπτική πλειονότητα των φορών, το νήμα δικτύου τεντώνει την ουρά του λειτουργικού συστήματος - διαβάζει δεδομένα από την υποδοχή και τα μεταφέρει στην προσωρινή μνήμη χώρου χρηστών, μόνο περιστασιακά αλλάζει στο να δώσει το γεμάτο buffer σε συσσωρευτές. Η ουρά στην υποδοχή πρακτικά δεν συσσωρεύεται, ο αριθμός των πακέτων που πέφτουν ουσιαστικά δεν αυξάνεται.

Σημείωση

Στις προεπιλεγμένες ρυθμίσεις, το μέγεθος του buffer έχει οριστεί να είναι αρκετά μεγάλο. Εάν αποφασίσετε ξαφνικά να δοκιμάσετε μόνοι σας τον διακομιστή, μπορεί να αντιμετωπίσετε το γεγονός ότι μετά την αποστολή ενός μικρού αριθμού μετρήσεων, δεν θα φτάσουν στο Graphite, παραμένοντας στο buffer ροής δικτύου. Για να εργαστείτε με μικρό αριθμό μετρήσεων, πρέπει να ορίσετε το bufsize και το task-queue-size σε μικρότερες τιμές στη διαμόρφωση.

Τέλος, μερικά charts για τους λάτρεις των chart.

Στατιστικά στοιχεία για τον αριθμό των εισερχόμενων μετρήσεων για κάθε διακομιστή: περισσότερα από 2 εκατομμύρια MPS.

Bioyino - κατανεμημένος, κλιμακούμενος συσσωρευτής μετρήσεων

Απενεργοποίηση ενός από τους κόμβους και αναδιανομή εισερχόμενων μετρήσεων.

Bioyino - κατανεμημένος, κλιμακούμενος συσσωρευτής μετρήσεων

Στατιστικά στοιχεία για τις εξερχόμενες μετρήσεις: μόνο ένας κόμβος στέλνει πάντα - το αφεντικό της επιδρομής.

Bioyino - κατανεμημένος, κλιμακούμενος συσσωρευτής μετρήσεων

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

Bioyino - κατανεμημένος, κλιμακούμενος συσσωρευτής μετρήσεων

Λεπτομέρειες των εισερχόμενων μετρήσεων (τα ονόματα των μετρήσεων είναι κρυφά).

Bioyino - κατανεμημένος, κλιμακούμενος συσσωρευτής μετρήσεων

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

Φυσικά, όλοι είναι ευπρόσδεκτοι να βοηθήσουν στην ανάπτυξη του έργου: δημιουργήστε PR, Θέματα, εάν είναι δυνατόν θα απαντήσουμε, θα βελτιώσουμε κ.λπ.

Με αυτό που λέγεται, αυτά είναι όλα παιδιά, αγοράστε τους ελέφαντες μας!



Πηγή: www.habr.com

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