Service Tracing, OpenTracing és Jaeger

Service Tracing, OpenTracing és Jaeger

Projektjeink során mikroszolgáltatási architektúrát használunk. A teljesítmény szűk keresztmetszete esetén sok időt töltenek a naplók figyelésével és elemzésével. Az egyes műveletek időzítésének naplófájlba naplózásakor általában nehéz megérteni, hogy mi vezetett e műveletek meghívásához, nyomon követni a műveletek sorrendjét vagy az egyik művelet időbeli eltolódását a másikhoz képest különböző szolgáltatásokban.

A kézi munka minimalizálása érdekében úgy döntöttünk, hogy az egyik nyomkövető eszközt használjuk. Ebben a cikkben lesz szó arról, hogyan és miért használhatja a nyomkövetést, és hogyan csináltuk.

Milyen problémákat lehet megoldani a nyomkövetéssel

  1. Keresse meg a teljesítmény szűk keresztmetszeteit egyetlen szolgáltatáson belül és a teljes végrehajtási fában az összes résztvevő szolgáltatás között. Például:
    • Sok rövid, egymást követő hívás a szolgáltatások között, például geokódoláshoz vagy adatbázishoz.
    • Hosszú I/O várakozás, például hálózati átvitel vagy lemezolvasás.
    • Hosszú adatelemzés.
    • CPU-t igénylő hosszú műveletek.
    • A végeredmény eléréséhez nem szükséges kódrészek, amelyek eltávolíthatók vagy késleltethetők.
  2. Világosan értse meg, hogy milyen sorrendben mit hívnak, és mi történik a művelet végrehajtása során.
    Service Tracing, OpenTracing és Jaeger
    Látható, hogy például a WS szolgáltatáshoz érkezett a Request -> a WS szolgáltatás az R szolgáltatáson keresztül adatot adott -> majd kérést küldött a V szolgáltatásnak -> a V szolgáltatás sok adatot töltött be az R-ből szolgáltatás -> a P szolgáltatáshoz ment -> a P szolgáltatás ismét az R szolgáltatáshoz ment -> az V szolgáltatás figyelmen kívül hagyta az eredményt és a J szolgáltatásba ment -> és csak ezután adta vissza a választ a WS szolgáltatásnak, miközben folytatta valami más kiszámítását a háttér.
    Ilyen nyomkövetés vagy a teljes folyamat részletes dokumentációja nélkül nagyon nehéz megérteni, hogy mi történik, amikor először nézzük meg a kódot, és a kód szétszórva van a különböző szolgáltatások között, és egy csomó tároló és interfész mögött rejtőzik.
  3. Információgyűjtés a végrehajtási fáról a későbbi halasztott elemzéshez. A végrehajtás minden szakaszában hozzáadhat információkat az ebben a szakaszban elérhető nyomkövetéshez, majd kitalálhatja, hogy mely bemeneti adatok vezettek hasonló forgatókönyvhöz. Például:
    • Felhasználói azonosító
    • jogok
    • A kiválasztott módszer típusa
    • Napló vagy végrehajtási hiba
  4. A nyomvonalak metrikák részhalmazává alakítása és további elemzése már metrikák formájában.

Milyen nyomokat tud naplózni. Span

A nyomkövetésben ott van a fesztáv fogalma, ez egy napló analógja a konzolhoz. A fürdő a következőket kínálja:

  • Név, általában a végrehajtott metódus neve
  • Annak a szolgáltatásnak a neve, amelyben a tartomány létrejött
  • Saját egyedi azonosító
  • Valamilyen metainformáció kulcs/érték formájában, ami be van jelentkezve. Például a metódus paraméterei vagy a metódus hibával végződött vagy sem
  • Ennek az időszaknak a kezdési és befejezési ideje
  • Szülő span azonosító

Minden tartomány elküldésre kerül a tartománygyűjtőnek, hogy az adatbázisban tárolva legyen későbbi áttekintés céljából, amint a végrehajtás befejeződött. A jövőben létrehozhat egy fát az összes tartományból, ha szülőazonosítóval csatlakozik. Az elemzés során megtalálhatja például az összes olyan szolgáltatást, amely több időt vett igénybe. Ezen túlmenően, ha egy adott szakaszra lép, tekintse meg a teljes fát ezen tartomány felett és alatt.

Service Tracing, OpenTracing és Jaeger

Opentrace, Jagger és hogyan valósítottuk meg projektjeinkhez

Van egy közös szabvány opentrace, amely leírja, hogyan és mit kell gyűjteni, anélkül, hogy bármilyen nyelven egy konkrét implementációhoz lenne kötve. Például a Java-ban minden nyomkövetéssel végzett munka a közös Opentrace API-n keresztül történik, és alatta például a Jaeger vagy egy üres alapértelmezett implementáció, amely semmit sem csinál, elrejthető.
használunk Vadász az Opentrace megvalósításaként. Több összetevőből áll:

Service Tracing, OpenTracing és Jaeger

  • A Jaeger-agent egy helyi ügynök, amely általában minden gépre telepítve van, és a szolgáltatások a helyi alapértelmezett porton vannak bejelentkezve. Ha nincs ügynök, akkor ezen a gépen általában le van tiltva az összes szolgáltatás nyomkövetése
  • Jaeger-collector - minden ügynök elküldi az összegyűjtött nyomokat, és a kiválasztott adatbázisba helyezi azokat
  • Az adatbázis az általuk preferált cassandra, de az elaszticsearch-et használjuk, van néhány másik adatbázishoz való implementáció és egy memórián belüli megvalósítás, amely nem ment el semmit a lemezre
  • A Jaeger-query egy olyan szolgáltatás, amely bemegy az adatbázisba, és visszaadja a már összegyűjtött nyomokat elemzés céljából
  • A Jaeger-ui egy webes felület a nyomok keresésére és megtekintésére, a jaeger-query-re megy

Service Tracing, OpenTracing és Jaeger

Külön komponensnek nevezhetjük az opentrace jaeger implementációját meghatározott nyelvekhez, amelyen keresztül a spanokat küldik a jaeger-agentnek.
Jagger csatlakoztatása Java-ban Az io.opentracing.Tracer interfész megvalósítása, amely után az összes nyomkövetés a valódi ügynökhöz fog repülni.

Service Tracing, OpenTracing és Jaeger

A rugós alkatrészhez is csatlakoztatható opentracing-spring-cloud-starter és megvalósítás a Jaegertől opentracing-spring-jaeger-cloud-starter amely automatikusan beállítja a nyomkövetést mindazokhoz, amelyek áthaladnak ezeken az összetevőkön, például a vezérlőkhöz intézett http-kérések, a jdbc-n keresztüli adatbázis kérések stb.

Nyomkövetések naplózása Java-ban

Valahol a legfelső szinten létre kell hozni az első Span-t, ezt megteheti automatikusan, például a rugóvezérlővel, amikor egy kérés érkezik, vagy manuálisan, ha nincs. Ezt követően az alábbi hatókörön keresztül továbbítják. Ha az alábbi módszerek bármelyike ​​kiterjedést szeretne hozzáadni, akkor az aktuális aktív tartományt veszi a hatókörből, új tartományt hoz létre, és azt mondja, hogy a szülője a kapott activeSpan, majd az új tartományt aktívvá teszi. Külső szolgáltatások hívásakor az aktuális aktív tartomány átadásra kerül nekik, és ezek a szolgáltatások erre a tartományra hivatkozva hoznak létre új tartományokat.
Minden munka a Tracer-példányon megy keresztül, ezt a DI-mechanizmuson keresztül kaphatja meg, vagy a GlobalTracer.get ()-t globális változóként, ha a DI-mechanizmus nem működik. Alapértelmezés szerint, ha a nyomkövető nincs inicializálva, a NoopTracer visszatér, ami nem csinál semmit.
Továbbá az aktuális hatókör a nyomkövetőből a ScopeManageren keresztül kerül beszerzésre, a jelenlegiből új hatókör jön létre az új tartomány összerendelésével, majd a létrehozott hatókör bezárul, ami bezárja a létrehozott tartományt és visszaadja az előző Scope-ot az aktív állapot. A hatókör egy szálhoz van kötve, ezért többszálú programozáskor ne felejtse el átvinni az aktív szakaszt egy másik szálra, hogy egy másik szál hatókörét tovább aktiválja erre a szálra hivatkozva.

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

A többszálú programozáshoz a TracedExecutorService és hasonló burkolók is rendelkezésre állnak, amelyek automatikusan továbbítják az aktuális szakaszt a szálhoz, amikor aszinkron feladatokat indítanak:

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

Külső http kérésekhez van TracingHttpClient

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

Problémák, amelyekkel szembesültünk

  • A bab és a DI nem mindig működik, ha a nyomkövetőt nem használják szolgáltatásban vagy komponensben Automatikus bekötés Előfordulhat, hogy a Tracer nem működik, és a GlobalTracer.get() fájlt kell használnia.
  • Az annotációk nem működnek, ha nem komponensről vagy szolgáltatásról van szó, vagy ha a metódust ugyanazon osztály szomszédos metódusából hívják. Ügyeljen arra, hogy ellenőrizze, mi működik, és manuális nyomkövetést kell létrehoznia, ha a @Traced nem működik. Csatolhat egy további fordítót is a java megjegyzésekhez, akkor mindenhol működniük kell.
  • A régi rugós és rugós rendszerindításban az opentraing tavaszi felhő automatikus konfigurálása nem működik a DI hibái miatt, akkor ha azt szeretné, hogy a rugós összetevőkben lévő nyomok automatikusan működjenek, megteheti analógiával 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
  • Az erőforrásokkal való próbálkozás nem működik groovyban, végre kell próbálnia.
  • Minden szolgáltatásnak saját spring.application.name-vel kell rendelkeznie, amely alatt a nyomkövetések naplózásra kerülnek. Mit jelent egy külön név az eladásra és a tesztre, hogy ne zavarja őket együtt.
  • Ha GlobalTracer-t és tomcat-et használ, akkor az ebben a tomcatban futó összes szolgáltatásnak egy GlobalTracerje van, így mindegyiknek ugyanaz a szolgáltatásneve.
  • Amikor nyomvonalakat ad hozzá egy metódushoz, meg kell győződnie arról, hogy nem hívja meg sokszor egy ciklusban. Minden híváshoz hozzá kell adni egy közös nyomkövetést, amely garantálja a teljes munkaidőt. Ellenkező esetben többletterhelés jön létre.
  • Egyszer a jaeger-uiban túl nagy kérések érkeztek nagyszámú nyomra, és mivel nem vártak választ, újra megtették. Ennek eredményeként a jaeger-lekérdezés sok memóriát kezdett enni, és lelassította a rugalmasságot. A jaeger-query újraindítása segített

A nyomok mintavétele, tárolása és megtekintése

Három típusa van mintavételi nyomok:

  1. Const, amely elküldi és elmenti az összes nyomot.
  2. Valószínűségi, amely bizonyos valószínűséggel szűri a nyomokat.
  3. Ratelimiting, amely korlátozza a nyomok másodpercenkénti számát. Ezeket a beállításokat az ügyfélen konfigurálhatja, akár a jaeger-agenten, akár a gyűjtőn. Most a const 1-et használjuk az értékelő veremben, mivel nincs túl sok kérés, de sokáig tart. A jövőben, ha ez túlzottan megterheli a rendszert, korlátozhatja azt.

Ha cassandra-t használ, akkor alapértelmezés szerint csak két napig tárolja a nyomokat. használunk elasticsearch és a nyomok mindvégig tárolásra kerülnek, és nem törlődnek. Minden naphoz külön index jön létre, például jaeger-service-2019-03-04. A jövőben be kell állítania a régi nyomok automatikus tisztítását.

A nyomok megtekintéséhez szüksége van:

  • Válassza ki a szolgáltatást, amellyel a nyomkövetéseket szűrni szeretné, például a tomcat7-default olyan szolgáltatáshoz, amely a tomcatban fut, és nem lehet saját neve.
  • Ezután válassza ki a műveletet, az időintervallumot és a minimális működési időt, például 10 másodperctől, hogy csak hosszú végrehajtásokat végezzen.
    Service Tracing, OpenTracing és Jaeger
  • Menjen az egyik nyomvonalhoz, és nézze meg, mi lassult le ott.
    Service Tracing, OpenTracing és Jaeger

Továbbá, ha valamilyen kérésazonosító ismert, akkor ennek az azonosítónak a nyomát találhatja meg egy címkekereséssel, ha ez az azonosító a nyomkövetési tartományban naplózva van.

dokumentáció

Cikkek

Videó

Forrás: will.com

Hozzászólás