Suivi des services, OpenTracing et Jaeger

Suivi des services, OpenTracing et Jaeger

Nous utilisons une architecture microservice dans nos projets. Lorsque des goulots d'étranglement de performances se produisent, beaucoup de temps est consacré à la surveillance et à l'analyse des journaux. Lors de la journalisation des minutages d'opérations individuelles dans un fichier journal, il est généralement difficile de comprendre ce qui a conduit à l'invocation de ces opérations, de suivre la séquence d'actions ou le décalage temporel d'une opération par rapport à une autre dans différents services.

Pour minimiser le travail manuel, nous avons décidé d'utiliser l'un des outils de traçage. Comment et pourquoi vous pouvez utiliser le traçage et comment nous l'avons fait, et seront discutés dans cet article.

Quels problĂšmes peuvent ĂȘtre rĂ©solus avec le traçage

  1. Trouvez les goulots d'étranglement des performances à la fois au sein d'un service unique et dans l'ensemble de l'arborescence d'exécution entre tous les services participants. Par exemple:
    • De nombreux appels courts et consĂ©cutifs entre services, par exemple vers un gĂ©ocodage ou vers une base de donnĂ©es.
    • Attentes d'E/S longues, telles que les transferts rĂ©seau ou les lectures de disque.
    • Longue analyse de donnĂ©es.
    • OpĂ©rations longues nĂ©cessitant CPU.
    • Les sections de code qui ne sont pas nĂ©cessaires pour obtenir le rĂ©sultat final et qui peuvent ĂȘtre supprimĂ©es ou retardĂ©es.
  2. Comprenez clairement dans quel ordre ce qui est appelé et ce qui se passe lorsque l'opération est effectuée.
    Suivi des services, OpenTracing et Jaeger
    On peut voir que, par exemple, la requĂȘte est arrivĂ©e au service WS -> le service WS a ajoutĂ© des donnĂ©es via le service R -> puis a envoyĂ© une requĂȘte au service V -> le service V a chargĂ© beaucoup de donnĂ©es du R service -> est allĂ© au service P -> le service P est allĂ© Ă  nouveau au service R -> le service V a ignorĂ© le rĂ©sultat et est allĂ© au service J -> et n'a renvoyĂ© qu'ensuite la rĂ©ponse au service WS, tout en continuant Ă  calculer autre chose dans le arriĂšre-plan.
    Sans une telle trace ou une documentation détaillée pour l'ensemble du processus, il est trÚs difficile de comprendre ce qui se passe lorsque l'on regarde le code pour la premiÚre fois, et le code est dispersé sur différents services et caché derriÚre un tas de bacs et d'interfaces.
  3. Collecte d'informations sur l'arbre d'exĂ©cution pour une analyse diffĂ©rĂ©e ultĂ©rieure. À chaque Ă©tape de l'exĂ©cution, vous pouvez ajouter des informations Ă  la trace disponible Ă  ce stade, puis dĂ©terminer quelles donnĂ©es d'entrĂ©e ont conduit Ă  un scĂ©nario similaire. Par exemple:
    • ID de l'utilisateur
    • Droits
    • Type de mĂ©thode sĂ©lectionnĂ©e
    • Journal ou erreur d'exĂ©cution
  4. Transformer les traces en un sous-ensemble de métriques et une analyse plus approfondie déjà sous la forme de métriques.

Quelle trace peut enregistrer. Portée

Dans le traçage, il y a le concept d'une portée, c'est un analogue d'un journal, à la console. Le spa dispose de :

  • Nom, gĂ©nĂ©ralement le nom de la mĂ©thode qui a Ă©tĂ© exĂ©cutĂ©e
  • Le nom du service dans lequel le span a Ă©tĂ© gĂ©nĂ©rĂ©
  • Propre identifiant unique
  • Une sorte de mĂ©ta-information sous la forme d'une clĂ©/valeur qui y a Ă©tĂ© connectĂ©e. Par exemple, les paramĂštres de la mĂ©thode ou la mĂ©thode s'est terminĂ©e par une erreur ou non
  • Heures de dĂ©but et de fin pour cette pĂ©riode
  • ID d'Ă©tendue parent

Chaque span est envoyĂ© au collecteur de span pour ĂȘtre stockĂ© dans la base de donnĂ©es pour un examen ultĂ©rieur dĂšs qu'il a terminĂ© son exĂ©cution. À l'avenir, vous pourrez crĂ©er une arborescence de toutes les Ă©tendues en vous connectant par identifiant parent. Lors de l'analyse, vous pouvez trouver, par exemple, toutes les durĂ©es d'un service qui ont pris plus d'un certain temps. De plus, en allant Ă  une Ă©tendue spĂ©cifique, voir l'arbre entier au-dessus et en dessous de cette Ă©tendue.

Suivi des services, OpenTracing et Jaeger

Opentrace, Jagger et comment nous l'avons implémenté pour nos projets

Il existe une norme commune opentrace, qui dĂ©crit comment et ce qui doit ĂȘtre collectĂ©, sans ĂȘtre liĂ© par un traçage Ă  une implĂ©mentation spĂ©cifique dans une langue. Par exemple, en Java, tout travail avec des traces est effectuĂ© via l'API Opentrace commune, et sous celle-ci, par exemple, Jaeger ou une implĂ©mentation par dĂ©faut vide qui ne fait rien peut ĂȘtre masquĂ©e.
Nous utilisons Jaeger en tant qu'implémentation d'Opentrace. Il se compose de plusieurs composants :

Suivi des services, OpenTracing et Jaeger

  • Jaeger-agent est un agent local qui est gĂ©nĂ©ralement installĂ© sur chaque machine et les services y sont connectĂ©s sur le port local par dĂ©faut. S'il n'y a pas d'agent, les traces de tous les services sur cette machine sont gĂ©nĂ©ralement dĂ©sactivĂ©es
  • Jaeger-collector - tous les agents lui envoient les traces collectĂ©es, et il les place dans la base de donnĂ©es sĂ©lectionnĂ©e
  • La base de donnĂ©es est leur cassandra prĂ©fĂ©rĂ©e, mais nous utilisons elasticsearch, il existe des implĂ©mentations pour quelques autres bases de donnĂ©es et une implĂ©mentation en mĂ©moire qui n'enregistre rien sur le disque
  • Jaeger-query est un service qui va Ă  la base de donnĂ©es et renvoie les traces dĂ©jĂ  collectĂ©es pour analyse
  • Jaeger-ui est une interface web pour rechercher et visualiser des traces, il va Ă  jaeger-query

Suivi des services, OpenTracing et Jaeger

Un composant distinct peut ĂȘtre appelĂ© l'implĂ©mentation d'opentrace jaeger pour des langages spĂ©cifiques, Ă  travers lequel les Ă©tendues sont envoyĂ©es Ă  jaeger-agent.
Connecter Jagger en Java revient à implémenter l'interface io.opentracing.Tracer, aprÚs quoi toutes les traces qui la traversent voleront vers l'agent réel.

Suivi des services, OpenTracing et Jaeger

Également pour le composant de ressort, vous pouvez connecter opentracing-spring-cloud-starter et mise en Ɠuvre de Jaeger opentracing-spring-jaeger-cloud-starter qui configurera automatiquement le traçage pour tout ce qui passe par ces composants, par exemple les requĂȘtes http aux contrĂŽleurs, les requĂȘtes Ă  la base de donnĂ©es via jdbc, etc.

Journalisation des traces en Java

Quelque part au niveau supĂ©rieur, le premier Span doit ĂȘtre créé, cela peut ĂȘtre fait automatiquement, par exemple, par le contrĂŽleur de ressort lorsqu'une demande est reçue, ou manuellement s'il n'y en a pas. Il est ensuite transmis via le champ d'application ci-dessous. Si l'une des mĂ©thodes ci-dessous souhaite ajouter un Span, elle prend l'activeSpan actuel du Scope, crĂ©e un nouveau Span et indique que son parent est l'activeSpan rĂ©sultant, et active le nouveau Span. Lors de l'appel de services externes, la plage active actuelle leur est transmise et ces services crĂ©ent de nouvelles plages en rĂ©fĂ©rence Ă  cette plage.
Tout le travail passe par l'instance Tracer, vous pouvez l'obtenir via le mécanisme DI, ou GlobalTracer.get () en tant que variable globale si le mécanisme DI ne fonctionne pas. Par défaut, si le traceur n'a pas été initialisé, NoopTracer retournera ce qui ne fait rien.
De plus, la portée actuelle est obtenue à partir du traceur via le ScopeManager, une nouvelle portée est créée à partir de la portée actuelle avec une liaison de la nouvelle portée, puis la portée créée est fermée, ce qui ferme la portée créée et renvoie la portée précédente à l'état actif. La portée est liée à un thread, donc lors de la programmation multi-thread, vous ne devez pas oublier de transférer la plage active vers un autre thread, pour une activation ultérieure de la portée d'un autre thread en référence à cette plage.

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)) {
                ...
            }
        });
    }
}

Pour la programmation multi-thread, il existe Ă©galement TracedExecutorService et des wrappers similaires qui transfĂšrent automatiquement l'Ă©tendue actuelle au thread lorsque des tĂąches asynchrones sont lancĂ©es :

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

Pour les requĂȘtes http externes, il y a TraçageHttpClient

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

ProblÚmes auxquels nous avons été confrontés

  • Les beans et DI ne fonctionnent pas toujours si le traceur n'est pas utilisĂ© dans un service ou un composant, alors CĂąblage automatique Tracer peut ne pas fonctionner et vous devrez utiliser GlobalTracer.get().
  • Les annotations ne fonctionnent pas s'il ne s'agit pas d'un composant ou d'un service, ou si la mĂ©thode est appelĂ©e depuis une mĂ©thode voisine de la mĂȘme classe. Vous devez faire attention Ă  vĂ©rifier ce qui fonctionne et utiliser la crĂ©ation de trace manuelle si @Traced ne fonctionne pas. Vous pouvez Ă©galement joindre un compilateur supplĂ©mentaire pour les annotations Java, alors elles devraient fonctionner partout.
  • Dans l'ancien dĂ©marrage du printemps et du printemps, la configuration automatique du nuage de printemps opentraing ne fonctionne pas en raison de bogues dans DI, alors si vous voulez que les traces dans les composants du printemps fonctionnent automatiquement, vous pouvez le faire par analogie avec 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
  • Try with resources ne fonctionne pas dans groovy, vous devez utiliser try finally.
  • Chaque service doit avoir son propre nom spring.application.name sous lequel les traces seront enregistrĂ©es. Qu'est-ce qu'un nom distinct pour la vente et le test, afin de ne pas les gĂȘner ensemble.
  • Si vous utilisez GlobalTracer et tomcat, tous les services exĂ©cutĂ©s dans ce tomcat ont un GlobalTracer, ils auront donc tous le mĂȘme nom de service.
  • Lorsque vous ajoutez des traces Ă  une mĂ©thode, vous devez vous assurer qu'elle n'est pas appelĂ©e plusieurs fois dans une boucle. Il est nĂ©cessaire d'ajouter une trace commune pour tous les appels, ce qui garantit le temps de travail total. Sinon, une surcharge sera créée.
  • Une fois dans jaeger-ui, des requĂȘtes trop importantes Ă©taient faites pour un grand nombre de traces, et comme ils n'attendaient pas de rĂ©ponse, ils recommençaient. En consĂ©quence, Jaeger-Query a commencĂ© Ă  consommer beaucoup de mĂ©moire et Ă  ralentir Elastic. AidĂ© en redĂ©marrant jaeger-query

Échantillonnage, stockage et visualisation des traces

Il existe trois types traces d'échantillonnage:

  1. Const qui envoie et enregistre toutes les traces.
  2. Probabiliste qui filtre les traces avec une probabilité donnée.
  3. Ratelimiting qui limite le nombre de traces par seconde. Vous pouvez configurer ces paramĂštres sur le client, soit sur l'agent jaeger, soit sur le collecteur. Maintenant, nous utilisons const 1 dans la pile de valuateurs, car il n'y a pas beaucoup de requĂȘtes, mais elles prennent beaucoup de temps. À l'avenir, si cela exerce une charge excessive sur le systĂšme, vous pouvez la limiter.

Si vous utilisez cassandra, par dĂ©faut, il ne stocke les traces que pendant deux jours. Nous utilisons elasticsearch et les traces sont stockĂ©es pour toujours et ne sont pas supprimĂ©es. Un index distinct est créé pour chaque jour, par exemple jaeger-service-2019-03-04. À l'avenir, vous devrez configurer le nettoyage automatique des anciennes traces.

Pour visualiser les traces dont vous avez besoin :

  • SĂ©lectionnez le service par lequel vous souhaitez filtrer les traces, par exemple, tomcat7-default pour un service qui s'exĂ©cute dans le tomcat et ne peut pas avoir son propre nom.
  • SĂ©lectionnez ensuite l'opĂ©ration, l'intervalle de temps et le temps d'opĂ©ration minimum, par exemple Ă  partir de 10 secondes, pour ne prendre que des exĂ©cutions longues.
    Suivi des services, OpenTracing et Jaeger
  • Allez Ă  l'une des traces et voyez ce qui ralentissait lĂ -bas.
    Suivi des services, OpenTracing et Jaeger

De plus, si un identifiant de requĂȘte est connu, vous pouvez trouver une trace par cet identifiant via une recherche de balise, si cet identifiant est enregistrĂ© dans la plage de trace.

Documentation

Articles

Vidéos

Source: habr.com

Achetez un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Achetez un hĂ©bergement web fiable avec protection DDoS, serveurs VPS et VDS | ProHoster