Service Tracing, OpenTracing και Jaeger

Service Tracing, OpenTracing και Jaeger

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

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

Ποια προβλήματα μπορούν να λυθούν με τον εντοπισμό

  1. Βρείτε τα σημεία συμφόρησης απόδοσης τόσο σε μία υπηρεσία όσο και σε ολόκληρο το δέντρο εκτέλεσης μεταξύ όλων των συμμετεχουσών υπηρεσιών. Για παράδειγμα:
    • Πολλές σύντομες διαδοχικές κλήσεις μεταξύ υπηρεσιών, για παράδειγμα, σε γεωκωδικοποίηση ή σε μια βάση δεδομένων.
    • Μεγάλη αναμονή εισόδου/εξόδου, όπως μεταφορές δικτύου ή αναγνώσεις δίσκου.
    • Μεγάλη ανάλυση δεδομένων.
    • Μεγάλες λειτουργίες που απαιτούν CPU.
    • Ενότητες κώδικα που δεν χρειάζονται για να ληφθεί το τελικό αποτέλεσμα και μπορούν να αφαιρεθούν ή να καθυστερήσουν.
  2. Κατανοήστε ξεκάθαρα με ποια σειρά τι ονομάζεται και τι συμβαίνει όταν εκτελείται η επέμβαση.
    Service Tracing, OpenTracing και Jaeger
    Μπορεί να φανεί ότι, για παράδειγμα, το αίτημα ήρθε στην υπηρεσία WS -> η υπηρεσία WS συμπλήρωσε τα δεδομένα μέσω της υπηρεσίας R -> στη συνέχεια έστειλε ένα αίτημα στην υπηρεσία V -> η υπηρεσία V φόρτωσε πολλά δεδομένα από το Υπηρεσία R -> πήγε στην υπηρεσία P -> η υπηρεσία P πήγε ξανά στην υπηρεσία R -> η υπηρεσία V αγνόησε το αποτέλεσμα και πήγε στην υπηρεσία J -> και μόνο τότε επέστρεψε την απόκριση στην υπηρεσία WS, ενώ συνέχισε να υπολογίζει κάτι άλλο στο το φόντο.
    Χωρίς ένα τέτοιο ίχνος ή λεπτομερή τεκμηρίωση για ολόκληρη τη διαδικασία, είναι πολύ δύσκολο να καταλάβετε τι συμβαίνει όταν κοιτάζετε τον κώδικα για πρώτη φορά και ο κώδικας είναι διάσπαρτος σε διάφορες υπηρεσίες και κρύβεται πίσω από μια δέσμη απορριμμάτων και διεπαφών.
  3. Συλλογή πληροφοριών σχετικά με το δέντρο εκτέλεσης για μετέπειτα αναβαλλόμενη ανάλυση. Σε κάθε στάδιο της εκτέλεσης, μπορείτε να προσθέσετε πληροφορίες στο ίχνος που είναι διαθέσιμο σε αυτό το στάδιο και στη συνέχεια να υπολογίσετε ποια δεδομένα εισόδου οδήγησαν σε ένα παρόμοιο σενάριο. Για παράδειγμα:
    • ταυτότητα χρήστη
    • Δικαιώματα
    • Τύπος επιλεγμένης μεθόδου
    • Σφάλμα καταγραφής ή εκτέλεσης
  4. Μετατροπή των ιχνών σε υποσύνολο μετρήσεων και περαιτέρω ανάλυση ήδη με τη μορφή μετρήσεων.

Τι ίχνος μπορεί να καταγραφεί. Σπιθαμή

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

  • Όνομα, συνήθως το όνομα της μεθόδου που εκτελέστηκε
  • Το όνομα της υπηρεσίας στην οποία δημιουργήθηκε το διάστημα
  • Διαθέτετε μοναδικό αναγνωριστικό
  • Ορισμένες μετα-πληροφορίες με τη μορφή κλειδιού/τιμής που έχει συνδεθεί σε αυτό. Για παράδειγμα, οι παράμετροι μεθόδου ή η μέθοδος έληξε με σφάλμα ή όχι
  • Ώρες έναρξης και λήξης για αυτό το διάστημα
  • Αναγνωριστικό γονικού εύρους

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

Service Tracing, OpenTracing και Jaeger

Opentrace, Jagger και πώς το εφαρμόσαμε για τα έργα μας

Υπάρχει ένα κοινό πρότυπο opentrace, το οποίο περιγράφει πώς και τι πρέπει να συλλεχθεί, χωρίς να συνδέεται με την ανίχνευση σε μια συγκεκριμένη υλοποίηση σε οποιαδήποτε γλώσσα. Για παράδειγμα, στην Java, όλη η εργασία με ίχνη πραγματοποιείται μέσω του κοινού API Opentrace και κάτω από αυτό, για παράδειγμα, το Jaeger ή μια κενή προεπιλεγμένη εφαρμογή που δεν κάνει τίποτα μπορεί να κρυφτεί.
Χρησιμοποιούμε Jaeger ως υλοποίηση του Opentrace. Αποτελείται από πολλά συστατικά:

Service Tracing, OpenTracing και Jaeger

  • Το Jaeger-agent είναι ένας τοπικός πράκτορας που συνήθως εγκαθίσταται σε κάθε μηχάνημα και οι υπηρεσίες συνδέονται σε αυτόν στην τοπική προεπιλεγμένη θύρα. Εάν δεν υπάρχει αντιπρόσωπος, τότε συνήθως απενεργοποιούνται τα ίχνη όλων των υπηρεσιών σε αυτό το μηχάνημα
  • Jaeger-collector - όλοι οι πράκτορες στέλνουν συλλεγμένα ίχνη σε αυτόν και τα τοποθετεί στην επιλεγμένη βάση δεδομένων
  • Η βάση δεδομένων είναι η προτιμώμενη cassandra τους, αλλά χρησιμοποιούμε elasticsearch, υπάρχουν υλοποιήσεις για μερικές άλλες βάσεις δεδομένων και μια υλοποίηση στη μνήμη που δεν αποθηκεύει τίποτα στο δίσκο
  • Το Jaeger-query είναι μια υπηρεσία που πηγαίνει στη βάση δεδομένων και επιστρέφει ήδη συλλεγμένα ίχνη για ανάλυση
  • Το Jaeger-ui είναι μια διεπαφή ιστού για αναζήτηση και προβολή ιχνών, πηγαίνει στο jaeger-query

Service Tracing, OpenTracing και Jaeger

Ένα ξεχωριστό στοιχείο μπορεί να ονομαστεί η υλοποίηση του opentrace jaeger για συγκεκριμένες γλώσσες, μέσω του οποίου αποστέλλονται διαστήματα στον jaeger-agent.
Σύνδεση Jagger σε Java καταλήγει στην υλοποίηση της διεπαφής io.opentracing.Tracer, μετά την οποία όλα τα ίχνη μέσω αυτής θα μεταβούν στον πραγματικό πράκτορα.

Service Tracing, OpenTracing και Jaeger

Επίσης για το εξάρτημα ελατηρίου, μπορείτε να συνδέσετε opentracing-spring-cloud-starter και υλοποίηση από τον Jaeger opentracing-spring-jaeger-cloud-starter που θα ρυθμίσει αυτόματα την ανίχνευση για οτιδήποτε περνά μέσα από αυτά τα στοιχεία, για παράδειγμα αιτήματα http σε ελεγκτές, αιτήματα στη βάση δεδομένων μέσω jdbc κ.λπ.

Ίχνη καταγραφής σε Java

Κάπου στο ανώτερο επίπεδο, πρέπει να δημιουργηθεί το πρώτο Span, αυτό μπορεί να γίνει αυτόματα, για παράδειγμα, από τον ελεγκτή ελατηρίου όταν λαμβάνεται ένα αίτημα ή χειροκίνητα εάν δεν υπάρχει. Στη συνέχεια μεταδίδεται μέσω του Πεδίου παρακάτω. Εάν κάποια από τις παρακάτω μεθόδους θέλει να προσθέσει ένα Span, παίρνει το τρέχον activeSpan από το Scope, δημιουργεί ένα νέο Span και λέει ότι ο γονέας του είναι το activeSpan που προκύπτει και κάνει το νέο Span ενεργό. Κατά την κλήση εξωτερικών υπηρεσιών, το τρέχον ενεργό διάστημα μεταβιβάζεται σε αυτές και αυτές οι υπηρεσίες δημιουργούν νέα πεδία με αναφορά σε αυτό το διάστημα.
Όλη η εργασία περνά από την παρουσία Tracer, μπορείτε να τη λάβετε μέσω του μηχανισμού DI ή του GlobalTracer.get () ως καθολική μεταβλητή εάν ο μηχανισμός DI δεν λειτουργεί. Από προεπιλογή, εάν το tracer δεν έχει αρχικοποιηθεί, το NoopTracer θα επιστρέψει το οποίο δεν κάνει τίποτα.
Περαιτέρω, το τρέχον εύρος λαμβάνεται από τον ανιχνευτή μέσω του ScopeManager, δημιουργείται ένα νέο εύρος από το τρέχον με δέσμευση του νέου εύρους και, στη συνέχεια, το εύρος που δημιουργήθηκε κλείνει, το οποίο κλείνει το δημιουργημένο διάστημα και επιστρέφει το προηγούμενο πεδίο εφαρμογής στο την ενεργό κατάσταση. Το εύρος είναι συνδεδεμένο με ένα νήμα, επομένως κατά τον προγραμματισμό πολλαπλών νημάτων, δεν πρέπει να ξεχνάτε να μεταφέρετε το ενεργό διάστημα σε άλλο νήμα, για περαιτέρω ενεργοποίηση του εύρους ενός άλλου νήματος με αναφορά σε αυτό το διάστημα.

io.opentracing.Tracer tracer = ...; // GlobalTracer.get()

void DoSmth () {
   try (Scope scope = tracer.buildSpan("DoSmth").startActive(true)) {
      ...
   }
}
void DoOther () {
    Span span = tracer.buildSpan("someWork").start();
    try (Scope scope = tracer.scopeManager().activate(span, false)) {
        // Do things.
    } catch(Exception ex) {
        Tags.ERROR.set(span, true);
        span.log(Map.of(Fields.EVENT, "error", Fields.ERROR_OBJECT, ex, Fields.MESSAGE, ex.getMessage()));
    } finally {
        span.finish();
    }
}

void DoAsync () {
    try (Scope scope = tracer.buildSpan("ServiceHandlerSpan").startActive(false)) {
        ...
        final Span span = scope.span();
        doAsyncWork(() -> {
            // STEP 2 ABOVE: reactivate the Span in the callback, passing true to
            // startActive() if/when the Span must be finished.
            try (Scope scope = tracer.scopeManager().activate(span, false)) {
                ...
            }
        });
    }
}

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

private ExecutorService executor = new TracedExecutorService(
    Executors.newFixedThreadPool(10), GlobalTracer.get()
);

Για εξωτερικά αιτήματα http υπάρχει TracingHttpClient

HttpClient httpClient = new TracingHttpClientBuilder().build();

Προβλήματα που αντιμετωπίσαμε

  • Τα φασόλια και το DI δεν λειτουργούν πάντα εάν ο ιχνηθέτης δεν χρησιμοποιείται σε μια υπηρεσία ή εξάρτημα, τότε Αυτόματη καλωδίωση Το Tracer ενδέχεται να μην λειτουργεί και θα πρέπει να χρησιμοποιήσετε το GlobalTracer.get().
  • Οι σχολιασμοί δεν λειτουργούν εάν δεν είναι στοιχείο ή υπηρεσία ή εάν η μέθοδος καλείται από μια γειτονική μέθοδο της ίδιας κλάσης. Πρέπει να είστε προσεκτικοί για να ελέγξετε τι λειτουργεί και να χρησιμοποιήσετε τη μη αυτόματη δημιουργία ίχνους εάν το @Traced δεν λειτουργεί. Μπορείτε επίσης να επισυνάψετε έναν πρόσθετο μεταγλωττιστή για σχολιασμούς java, τότε θα πρέπει να λειτουργούν παντού.
  • Στην παλιά μπότα ελατηρίου και ελατηρίου, η αυτόματη διαμόρφωση cloud ελατηρίου opentraing δεν λειτουργεί λόγω σφαλμάτων στο DI, τότε εάν θέλετε τα ίχνη στα στοιχεία του ελατηρίου να λειτουργούν αυτόματα, μπορείτε να το κάνετε κατ' αναλογία με github.com/opentracing-contrib/java-spring-jaeger/blob/master/opentracing-spring-jaeger-starter/src/main/java/io/opentracing/contrib/java/spring/jaeger/starter/JaegerAutoConfiguration.java
  • Η δοκιμή με πόρους δεν λειτουργεί σε groovy, πρέπει να χρησιμοποιήσετε την δοκιμή τελικά.
  • Κάθε υπηρεσία πρέπει να έχει το δικό της spring.application.name κάτω από το οποίο θα καταγράφονται τα ίχνη. Τι σημαίνει ένα ξεχωριστό όνομα για την πώληση και τη δοκιμή, έτσι ώστε να μην παρεμβαίνει μαζί τους.
  • Εάν χρησιμοποιείτε το GlobalTracer και το tomcat, τότε όλες οι υπηρεσίες που εκτελούνται σε αυτό το tomcat έχουν ένα GlobalTracer, επομένως θα έχουν όλες το ίδιο όνομα υπηρεσίας.
  • Όταν προσθέτετε ίχνη σε μια μέθοδο, πρέπει να είστε βέβαιοι ότι δεν καλείται πολλές φορές σε βρόχο. Είναι απαραίτητο να προστεθεί ένα κοινό ίχνος για όλες τις κλήσεις, το οποίο εγγυάται τον συνολικό χρόνο εργασίας. Διαφορετικά, θα δημιουργηθεί υπερβολικό φορτίο.
  • Μόλις στο jaeger-ui, έγιναν πολύ μεγάλα αιτήματα για μεγάλο αριθμό ιχνών και επειδή δεν περίμεναν απάντηση, το έκαναν ξανά. Ως αποτέλεσμα, το jaeger-query άρχισε να τρώει πολλή μνήμη και να επιβραδύνει την ελαστικότητα. Βοηθήθηκε με την επανεκκίνηση του jaeger-query

Δειγματοληψία, αποθήκευση και προβολή ιχνών

Υπάρχουν τρεις τύποι ίχνη δειγματοληψίας:

  1. Const που στέλνει και αποθηκεύει όλα τα ίχνη.
  2. Πιθανολογικό που φιλτράρει ίχνη με κάποια δεδομένη πιθανότητα.
  3. Ratelimiting που περιορίζει τον αριθμό των ιχνών ανά δευτερόλεπτο. Μπορείτε να διαμορφώσετε αυτές τις ρυθμίσεις στον πελάτη, είτε στον jaeger-agent είτε στον συλλέκτη. Τώρα χρησιμοποιούμε το const 1 στη στοίβα του εκτιμητή, καθώς δεν υπάρχουν πολλά αιτήματα, αλλά χρειάζονται πολύ χρόνο. Στο μέλλον, εάν αυτό ασκήσει υπερβολικό φορτίο στο σύστημα, μπορείτε να το περιορίσετε.

Εάν χρησιμοποιείτε cassandra, τότε από προεπιλογή αποθηκεύει ίχνη μόνο για δύο ημέρες. Χρησιμοποιούμε ελαστική αναζήτηση και τα ίχνη αποθηκεύονται για πάντα και δεν διαγράφονται. Δημιουργείται ξεχωριστό ευρετήριο για κάθε ημέρα, για παράδειγμα jaeger-service-2019-03-04. Στο μέλλον, θα πρέπει να διαμορφώσετε τον αυτόματο καθαρισμό παλαιών ιχνών.

Για να δείτε τα ίχνη χρειάζεστε:

  • Επιλέξτε την υπηρεσία με την οποία θέλετε να φιλτράρετε τα ίχνη, για παράδειγμα, tomcat7-default για μια υπηρεσία που εκτελείται στο tomcat και δεν μπορεί να έχει το δικό της όνομα.
  • Στη συνέχεια, επιλέξτε τη λειτουργία, το χρονικό διάστημα και τον ελάχιστο χρόνο λειτουργίας, για παράδειγμα από 10 δευτερόλεπτα, για να διαρκέσετε μόνο μεγάλες εκτελέσεις.
    Service Tracing, OpenTracing και Jaeger
  • Πηγαίνετε σε ένα από τα ίχνη και δείτε τι επιβραδύνει εκεί.
    Service Tracing, OpenTracing και Jaeger

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

Εγγραφές

άρθρα

βίντεο

Πηγή: www.habr.com

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