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í
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.
Jasně pochopte, v jakém pořadí se co nazývá a co se stane, když je operace provedena.
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í.
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í
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.
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:
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
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.
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.
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()
);
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.
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
Pravděpodobnostní, která filtruje stopy s určitou pravděpodobností.
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í.
Jděte na jednu ze stop a podívejte se, co se tam zpomalovalo.
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í.