Όπως στο
Μια μέρα ξύπνησα με ένα δυσαρεστημένο email λόγω μεγάλων καθυστερήσεων με τον Alvin, το οποίο σχεδιάζαμε να κυκλοφορήσουμε στο εγγύς μέλλον. Συγκεκριμένα, ο πελάτης αντιμετώπισε καθυστέρηση 99ου εκατοστημόριου στην περιοχή των 50 ms, πολύ πάνω από τον προϋπολογισμό μας για λανθάνουσα κατάσταση. Αυτό ήταν εκπληκτικό καθώς δοκίμασα την υπηρεσία εκτενώς, ειδικά σε λανθάνουσα κατάσταση, που είναι ένα κοινό παράπονο.
Πριν βάλω τον Alvin σε δοκιμές, έκανα πολλά πειράματα με 40 ερωτήματα ανά δευτερόλεπτο (QPS), όλα δείχνουν λανθάνουσα κατάσταση μικρότερη από 10 ms. Ήμουν έτοιμος να δηλώσω ότι δεν συμφωνώ με τα αποτελέσματά τους. Αλλά ρίχνοντας μια άλλη ματιά στην επιστολή, παρατήρησα κάτι νέο: δεν είχα δοκιμάσει ακριβώς τις συνθήκες που ανέφεραν, το QPS τους ήταν πολύ χαμηλότερο από το δικό μου. Δοκίμασα σε 40k QPS, αλλά αυτά μόνο σε 1k. Έκανα ένα άλλο πείραμα, αυτή τη φορά με χαμηλότερο QPS, μόνο και μόνο για να τους κατευνάσω.
Εφόσον γράφω για αυτό το blog, πιθανότατα έχετε ήδη καταλάβει ότι οι αριθμοί τους ήταν σωστοί. Δοκίμασα τον εικονικό πελάτη μου ξανά και ξανά, με το ίδιο αποτέλεσμα: ένας χαμηλός αριθμός αιτημάτων όχι μόνο αυξάνει τον λανθάνοντα χρόνο, αλλά αυξάνει τον αριθμό των αιτημάτων με καθυστέρηση μεγαλύτερη από 10 ms. Με άλλα λόγια, εάν στα 40k QPS περίπου 50 αιτήματα ανά δευτερόλεπτο υπερέβαιναν τα 50 ms, τότε σε 1k QPS υπήρχαν 100 αιτήματα άνω των 50 ms κάθε δευτερόλεπτο. Παράδοξο!
Περιορίζοντας την αναζήτηση
Όταν αντιμετωπίζετε ένα πρόβλημα καθυστέρησης σε ένα κατανεμημένο σύστημα με πολλά στοιχεία, το πρώτο βήμα είναι να δημιουργήσετε μια σύντομη λίστα υπόπτων. Ας σκάψουμε λίγο πιο βαθιά στην αρχιτεκτονική του Alvin:
Ένα καλό σημείο εκκίνησης είναι μια λίστα με ολοκληρωμένες μεταβάσεις εισόδου/εξόδου (κλήσεις δικτύου/αναζητήσεις δίσκου, κ.λπ.). Ας προσπαθήσουμε να καταλάβουμε πού είναι η καθυστέρηση. Εκτός από την προφανή I/O με τον πελάτη, ο Alvin κάνει ένα επιπλέον βήμα: έχει πρόσβαση στο χώρο αποθήκευσης δεδομένων. Ωστόσο, αυτός ο χώρος αποθήκευσης λειτουργεί στο ίδιο σύμπλεγμα με το Alvin, επομένως ο λανθάνοντας χρόνος εκεί θα πρέπει να είναι μικρότερος από τον πελάτη. Λοιπόν, η λίστα των υπόπτων:
- Κλήση δικτύου από πελάτη στον Alvin.
- Κλήση δικτύου από τον Alvin στο χώρο αποθήκευσης δεδομένων.
- Αναζήτηση στο δίσκο στο χώρο αποθήκευσης δεδομένων.
- Κλήση δικτύου από την αποθήκη δεδομένων στον Alvin.
- Κλήση δικτύου από τον Alvin σε έναν πελάτη.
Ας προσπαθήσουμε να διαγράψουμε κάποια σημεία.
Η αποθήκευση δεδομένων δεν έχει καμία σχέση με αυτό
Το πρώτο πράγμα που έκανα ήταν να μετατρέψω τον Alvin σε διακομιστή ping-ping που δεν επεξεργάζεται αιτήματα. Όταν λαμβάνει ένα αίτημα, επιστρέφει μια κενή απάντηση. Εάν η καθυστέρηση μειωθεί, τότε ένα σφάλμα στην υλοποίηση του Alvin ή της αποθήκης δεδομένων δεν είναι κάτι πρωτόγνωρο. Στο πρώτο πείραμα έχουμε το ακόλουθο γράφημα:
Όπως μπορείτε να δείτε, δεν υπάρχει καμία βελτίωση κατά τη χρήση του διακομιστή ping-ping. Αυτό σημαίνει ότι η αποθήκη δεδομένων δεν αυξάνει την καθυστέρηση και η λίστα των υπόπτων μειώνεται στο μισό:
- Κλήση δικτύου από πελάτη στον Alvin.
- Κλήση δικτύου από τον Alvin σε έναν πελάτη.
Εξαιρετική! Η λίστα συρρικνώνεται γρήγορα. Νόμιζα ότι είχα σχεδόν καταλάβει τον λόγο.
gRPC
Τώρα είναι η ώρα να σας παρουσιάσουμε έναν νέο παίκτη: gRPC
καλά βελτιστοποιημένο και ευρέως χρησιμοποιημένο, αυτή ήταν η πρώτη μου φορά που το χρησιμοποιούσα σε ένα σύστημα αυτού του μεγέθους και περίμενα ότι η υλοποίησή μου δεν θα ήταν βέλτιστη - το λιγότερο.
διαθεσιμότητα gRPC
στη στοίβα δημιούργησε μια νέα ερώτηση: ίσως είναι η εφαρμογή μου ή εγώ gRPC
προκαλεί πρόβλημα καθυστέρησης; Προσθήκη νέου υπόπτου στη λίστα:
- Ο πελάτης καλεί τη βιβλιοθήκη
gRPC
- Βιβλιοθήκη
gRPC
πραγματοποιεί μια κλήση δικτύου στη βιβλιοθήκη του πελάτηgRPC
στο διακομιστή - Βιβλιοθήκη
gRPC
επαφές Alvin (καμία λειτουργία σε περίπτωση διακομιστή πινγκ-πονγκ)
Για να σας δώσω μια ιδέα για το πώς φαίνεται ο κώδικας, η εφαρμογή πελάτη μου/Alvin δεν διαφέρει πολύ από την εφαρμογή πελάτη-διακομιστή
Σημείωση: Η παραπάνω λίστα είναι λίγο απλοποιημένη γιατί
gRPC
καθιστά δυνατή τη χρήση του δικού σας μοντέλου νήματος (πρότυπο;), στο οποίο η στοίβα εκτέλεσης είναι συνυφασμένηgRPC
και υλοποίηση χρήστη. Για λόγους απλότητας, θα παραμείνουμε σε αυτό το μοντέλο.
Το προφίλ θα διορθώσει τα πάντα
Έχοντας διαγράψει τις αποθήκες δεδομένων, νόμιζα ότι είχα σχεδόν τελειώσει: «Τώρα είναι εύκολο! Ας εφαρμόσουμε το προφίλ και ας μάθουμε πού συμβαίνει η καθυστέρηση." Εγώ
Πήρα τέσσερα προφίλ: με υψηλό QPS (χαμηλή καθυστέρηση) και με διακομιστή πινγκ πονγκ με χαμηλό QPS (υψηλή καθυστέρηση), τόσο από την πλευρά του πελάτη όσο και από την πλευρά του διακομιστή. Και για παν ενδεχόμενο, πήρα και δείγμα προφίλ επεξεργαστή. Όταν συγκρίνω προφίλ, συνήθως αναζητώ μια ανώμαλη στοίβα κλήσεων. Για παράδειγμα, στην κακή πλευρά με τον υψηλό λανθάνοντα χρόνο υπάρχουν πολλοί περισσότεροι διακόπτες περιβάλλοντος (10 φορές ή περισσότεροι). Αλλά στην περίπτωσή μου, ο αριθμός των διακοπτών περιβάλλοντος ήταν σχεδόν ο ίδιος. Προς φρίκη μου, δεν υπήρχε τίποτα σημαντικό εκεί.
Πρόσθετος εντοπισμός σφαλμάτων
Ήμουν απελπισμένος. Δεν ήξερα ποια άλλα εργαλεία θα μπορούσα να χρησιμοποιήσω και το επόμενο σχέδιό μου ήταν ουσιαστικά να επαναλάβω τα πειράματα με διαφορετικές παραλλαγές αντί να διαγνώσω ξεκάθαρα το πρόβλημα.
Κι αν
Από την αρχή με απασχολούσε το συγκεκριμένο latency των 50ms. Αυτή είναι μια πολύ μεγάλη στιγμή. Αποφάσισα ότι θα κόψω κομμάτια από τον κώδικα μέχρι να καταλάβω ποιο ακριβώς τμήμα προκαλεί αυτό το σφάλμα. Μετά ήρθε ένα πείραμα που πέτυχε.
Ως συνήθως, εκ των υστέρων φαίνεται ότι όλα ήταν προφανή. Τοποθέτησα τον πελάτη στο ίδιο μηχάνημα με τον Alvin - και έστειλα ένα αίτημα localhost
. Και η αύξηση της καθυστέρησης έχει φύγει!
Κάτι δεν πήγαινε καλά με το δίκτυο.
Εκμάθηση δεξιοτήτων μηχανικού δικτύου
Πρέπει να ομολογήσω: οι γνώσεις μου για τις τεχνολογίες δικτύου είναι τρομερές, ειδικά αν λάβουμε υπόψη το γεγονός ότι εργάζομαι μαζί τους καθημερινά. Αλλά το δίκτυο ήταν ο κύριος ύποπτος και έπρεπε να μάθω πώς να το διορθώνω.
Ευτυχώς, το Διαδίκτυο αγαπά όσους θέλουν να μάθουν. Ο συνδυασμός ping και tracert φαινόταν σαν μια αρκετά καλή αρχή για τον εντοπισμό σφαλμάτων των προβλημάτων μεταφοράς δικτύου.
Πρώτον, ξεκίνησα
Μετά προσπάθησα
Επομένως, δεν ήταν ο κώδικάς μου, η εφαρμογή του gRPC ή το δίκτυο που προκαλούσε την καθυστέρηση. Είχα αρχίσει να ανησυχώ ότι δεν θα το καταλάβαινα ποτέ αυτό.
Τώρα σε ποιο λειτουργικό σύστημα είμαστε
gRPC
χρησιμοποιείται ευρέως στο Linux, αλλά εξωτικό στα Windows. Αποφάσισα να δοκιμάσω ένα πείραμα, το οποίο λειτούργησε: Δημιούργησα μια εικονική μηχανή Linux, μεταγλωττίζω το Alvin για Linux και το ανέπτυξα.
Και να τι συνέβη: ο διακομιστής πινγκ-πονγκ Linux δεν είχε τις ίδιες καθυστερήσεις με έναν παρόμοιο κεντρικό υπολογιστή των Windows, αν και η πηγή δεδομένων δεν ήταν διαφορετική. Αποδεικνύεται ότι το πρόβλημα βρίσκεται στην εφαρμογή gRPC για Windows.
Ο αλγόριθμος του Nagle
Όλο αυτό το διάστημα νόμιζα ότι μου έλειπε μια σημαία gRPC
. Τώρα καταλαβαίνω τι είναι πραγματικά gRPC
Η σημαία των Windows λείπει. Βρήκα μια εσωτερική βιβλιοθήκη RPC που ήμουν σίγουρος ότι θα λειτουργούσε καλά για όλες τις σημαίες που είχαν οριστεί
Σχεδόν Έγινε: Άρχισα να αφαιρώ τις πρόσθετες σημαίες μία κάθε φορά μέχρι να επιστρέψει η παλινδρόμηση, ώστε να μπορέσω να εντοπίσω την αιτία. Ήταν διαβόητο
gRPC
Αυτή η σημαία ορίστηκε στην εφαρμογή Linux για υποδοχές TCP, αλλά όχι στα Windows. Είμαι αυτό
Συμπέρασμα
Η υψηλότερη καθυστέρηση σε χαμηλό QPS προκλήθηκε από τη βελτιστοποίηση του λειτουργικού συστήματος. Εκ των υστέρων, το προφίλ δεν εντόπισε λανθάνουσα κατάσταση επειδή έγινε σε λειτουργία πυρήνα και όχι σε
Όσον αφορά το πείραμα του localhost, πιθανότατα δεν άγγιξε τον πραγματικό κώδικα δικτύωσης και ο αλγόριθμος του Nagle δεν εκτελούσε, επομένως τα ζητήματα λανθάνοντος χρόνου εξαφανίστηκαν όταν ο πελάτης έφτασε στον Alvin μέσω του localhost.
Την επόμενη φορά που θα δείτε αύξηση του λανθάνοντος χρόνου καθώς μειώνεται ο αριθμός των αιτημάτων ανά δευτερόλεπτο, ο αλγόριθμος του Nagle θα πρέπει να είναι στη λίστα των υπόπτων σας!
Πηγή: www.habr.com