Service Tracing, OpenTracing i Jaeger

Service Tracing, OpenTracing i Jaeger

Utilitzem arquitectura de microserveis en els nostres projectes. Quan es produeixen colls d'ampolla de rendiment, es dedica molt de temps a supervisar i analitzar els registres. Quan es registren els temps d'operacions individuals en un fitxer de registre, normalment és difícil entendre què va provocar la invocació d'aquestes operacions, fer un seguiment de la seqüència d'accions o el canvi de temps d'una operació en relació amb una altra en diferents serveis.

Per minimitzar el treball manual, vam decidir utilitzar una de les eines de rastreig. Sobre com i per què podeu utilitzar el rastreig i com ho hem fet, i es parlarà en aquest article.

Quins problemes es poden resoldre amb el traçat

  1. Trobeu colls d'ampolla de rendiment tant dins d'un sol servei com a tot l'arbre d'execució entre tots els serveis participants. Per exemple:
    • Moltes trucades consecutives curtes entre serveis, per exemple, a la geocodificació o a una base de dades.
    • Llarges esperes d'E/S, com ara transferències de xarxa o lectures de disc.
    • Anàlisi llarg de dades.
    • Operacions llargues que requereixen CPU.
    • Seccions de codi que no són necessàries per obtenir el resultat final i que es poden eliminar o retardar.
  2. Entendre clarament en quina seqüència es diu i què passa quan es realitza l'operació.
    Service Tracing, OpenTracing i Jaeger
    Es pot veure que, per exemple, la Sol·licitud va arribar al servei WS -> el servei WS va complementar les dades mitjançant el servei R -> després va enviar una sol·licitud al servei V -> el servei V va carregar moltes dades del servei V. Servei R -> va anar al servei P -> el servei P va tornar al servei R -> el servei V va ignorar el resultat i va anar al servei J -> i només llavors va tornar la resposta al servei WS, mentre continuava calculant una altra cosa a el rerefons.
    Sense aquest rastre o documentació detallada per a tot el procés, és molt difícil entendre què passa quan es mira el codi per primera vegada, i el codi està escampat per diferents serveis i s'amaga darrere d'un munt de papereres i interfícies.
  3. Recollida d'informació sobre l'arbre d'execució per a l'anàlisi posterior posterior. En cada etapa d'execució, podeu afegir informació a la traça disponible en aquesta etapa i, a continuació, esbrinar quines dades d'entrada van conduir a un escenari similar. Per exemple:
    • ID d'usuari
    • Drets
    • Tipus de mètode seleccionat
    • Error de registre o d'execució
  4. Convertint les traces en un subconjunt de mètriques i anàlisis posteriors ja en forma de mètriques.

Quin rastre pot registrar. Envergadura

En el traçat hi ha el concepte d'un tram, aquest és un anàleg d'un registre, a la consola. L'spa disposa de:

  • Nom, normalment el nom del mètode que s'ha executat
  • El nom del servei en què s'ha generat l'abast
  • ID únic propi
  • Algun tipus de metainformació en forma de clau/valor que s'ha iniciat sessió. Per exemple, els paràmetres del mètode o el mètode va acabar amb un error o no
  • Horaris d'inici i finalització d'aquest període
  • Identificador d'abast dels pares

Cada span s'envia al col·lector de span per ser emmagatzemat a la base de dades per a una posterior revisió tan bon punt s'hagi completat la seva execució. En el futur, podeu crear un arbre de tots els trams connectant-vos mitjançant l'identificador principal. En analitzar, podeu trobar, per exemple, tots els intervals d'algun servei que han trigat més d'un temps. A més, en anar a un tram específic, vegeu tot l'arbre per sobre i per sota d'aquest tram.

Service Tracing, OpenTracing i Jaeger

Opentrace, Jagger i com ho hem implementat per als nostres projectes

Hi ha un estàndard comú traça oberta, que descriu com i què s'hauria de recollir, sense estar lligat a una implementació específica en cap idioma. Per exemple, a Java, tot el treball amb traces es realitza a través de l'API comuna d'Opentrace, i sota d'ella, per exemple, es pot amagar Jaeger o una implementació predeterminada buida que no fa res.
Estem utilitzant Jaeger com a implementació d'Opentrace. Consta de diversos components:

Service Tracing, OpenTracing i Jaeger

  • Jaeger-agent és un agent local que normalment s'instal·la a cada màquina i els serveis s'hi inicien sessió al port predeterminat local. Si no hi ha cap agent, les traces de tots els serveis d'aquesta màquina solen estar desactivades
  • Jaeger-collector: tots els agents li envien rastres recollits i els col·loca a la base de dades seleccionada
  • La base de dades és la seva Cassandra preferida, però fem servir elasticsearch, hi ha implementacions per a un parell de bases de dades més i una implementació en memòria que no desa res al disc.
  • Jaeger-query és un servei que va a la base de dades i retorna els rastres ja recollits per a l'anàlisi
  • Jaeger-ui és una interfície web per cercar i visualitzar traces, va a jaeger-query

Service Tracing, OpenTracing i Jaeger

Un component separat es pot anomenar la implementació d'opentrace jaeger per a llenguatges específics, a través del qual s'envien els intervals a jaeger-agent.
Connectant Jagger a Java es redueix a la implementació de la interfície io.opentracing.Tracer, després de la qual tots els rastres a través d'ella volaran a l'agent real.

Service Tracing, OpenTracing i Jaeger

També per al component de molla, podeu connectar-vos opentracing-spring-cloud-starter i implementació de Jaeger opentracing-spring-jaeger-núvol-iniciador que configurarà automàticament el seguiment de tot el que passa per aquests components, per exemple, les sol·licituds http als controladors, les sol·licituds a la base de dades mitjançant jdbc, etc.

Traces de registre a Java

En algun lloc del nivell superior, s'ha de crear el primer Span, això es pot fer automàticament, per exemple, pel controlador de molla quan es rep una sol·licitud, o manualment si no n'hi ha. Després es transmet a través de l'àmbit següent. Si algun dels mètodes següents vol afegir un Span, agafa l'activeSpan actual de l'àmbit, crea un nou Span i diu que el seu pare és l'activeSpan resultant i fa que el nou Span estigui actiu. Quan es crida a serveis externs, se'ls passa l'abast actiu actual i aquests serveis creen nous intervals amb referència a aquest interval.
Tot el treball passa per la instància Tracer, podeu obtenir-lo mitjançant el mecanisme DI, o GlobalTracer.get () com a variable global si el mecanisme DI no funciona. De manera predeterminada, si el traçador no s'ha inicialitzat, NoopTracer tornarà que no fa res.
A més, l'àmbit actual s'obté del traçador mitjançant ScopeManager, es crea un nou àmbit a partir de l'actual amb una vinculació del nou àmbit i, a continuació, es tanca l'àmbit creat, que tanca l'àmbit creat i retorna l'àmbit anterior a l'estat actiu. L'abast està lligat a un fil, de manera que quan es programa amb múltiples fils, no us oblideu de transferir l'abast actiu a un altre fil, per activar més l'abast d'un altre fil amb referència a aquest abast.

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

Per a la programació multifils, també hi ha TracedExecutorService i embolcalls similars que reenvien automàticament l'abast actual al fil quan s'inicien tasques asíncrones:

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

Per a sol·licituds http externes hi ha TracingHttpClient

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

Problemes que hem enfrontat

  • Els fesols i el DI no sempre funcionen si el traçador no s'utilitza en un servei o component, doncs Cablejat automàticament És possible que Tracer no funcioni i haureu d'utilitzar GlobalTracer.get().
  • Les anotacions no funcionen si no és un component o servei, o si el mètode es crida des d'un mètode veí de la mateixa classe. Heu d'anar amb compte per comprovar què funciona i utilitzar la creació manual de traça si @Traced no funciona. També podeu adjuntar un compilador addicional per a les anotacions java, llavors haurien de funcionar a tot arreu.
  • A l'antiga arrencada de primavera i primavera, la configuració automàtica del núvol de primavera d'opentraing no funciona a causa d'errors a DI, aleshores si voleu que les traces dels components de la primavera funcionin automàticament, podeu fer-ho per analogia amb 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
  • Prova amb recursos no funciona en groovy, has d'utilitzar try finalment.
  • Cada servei ha de tenir el seu propi spring.application.name sota el qual es registraran les traces. Què significa un nom separat per a la venda i la prova, per no interferir amb ells junts.
  • Si utilitzeu GlobalTracer i tomcat, tots els serveis que s'executen en aquest tomcat tenen un GlobalTracer, de manera que tots tindran el mateix nom de servei.
  • Quan afegiu traces a un mètode, heu d'assegurar-vos que no es crida moltes vegades en un bucle. Cal afegir un rastre comú per a totes les trucades, que garanteix el temps total de treball. En cas contrari, es crearà una càrrega excessiva.
  • Un cop a jaeger-ui, es van fer peticions massa grans per a un gran nombre de rastres, i com que no van esperar resposta, ho van tornar a fer. Com a resultat, jaeger-query va començar a menjar molta memòria i alentir l'elasticitat. Ajudat reiniciant jaeger-query

Mostra, emmagatzematge i visualització de traces

Hi ha tres tipus traces de mostreig:

  1. Const que envia i guarda tots els rastres.
  2. Probabilística que filtra traces amb alguna probabilitat determinada.
  3. Ratelimiting que limita el nombre de rastres per segon. Podeu configurar aquests paràmetres al client, ja sigui al jaeger-agent o al col·lector. Ara fem servir const 1 a la pila de valoradors, ja que no hi ha moltes sol·licituds, però triguen molt de temps. En el futur, si això exercirà una càrrega excessiva sobre el sistema, podeu limitar-la.

Si utilitzeu Cassandra, per defecte només emmagatzema rastres durant dos dies. Estem utilitzant cerca elastica i les traces s'emmagatzemen per sempre i no s'esborren. Es crea un índex separat per a cada dia, per exemple, jaeger-service-2019-03-04. En el futur, haureu de configurar la neteja automàtica de rastres antics.

Per veure les traces necessiteu:

  • Seleccioneu el servei pel qual voleu filtrar les traces, per exemple, tomcat7-default per a un servei que s'està executant al tomcat i que no pot tenir el seu propi nom.
  • A continuació, seleccioneu l'operació, l'interval de temps i el temps d'operació mínim, per exemple a partir de 10 segons, per fer només execucions llargues.
    Service Tracing, OpenTracing i Jaeger
  • Aneu a una de les traces i mireu què s'estava alentint allà.
    Service Tracing, OpenTracing i Jaeger

A més, si es coneix algun identificador de sol·licitud, podeu trobar un rastre per aquest identificador mitjançant una cerca d'etiquetes, si aquest identificador està registrat a l'espai de traça.

Registres

articles

Vídeo

Font: www.habr.com

Afegeix comentari