Sledování služeb, OpenTracing a Jaeger

Sledování služeb, OpenTracing a Jaeger

V našich projektech využíváme mikroservisní architekturu. Když nastanou úzká hrdla výkonu, mnoho času se stráví sledováním a analýzou protokolů. Při protokolování časování jednotlivých operací do souboru protokolu je obvykle obtížné pochopit, co vedlo k vyvolání těchto operací, sledovat sled akcí nebo časový posun jedné operace vůči druhé v různých službách.

Abychom minimalizovali ruční práci, rozhodli jsme se použít jeden z nástrojů pro sledování. O tom, jak a proč můžete použít trasování a jak jsme to udělali, a bude diskutováno v tomto článku.

Jaké problémy lze řešit pomocí trasování

  1. Najděte úzká hrdla výkonu jak v rámci jedné služby, tak v celém stromu provádění mezi všemi zúčastněnými službami. Například:
    • Mnoho krátkých po sobě jdoucích volání mezi službami, například do geokódování nebo do databáze.
    • Dlouhé I/O čekání, jako jsou síťové přenosy nebo čtení disku.
    • Dlouhá analýza dat.
    • Dlouhé operace vyžadující CPU.
    • Části kódu, které nejsou potřeba k získání konečného výsledku a mohou být odstraněny nebo zpožděny.
  2. Jasně pochopte, v jakém pořadí se co nazývá a co se stane, když je operace provedena.
    Sledování služeb, OpenTracing a Jaeger
    Je vidět, že např. přišel Požadavek na službu WS -> služba WS doplnila data přes službu R -> poté odeslala požadavek na službu V -> služba V načetla spoustu dat z Služba R -> odešla do služby P -> služba P odešla znovu do služby R -> služba V ignorovala výsledek a odešla do služby J -> a teprve poté vrátila odpověď službě WS, přičemž pokračovala ve výpočtu něčeho jiného v pozadí.
    Bez takové stopy nebo podrobné dokumentace k celému procesu je při prvním pohledu na kód velmi obtížné pochopit, co se děje, a kód je roztroušený po různých službách a skrytý za hromadou přihrádek a rozhraní.
  3. Sběr informací o exekučním stromu pro následnou odloženou analýzu. V každé fázi provádění můžete do trasování přidat informace, které jsou v této fázi k dispozici, a poté zjistit, jaká vstupní data vedla k podobnému scénáři. Například:
    • uživatelské ID
    • Práva
    • Typ zvolené metody
    • Chyba protokolu nebo provádění
  4. Přeměna stop na podmnožinu metrik a další analýza již ve formě metrik.

Jaká stopa může zaznamenat. Rozpětí

Při trasování existuje koncept rozpětí, což je analogie jednoho protokolu ke konzole. Lázně mají:

  • Název, obvykle název metody, která byla provedena
  • Název služby, ve které byl rozsah vygenerován
  • Vlastní unikátní ID
  • Nějaký druh metainformace ve formě klíče/hodnoty, který byl do něj přihlášen. Například parametry metody nebo metoda skončila s chybou nebo ne
  • Časy začátku a konce pro toto období
  • ID rodičovského rozsahu

Každé rozpětí je odesláno do kolektoru rozpětí, aby bylo uloženo v databázi pro pozdější kontrolu, jakmile bude dokončeno. V budoucnu můžete vytvořit strom všech rozsahů připojením pomocí ID rodiče. Při analýze můžete najít například všechna rozpětí v některé službě, která trvala déle než nějaký čas. Dále, když přejdete na konkrétní pole, uvidíte celý strom nad a pod tímto polem.

Sledování služeb, OpenTracing a Jaeger

Opentrace, Jagger a jak jsme to implementovali pro naše projekty

Existuje společný standard opentrace, který popisuje, jak a co by se mělo shromažďovat, aniž by byl vázán sledováním konkrétní implementace v jakémkoli jazyce. Například v Javě se veškerá práce se stopami provádí přes společné Opentrace API a pod ním se dá schovat třeba Jaeger nebo prázdná výchozí implementace, která nic nedělá.
Používáme Mořský pták jako implementace Opentrace. Skládá se z několika komponent:

Sledování služeb, OpenTracing a Jaeger

  • Jaeger-agent je místní agent, který je obvykle nainstalován na každém počítači a služby jsou do něj přihlášeny na místním výchozím portu. Pokud neexistuje žádný agent, jsou stopy všech služeb na tomto počítači obvykle zakázány
  • Jaeger-collector - všichni agenti do něj pošlou shromážděné stopy a on je vloží do vybrané databáze
  • Databáze je jejich preferovaná cassandra, ale my používáme elasticsearch, existují implementace pro pár dalších databází a implementace v paměti, která nic neukládá na disk
  • Jaeger-query je služba, která jde do databáze a vrací již shromážděné stopy k analýze
  • Jaeger-ui je webové rozhraní pro vyhledávání a prohlížení tras, jde do jaeger-query

Sledování služeb, OpenTracing a Jaeger

Samostatnou komponentou lze nazvat implementaci opentrace jaeger pro konkrétní jazyky, přes kterou jsou spans odesílány do jaeger-agent.
Připojení Jaggera v Javě přichází na řadu implementace rozhraní io.openracing.Tracer, po kterém všechny stopy přes něj poletí ke skutečnému agentovi.

Sledování služeb, OpenTracing a Jaeger

Také pro pružinový komponent můžete připojit opentracing-jarní-cloud-starter a implementace od společnosti Jaeger opentracing-spring-jaeger-cloud-starter který automaticky nakonfiguruje trasování pro vše, co prochází těmito komponentami, například http požadavky na řadiče, požadavky do databáze přes jdbc atd.

Trasování protokolování v Javě

Někde na nejvyšší úrovni musí být vytvořen první Span, to lze provést automaticky, například pružinovým ovladačem při přijetí požadavku, nebo ručně, pokud žádný není. Poté se přenáší prostřednictvím níže uvedeného rozsahu. Pokud některá z níže uvedených metod chce přidat Span, vezme aktuální activeSpan z rozsahu, vytvoří nové Span a řekne, že jeho nadřazeným je výsledné activeSpan, a učiní nový rozsah aktivním. Při volání externích služeb se jim předá aktuální aktivní rozsah a tyto služby vytvoří nové rozsahy s odkazem na tento rozsah.
Veškerá práce prochází instancí Tracer, můžete ji získat prostřednictvím mechanismu DI nebo GlobalTracer.get () jako globální proměnnou, pokud mechanismus DI nefunguje. Ve výchozím nastavení, pokud tracer nebyl inicializován, NoopTracer se vrátí, což nedělá nic.
Dále se aktuální rozsah získá z traceru přes ScopeManager, z aktuálního se vytvoří nový rozsah s vazbou nového rozsahu a poté se vytvořený rozsah uzavře, čímž se uzavře vytvořený rozsah a vrátí se předchozí rozsah do aktivní stav. Rozsah je vázán na vlákno, takže při vícevláknovém programování nesmíte zapomenout přenést aktivní rozsah do jiného vlákna, pro další aktivaci rozsahu jiného vlákna s odkazem na tento rozsah.

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

Pro programování s více vlákny existuje také TracedExecutorService a podobné moduly wrapper, které automaticky předají aktuální rozsah do vlákna, když jsou spuštěny asynchronní úlohy:

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

Pro externí http požadavky existuje TracingHttpClient

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

Problémy, kterým jsme čelili

  • Beans a DI nefungují vždy, pokud se tracer nepoužívá ve službě nebo komponentě Automaticky zapojeno Tracer nemusí fungovat a budete muset použít GlobalTracer.get().
  • Anotace nefungují, pokud se nejedná o komponentu nebo službu, nebo pokud je metoda volána ze sousední metody stejné třídy. Musíte být opatrní, abyste zkontrolovali, co funguje, a použijte ruční vytváření trasování, pokud @Traced nefunguje. Můžete také připojit další kompilátor pro java anotace, pak by měly fungovat všude.
  • Ve staré pružině a pružinové botě nefunguje automatická konfigurace jarního cloudu opentraing kvůli chybám v DI, pak pokud chcete, aby stopy v pružinových komponentách fungovaly automaticky, můžete to udělat analogicky s 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 nefunguje v groovy, musíte použít zkusit konečně.
  • Každá služba musí mít svůj vlastní spring.application.name, pod kterým se budou protokolovat trasování. Co dělá samostatný název pro prodej a test, aby je spolu nerušily.
  • Pokud používáte GlobalTracer a kocour, pak všechny služby spuštěné v tomto kocourku mají jeden GlobalTracer, takže všechny budou mít stejný název služby.
  • Při přidávání trasování do metody si musíte být jisti, že není volána mnohokrát ve smyčce. Pro všechny hovory je nutné přidat jednu společnou stopu, která zaručí celkovou dobu práce. V opačném případě se vytvoří nadměrné zatížení.
  • Jednou v jaeger-ui byly příliš velké požadavky na velké množství stop, a protože nečekali na odpověď, udělali to znovu. Výsledkem bylo, že jaeger-query začal jíst hodně paměti a zpomaloval elasticitu. Pomohlo restartování jaeger-query

Vzorkování, ukládání a prohlížení stop

Existují tři typy vzorkovací stopy:

  1. Const, který odesílá a ukládá všechny stopy.
  2. Pravděpodobnostní, která filtruje stopy s určitou pravděpodobností.
  3. Ratelimiting, který omezuje počet stop za sekundu. Tato nastavení můžete nakonfigurovat na klientovi, buď na jaeger-agent nebo na kolektoru. Nyní používáme const 1 ve valuator stack, protože požadavků není příliš mnoho, ale trvají dlouho. Pokud to v budoucnu způsobí nadměrné zatížení systému, můžete to omezit.

Pokud používáte cassandru, pak ve výchozím nastavení ukládá stopy pouze dva dny. Používáme elasticsearch a stopy jsou uloženy po celou dobu a nejsou vymazány. Pro každý den je vytvořen samostatný index, například jaeger-service-2019-03-04. V budoucnu budete muset nakonfigurovat automatické čištění starých stop.

K zobrazení tras potřebujete:

  • Vyberte službu, podle které chcete filtrovat trasování, například tomcat7-default pro službu, která běží v tomcat a nemůže mít svůj vlastní název.
  • Poté vyberte operaci, časový interval a minimální dobu operace, např. od 10 sekund, aby byla prováděna pouze dlouhá provedení.
    Sledování služeb, OpenTracing a Jaeger
  • Jděte na jednu ze stop a podívejte se, co se tam zpomalovalo.
    Sledování služeb, OpenTracing a Jaeger

Také, pokud je známo nějaké ID požadavku, můžete najít trasování podle tohoto id pomocí vyhledávání značek, pokud je toto id zaznamenáno v rozsahu trasování.

Документация

Články

Video

Zdroj: www.habr.com

Přidat komentář