Καθώς περνάμε από μια μονολιθική εφαρμογή σε μια αρχιτεκτονική μικροϋπηρεσιών, αντιμετωπίζουμε νέες προκλήσεις.
Σε μια μονολιθική εφαρμογή, είναι συνήθως αρκετά εύκολο να προσδιοριστεί σε ποιο μέρος του συστήματος παρουσιάστηκε το σφάλμα. Πιθανότατα, το πρόβλημα βρίσκεται στον κώδικα του ίδιου του monolith ή στη βάση δεδομένων. Αλλά όταν αρχίζουμε να αναζητούμε ένα πρόβλημα σε μια αρχιτεκτονική microservice, όλα δεν είναι πλέον τόσο προφανή. Πρέπει να βρούμε ολόκληρη τη διαδρομή που πήρε το αίτημα από την αρχή μέχρι το τέλος και να την επιλέξουμε από εκατοντάδες μικροϋπηρεσίες. Επιπλέον, πολλά από αυτά έχουν επίσης τις δικές τους εγκαταστάσεις αποθήκευσης, οι οποίες μπορούν επίσης να προκαλέσουν λογικά σφάλματα, καθώς και προβλήματα με την απόδοση και την ανοχή σφαλμάτων.
Έψαχνα εδώ και πολύ καιρό για ένα εργαλείο που θα βοηθούσε στην αντιμετώπιση τέτοιων προβλημάτων (έγραψα για αυτό στο Habré:
Η κατανεμημένη ανίχνευση είναι μια κοινή λύση στο πρόβλημα της εύρεσης σφαλμάτων στα κατανεμημένα συστήματα. Αλλά τι γίνεται εάν αυτή η προσέγγιση για τη συλλογή πληροφοριών σχετικά με τις αλληλεπιδράσεις δικτύου δεν έχει εφαρμοστεί ακόμη στο σύστημα ή, χειρότερα, σε μέρος του συστήματος λειτουργεί ήδη σωστά, αλλά εν μέρει όχι, καθώς δεν έχει προστεθεί σε παλιές υπηρεσίες ? Για να προσδιορίσετε την ακριβή βασική αιτία ενός προβλήματος, είναι απαραίτητο να έχετε μια πλήρη εικόνα του τι συμβαίνει στο σύστημα. Είναι ιδιαίτερα σημαντικό να κατανοήσουμε ποιες μικροϋπηρεσίες εμπλέκονται σε βασικά κρίσιμα για τις επιχειρήσεις μονοπάτια.
Εδώ μπορεί να μας βοηθήσει η προσέγγιση του πλέγματος υπηρεσιών, η οποία θα ασχοληθεί με όλα τα μηχανήματα συλλογής πληροφοριών δικτύου σε επίπεδο χαμηλότερο από αυτό που λειτουργούν οι ίδιες οι υπηρεσίες. Αυτή η προσέγγιση μας επιτρέπει να παρακολουθούμε όλη την κίνηση και να την αναλύουμε εν κινήσει. Επιπλέον, οι εφαρμογές δεν χρειάζεται καν να γνωρίζουν τίποτα γι 'αυτό.
Προσέγγιση πλέγματος εξυπηρέτησης
Η κύρια ιδέα της προσέγγισης του πλέγματος υπηρεσιών είναι να προσθέσουμε ένα άλλο επίπεδο υποδομής στο δίκτυο, το οποίο θα μας επιτρέψει να κάνουμε οτιδήποτε με την αλληλεπίδραση μεταξύ των υπηρεσιών. Οι περισσότερες υλοποιήσεις λειτουργούν ως εξής: ένα πρόσθετο κοντέινερ sidecar με διαφανή διακομιστή μεσολάβησης προστίθεται σε κάθε microservice, μέσω του οποίου διέρχεται όλη η εισερχόμενη και εξερχόμενη κίνηση της υπηρεσίας. Και αυτό είναι ακριβώς το μέρος όπου μπορούμε να κάνουμε εξισορρόπηση πελατών, να εφαρμόζουμε πολιτικές ασφαλείας, να επιβάλλουμε περιορισμούς στον αριθμό των αιτημάτων και να συλλέγουμε σημαντικές πληροφορίες για την αλληλεπίδραση των υπηρεσιών στην παραγωγή.
Λύσεις
Υπάρχουν ήδη αρκετές εφαρμογές αυτής της προσέγγισης:
Ως αποτέλεσμα, εξετάσαμε ακριβώς ποιες δυνατότητες χρειαζόμασταν αυτήν τη στιγμή και αποφασίσαμε ότι ο κύριος λόγος για τον οποίο ξεκινήσαμε να εφαρμόζουμε τέτοιες λύσεις ήταν η δυνατότητα συλλογής πληροφοριών ανίχνευσης από ολόκληρο το σύστημα με διαφάνεια. Θέλαμε επίσης να έχουμε τον έλεγχο της αλληλεπίδρασης των υπηρεσιών και να κάνουμε διάφορους χειρισμούς με τις κεφαλίδες που μεταφέρονται μεταξύ των υπηρεσιών.
Ως αποτέλεσμα, καταλήξαμε στην απόφασή μας:
Netramesh
Οι κύριοι στόχοι της νέας λύσης ήταν τα χαμηλά έξοδα πόρων και η υψηλή απόδοση. Μεταξύ των κύριων χαρακτηριστικών, θέλαμε αμέσως να είμαστε σε θέση να στέλνουμε με διαφάνεια διαστήματα ανίχνευσης στο σύστημά μας Jaeger.
Σήμερα, οι περισσότερες λύσεις cloud υλοποιούνται στο Golang. Και, φυσικά, υπάρχουν λόγοι για αυτό. Η σύνταξη εφαρμογών δικτύου στο Golang που λειτουργούν ασύγχρονα με I/O και κλιμακώνονται μεταξύ των πυρήνων όπως απαιτείται είναι βολική και αρκετά απλή. Και, αυτό που είναι επίσης πολύ σημαντικό, η απόδοση είναι επαρκής για να λύσει αυτό το πρόβλημα. Γι' αυτό και επιλέξαμε το Golang.
Παραγωγικότητα
Έχουμε επικεντρώσει τις προσπάθειές μας στην επίτευξη της μέγιστης παραγωγικότητας. Για μια λύση που αναπτύσσεται δίπλα σε κάθε παρουσία της υπηρεσίας, απαιτείται μικρή κατανάλωση μνήμης RAM και χρόνου CPU. Και, φυσικά, η καθυστέρηση απόκρισης θα πρέπει επίσης να είναι μικρή.
Ας δούμε τι αποτελέσματα έχουμε.
RAM
Το Netramesh καταναλώνει ~10Mb χωρίς κίνηση και 50Mb μέγιστο με φορτίο έως και 10000 RPS ανά παρουσία.
Το Istio envoy proxy καταναλώνει πάντα ~300Mb στα cluster μας με χιλιάδες περιπτώσεις. Αυτό δεν του επιτρέπει να κλιμακωθεί σε ολόκληρο το σύμπλεγμα.
Με το Netramesh είχαμε ~ 10x μείωση στην κατανάλωση μνήμης.
CPU
Η χρήση της CPU είναι σχετικά ίση υπό φορτίο. Εξαρτάται από τον αριθμό των αιτημάτων ανά μονάδα χρόνου στο πλαϊνό καρότσι. Τιμές σε 3000 αιτήματα ανά δευτερόλεπτο στο μέγιστο:
Υπάρχει ένα ακόμη σημαντικό σημείο: Netramesh - μια λύση χωρίς επίπεδο ελέγχου και χωρίς φορτίο δεν καταναλώνει χρόνο CPU. Με το Istio, τα sidecars ενημερώνουν πάντα τα τελικά σημεία υπηρεσίας. Ως αποτέλεσμα, μπορούμε να δούμε αυτήν την εικόνα χωρίς φορτίο:
Χρησιμοποιούμε το HTTP/1 για επικοινωνία μεταξύ των υπηρεσιών. Η αύξηση του χρόνου απόκρισης για το Istio κατά τη διαμεσολάβηση μέσω envoy ήταν έως και 5-10ms, κάτι που είναι αρκετά μεγάλο για υπηρεσίες που είναι έτοιμες να ανταποκριθούν σε ένα χιλιοστό του δευτερολέπτου. Με το Netramesh αυτός ο χρόνος μειώθηκε στα 0.5-2ms.
Επεκτασιμότητα
Ο μικρός αριθμός πόρων που καταναλώνει κάθε διακομιστής μεσολάβησης καθιστά δυνατή την τοποθέτησή του δίπλα σε κάθε υπηρεσία. Το Netramesh δημιουργήθηκε σκόπιμα χωρίς εξάρτημα επιπέδου ελέγχου για να διατηρεί απλώς κάθε πλευρικό κάθισμα ελαφρύ. Συχνά σε λύσεις πλέγματος σέρβις, το επίπεδο ελέγχου διανέμει πληροφορίες ανακάλυψης υπηρεσίας σε κάθε πλαϊνό κάρο. Μαζί με αυτό έρχονται πληροφορίες σχετικά με τα χρονικά όρια και τις ρυθμίσεις εξισορρόπησης. Όλα αυτά σας επιτρέπουν να κάνετε πολλά χρήσιμα πράγματα, αλλά, δυστυχώς, φουσκώνουν τα πλαϊνά σε μέγεθος.
Ανακάλυψη υπηρεσίας
Το Netramesh δεν προσθέτει επιπλέον μηχανισμούς για την ανακάλυψη υπηρεσίας. Όλη η κίνηση γίνεται με διαφάνεια μέσω του netra sidecar.
Το Netramesh υποστηρίζει πρωτόκολλο εφαρμογής HTTP/1. Για να το ορίσετε, χρησιμοποιείται μια διαμορφώσιμη λίστα θυρών. Συνήθως, το σύστημα έχει πολλές θύρες μέσω των οποίων πραγματοποιείται η επικοινωνία HTTP. Για παράδειγμα, χρησιμοποιούμε 80, 8890, 8080 για αλληλεπίδραση μεταξύ υπηρεσιών και εξωτερικών αιτημάτων. Σε αυτήν την περίπτωση, μπορούν να οριστούν χρησιμοποιώντας μια μεταβλητή περιβάλλοντος NETRA_HTTP_PORTS
.
Εάν χρησιμοποιείτε το Kubernetes ως ενορχηστρωτή και τον μηχανισμό της οντότητας Υπηρεσίας για επικοινωνία εντός του συμπλέγματος μεταξύ των υπηρεσιών, τότε ο μηχανισμός παραμένει ακριβώς ο ίδιος. Πρώτα, η microservice αποκτά μια διεύθυνση IP υπηρεσίας χρησιμοποιώντας kube-dns και ανοίγει μια νέα σύνδεση σε αυτήν. Αυτή η σύνδεση δημιουργείται πρώτα με το τοπικό netra-sidecar και όλα τα πακέτα TCP αρχικά φτάνουν στο netra. Στη συνέχεια, το netra-sidecar δημιουργεί μια σύνδεση με τον αρχικό προορισμό. Το NAT στο pod IP στον κόμβο παραμένει ακριβώς το ίδιο όπως χωρίς netra.
Κατανεμημένη ανίχνευση και προώθηση περιβάλλοντος
Το Netramesh παρέχει τη λειτουργικότητα που απαιτείται για την αποστολή διαστημάτων ανίχνευσης σχετικά με τις αλληλεπιδράσεις HTTP. Το Netra-sidecar αναλύει το πρωτόκολλο HTTP, μετρά τις καθυστερήσεις αιτημάτων και εξάγει τις απαραίτητες πληροφορίες από τις κεφαλίδες HTTP. Τελικά, έχουμε όλα τα ίχνη σε ένα ενιαίο σύστημα Jaeger. Για λεπτομερείς ρυθμίσεις, μπορείτε επίσης να χρησιμοποιήσετε τις μεταβλητές περιβάλλοντος που παρέχονται από την επίσημη βιβλιοθήκη
Όμως υπάρχει ένα πρόβλημα. Έως ότου οι υπηρεσίες δημιουργήσουν και στείλουν μια ειδική κεφαλίδα uber, δεν θα δούμε συνδεδεμένα διαστήματα ανίχνευσης στο σύστημα. Και αυτό είναι που χρειαζόμαστε για να βρούμε γρήγορα την αιτία των προβλημάτων. Και εδώ η Netramesh έχει μια λύση. Οι διακομιστής μεσολάβησης διαβάζουν τις κεφαλίδες HTTP και, εάν δεν περιέχουν το αναγνωριστικό ανίχνευσης uber, δημιουργούν ένα. Το Netramesh αποθηκεύει επίσης πληροφορίες σχετικά με τα εισερχόμενα και εξερχόμενα αιτήματα σε ένα sidecar και τα αντιστοιχίζει εμπλουτίζοντάς τα με τις απαραίτητες κεφαλίδες εξερχόμενων αιτημάτων. Το μόνο που χρειάζεται να κάνετε στις υπηρεσίες είναι να στείλετε μόνο μία κεφαλίδα X-Request-Id
, το οποίο μπορεί να διαμορφωθεί χρησιμοποιώντας μια μεταβλητή περιβάλλοντος NETRA_HTTP_REQUEST_ID_HEADER_NAME
. Για να ελέγξετε το μέγεθος του περιβάλλοντος στο Netramesh, μπορείτε να ορίσετε τις ακόλουθες μεταβλητές περιβάλλοντος: NETRA_TRACING_CONTEXT_EXPIRATION_MILLISECONDS
(ο χρόνος για τον οποίο θα αποθηκευτεί το πλαίσιο) και NETRA_TRACING_CONTEXT_CLEANUP_INTERVAL
(συχνότητα εκκαθάρισης περιβάλλοντος).
Είναι επίσης δυνατό να συνδυάσετε πολλαπλές διαδρομές στο σύστημά σας επισημαίνοντάς τις με ένα ειδικό διακριτικό περιόδου λειτουργίας. Το Netra σας επιτρέπει να εγκαταστήσετε HTTP_HEADER_TAG_MAP
για να μετατρέψετε τις κεφαλίδες HTTP σε αντίστοιχες ετικέτες διαστήματος ανίχνευσης. Αυτό μπορεί να είναι ιδιαίτερα χρήσιμο για δοκιμές. Αφού περάσετε τη λειτουργική δοκιμή, μπορείτε να δείτε ποιο μέρος του συστήματος επηρεάστηκε από το φιλτράρισμα από το αντίστοιχο κλειδί συνεδρίας.
Προσδιορισμός της πηγής αιτήματος
Για να προσδιορίσετε από πού προήλθε το αίτημα, μπορείτε να χρησιμοποιήσετε τη λειτουργία αυτόματης προσθήκης κεφαλίδας με την πηγή. Χρήση μεταβλητής περιβάλλοντος NETRA_HTTP_X_SOURCE_HEADER_NAME
Μπορείτε να καθορίσετε ένα όνομα κεφαλίδας που θα εγκατασταθεί αυτόματα. Με τη χρήση NETRA_HTTP_X_SOURCE_VALUE
μπορείτε να ορίσετε την τιμή στην οποία θα οριστεί η κεφαλίδα X-Source για όλα τα εξερχόμενα αιτήματα.
Αυτό επιτρέπει την ομοιόμορφη κατανομή αυτής της χρήσιμης κεφαλίδας σε όλο το δίκτυο. Στη συνέχεια, μπορείτε να το χρησιμοποιήσετε σε υπηρεσίες και να το προσθέσετε σε αρχεία καταγραφής και μετρήσεις.
Δρομολόγηση κυκλοφορίας και εσωτερικά Netramesh
Το Netramesh αποτελείται από δύο κύρια συστατικά. Το πρώτο, το netra-init, ορίζει κανόνες δικτύου για την παρακολούθηση της κυκλοφορίας. Χρησιμοποιεί INBOUND_INTERCEPT_PORTS, OUTBOUND_INTERCEPT_PORTS
.
Το εργαλείο έχει επίσης ένα ενδιαφέρον χαρακτηριστικό - πιθανολογική δρομολόγηση. Εάν χρησιμοποιείτε το Netramesh αποκλειστικά για τη συλλογή ανιχνεύσεων, τότε σε ένα περιβάλλον παραγωγής μπορείτε να εξοικονομήσετε πόρους και να ενεργοποιήσετε την πιθανολογική δρομολόγηση χρησιμοποιώντας μεταβλητές NETRA_INBOUND_PROBABILITY
и NETRA_OUTBOUND_PROBABILITY
(από 0 έως 1). Η προεπιλεγμένη τιμή είναι 1 (όλη η κίνηση παρεμποδίζεται).
Μετά την επιτυχή αναχαίτιση, το netra sidecar δέχεται τη νέα σύνδεση και χρησιμοποιεί SO_ORIGINAL_DST
επιλογή υποδοχής για να λάβετε τον αρχικό προορισμό. Στη συνέχεια, η Netra ανοίγει μια νέα σύνδεση με την αρχική διεύθυνση IP και δημιουργεί αμφίδρομη επικοινωνία TCP μεταξύ των μερών, ακούγοντας όλη την κίνηση που διέρχεται. Εάν η θύρα ορίζεται ως HTTP, η Netra προσπαθεί να την αναλύσει και να την ανιχνεύσει. Εάν η ανάλυση HTTP αποτύχει, το Netra επιστρέφει στο TCP και μεταφέρει με διαφάνεια τα byte.
Δημιουργία γραφήματος εξάρτησης
Μετά τη λήψη μεγάλου όγκου πληροφοριών ανίχνευσης στο Jaeger, θέλω να λάβω ένα πλήρες γράφημα των αλληλεπιδράσεων στο σύστημα. Αλλά αν το σύστημά σας είναι αρκετά φορτωμένο και συσσωρεύονται δισεκατομμύρια διαστήματα ανίχνευσης ανά ημέρα, η συγκέντρωση τους δεν είναι τόσο εύκολη υπόθεση. Υπάρχει ένας επίσημος τρόπος για να γίνει αυτό:
Εάν χρησιμοποιείτε το Elasticsearch για την αποθήκευση ανιχνεύσεων, μπορείτε να το χρησιμοποιήσετε
Πώς να χρησιμοποιήσετε το Netramesh
Το Netra μπορεί εύκολα να προστεθεί σε οποιαδήποτε υπηρεσία που εκτελεί οποιονδήποτε ενορχηστρωτή. Μπορείτε να δείτε ένα παράδειγμα
Αυτή τη στιγμή, η Netra δεν έχει τη δυνατότητα αυτόματης υλοποίησης sidecars σε υπηρεσίες, αλλά υπάρχουν σχέδια για εφαρμογή.
Το μέλλον της Netramesh
κύριος στόχος
Στο μέλλον, το Netramesh θα υποστηρίζει άλλα πρωτόκολλα επιπέδου εφαρμογής εκτός από το HTTP. Η δρομολόγηση L7 θα είναι διαθέσιμη στο εγγύς μέλλον.
Χρησιμοποιήστε το Netramesh εάν αντιμετωπίζετε παρόμοια προβλήματα και γράψτε μας με ερωτήσεις και προτάσεις.
Πηγή: www.habr.com