Πώς μειώσαμε την καθυστέρηση στο Keen IO

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

Η πλατφόρμα Keen IO επεξεργάζεται καθημερινά εκατομμύρια ερωτήματα adoc και μαζικά, διατηρώντας παράλληλα χρόνο λειτουργίας 99,9%+.

Βελτιωμένοι χρόνοι απόκρισης ερωτημάτων

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

Βελτιωμένη συνέπεια ερωτημάτων

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

Η μαγεία της προσωρινής αποθήκευσης

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

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

Εξέλιξη προσωρινής αποθήκευσης ερωτημάτων

Στο χαμηλότερο επίπεδο έχουμε έναν στόλο εργαζομένων (εντός του Apache Storm) υπεύθυνους για τον υπολογισμό των αποτελεσμάτων ερωτημάτων. Οποιοδήποτε ερώτημα μπορεί να θεωρηθεί ως συνάρτηση που επεξεργάζεται συμβάντα.

Query = function(events)

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

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

(Απλοποιημένη προβολή ερωτήματος υπό επεξεργασία)

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

Ακύρωση προσωρινής μνήμης

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

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

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

  1. Προστέθηκε μια χρονική σήμανση last-updated-at σε κάθε καταχώρηση προσωρινής μνήμης και
  2. Ρύθμιση memcached για εξαγωγή δεδομένων με βάση έναν αλγόριθμο LRU.

Το σχήμα που χρησιμοποιήσαμε για την αποθήκευση συμβάντων ήταν περίπου το εξής:

Cache Key = collection_name+bucket_id+bucket_last_updated_at_

Cache Value = bucket (or an array of events)

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

Έτσι, η πρώτη μας επανάληψη της κρυφής μνήμης έμοιαζε κάπως ως εξής:

(Query Caching V1)

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

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

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

(Query Caching V2)

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

(Βελτιωμένο ποσοστό επισκέψεων στην κρυφή μνήμη μετά την κυκλοφορία κατανεμημένης προσωρινής αποθήκευσης)

Βελτίωση της συνέπειας ερωτημάτων

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

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

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

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