
Meie projektides kasutame mikroteenuste arhitektuuri. JĂ”udlusprobleemide ilmnemisel kulub palju aega jĂ€lgimisele ja logide analĂŒĂŒsimisele. Aegade logimine eri operatsioonide jaoks logifaili seab tavaliselt probleeme, kuna on keeruline mĂ”ista, mis viis nende operatsioonide kĂ€ivitamiseni, jĂ€lgida toimingute jĂ€rjestust vĂ”i ajastuse nihkumist ĂŒhe operatsiooni suhtes teise vahel erinevates teenustes.
KĂ€sitöö vĂ€hendamiseks otsustasime kasutada ĂŒhte jĂ€lgimisriista. Sellest, kuidas ja miks jĂ€lgimist kasutada ning kuidas meie seda tegime, rÀÀgib see artikkel.
Milliseid probleeme saab jÀlgimisega lahendada
- Leida kitsaskohti jĂ”udluses nii ĂŒhe teenuse sees kui ka kogu teostuse puus kĂ”igi osalevate teenuste vahel. NĂ€iteks:
- Palju lĂŒhikesi jĂ€rjestikuseid kutseid teenuste vahel, nĂ€iteks geokodeerimise vĂ”i andmebaasi pĂ€ringute puhul.
- Pikad ootamised sisendi / vÀljundi osas, nÀiteks andmete edastamine vÔrgus vÔi kettalt lugemine.
- Pikk andmete parsimine.
- Pikad operatsioonid, mis nÔuavad CPU-d.
- Koodijupid, mis ei ole vajalikud lÔpptulemuse saamiseks ja vÔiksid olla eemaldatud vÔi viidatud hiljem.
- Selgelt mÔista, millises jÀrjekorras asjad aset leiavad ja mis toimub, kui operatsioon kÀivitub.

NÀha, et nÀiteks pÀring tuli teenusesse WS -> teenus WS tÀiendas andmeid teenuse R kaudu -> seejÀrel saatis pÀringu teenusele V -> teenus V laadis palju andmeid teenusest R -> kÀidi teenuses P -> teenus P kÀis veel kord teenuses R -> teenus V ignoreeris tulemust ja lÀks teenusesse J -> ja alles seejÀrel naasis vastus teenusele WS, samal ajal jÀtkates midagi muud taustal arvutamist.
Ilma sellise jĂ€lgimata vĂ”i ĂŒksikasjaliku dokumentatsioonita kogu protsessi kohta on esmakordselt koodi vaadates vĂ€ga keeruline mĂ”ista, mis toimub, ja kood on hajutatud erinevatesse teenustesse ning peidetud mitmete beani ja liideste taha. - Teostuse puu teabe kogumine edasiseks analĂŒĂŒsiks. Igas teostusetapis saab jĂ€lgisse lisada teavet, mis on sellel etapil saadaval, ja hiljem tuvastada, millised sisendi andmed viisid antud stsenaariumi ilmnemiseni. NĂ€iteks:
- Kasutaja ID
- Ăigused
- Valitud meetodi tĂŒĂŒp
- Log vÔi töötluse viga
- KĂ€iguteede muutmine alameetriks ja edasine analĂŒĂŒs metrikate kujul.
Mida suudab logida jÀlgimine. Span
JĂ€lgimises on mĂ”isted span, mis on analoog ĂŒhele logile, konsoolis. Spanil on:
- Nimi, tavaliselt meetodi nimi, mis viidi lÀbi
- Teenuse nimi, milles span genereeriti
- Oma ainulaadne ID
- MÔni meta teave key/value kujul, mis on sinna logitud. NÀiteks meetodi parameetrid vÔi see, kas meetod lÔppes veaga vÔi mitte
- Span'i algus- ja lÔppkja aeg
- Vanema span'i ID
Iga span saadetakse spanide kollektsionÀÀrile, et salvestada see andmebaasi edasiseks vaatamiseks, niipea kui see on oma tĂ€itmise lĂ”petanud. Hiljem on vĂ”imalik ehitada kĂ”igi spanide puu, ĂŒhendades neid vanema ID jĂ€rgi. AnalĂŒĂŒsi kĂ€igus on vĂ”imalik leida nĂ€iteks kĂ”ik spandid mĂ”nes teenuses, mis vĂ”tsid rohkem aega kui teatud aeg. Edasi liikudes saab konkreetse span'i juurde minnes nĂ€ha kĂ”iki puu osi selle span'i kohal ja all.

Opentrace, Jaeger ja kuidas me seda oma projektides rakendasime
On olemas ĂŒldine standard , mis kirjeldab, kuidas ja mida peab koguma, mitte seondudes jĂ€lgimise konkreetse teostusega mĂ”nes keeles. NĂ€iteks Java-s kĂ€ib kogu jĂ€lgimistöötamine lĂ€bi ĂŒldise API Opentrace, ja selle all vĂ”ib peituda nĂ€iteks Jaeger vĂ”i tĂŒhi vaikimisi teostus, mis ei tee midagi.
Meie sĂŒsteem kasutab kui Opentrace'i teostust. See koosneb mitmest komponendist:

- Jaeger-agent â kohalik agent, mis on tavaliselt igas masinas ja kuhu logivad teenused kohalikke vaikimisi porte. Kui agenti pole, siis on kĂ”igi selle masina teenuste jĂ€lgimised tavaliselt vĂ€lja lĂŒlitatud
- Jaeger-kollektor â kuhu kĂ”ik agendid saadavad kogutud jĂ€lgimised ning mis salvestab need valitud andmebaasi
- Andmebaas â nende eelistatuim on Cassandra, kuid meie kasutame Elasticsearchi, on olemas teostusi ka mĂ”ne muu andmebaasi ja mĂ€lu teostuse jaoks, mis ei salvestada midagi kettale
- Jaeger-kĂŒsimus â see on teenus, mis lĂ€heb andmebaasi ja toob juba kogutud jĂ€lgimised analĂŒĂŒsiks
- Jaeger-ui â see on veebirakendus jĂ€lgimiste otsimiseks ja vaatamiseks, mis lĂ€heb jaeger-kĂŒsimusse

Eraldi komponendina vÔib nimetada opentrace jaeger'i teostust konkreetsete keelte jaoks, mille kaudu span'id saadetakse jaeger-agenti.
see on nÀhtav, et rakendada liidest io.opentracing.Tracer, mille jÀrel kÔik jÀljed suunatakse lÀbi selle tegelikule agentile.

Samuti saab Springi komponente ĂŒhendada ja Jaegeri teostus , mis konfigureerib automaatselt jĂ€lgimise kĂ”igile, mis lĂ€bib neid komponente, nĂ€iteks HTTP-pĂ€ringud kontrolleritesse, andmebaasi pĂ€ringud lĂ€bi jdbc jne.
JĂ€lgede logimine Java-s
Kusagil kÔige kÔrgeimal tasemel peaks olema loodud esimene Span, see vÔib toimuda automaatselt nÀiteks Springi kontrolleri kaudu pÀringu saamisel vÔi kÀsitsi, kui sellist ei ole. Edasi edastatakse see alla Scope'i. Kui mÔni allolev meetod soovib lisada Span'i, vÔtab ta Scope'ist praeguse activeSpan'i, loob uue Span'i ja mÀÀrab, et tema vanem on saadud activeSpan, ning teeb uue Span'i aktiivseks. VÀlistele teenustele edastatakse praegune aktiivne span ja need teenused loovad uued spanid, mis on seotud sellega.
Kogu töö kÀib Tracer'i nÀite kaudu, mille saab saada DI mehhanismi abil vÔi GlobalTracer.get() kui globaalse muutujana, kui DI mehhanism ei tööta. Kui tracer ei ole algselt initsialiseeritud, naaseb NoopTracer, mis ei tee midagi.
SeejĂ€rel vĂ”etakse tracer'ist lĂ€bi ScopeManager'i praegune scope, luuakse uus scope praegusest, side uue span'iga, ja seejĂ€rel suletakse loodud Scope, mis sulgeb loodud span'i ja taastab varasema Scope'i aktiivseks olekuks. Scope on seotud ĂŒhe niidiga, seetĂ”ttu tuleb mitme niidi programmeerimisel meeles pidada, et edastada aktiivne span teisele niidile, et aktiveerida teise niidi Scope, mis on seotud selle span'iga.
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)) {
// Tee asju.
} 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: aktiveeri span tagasi callbackis, edastades true
// startActive() juhul, kui span peab olema lÔpetatud.
try (Scope scope = tracer.scopeManager().activate(span, false)) {
...
}
});
}
}Mitme lĂ”ime programmeerimiseks on olemas TracedExecutorService ja sarnased wrapper'id, mis edastavad automaatselt praeguse spani lĂ”ime, kui asĂŒnkroonsed ĂŒlesanded kĂ€ivitatakse:
private ExecutorService executor = new TracedExecutorService(
Executors.newFixedThreadPool(10), GlobalTracer.get()
);VÀliste http pÀringute jaoks on olemas
HttpClient httpClient = new TracingHttpClientBuilder().build();Probleemid, millega me silmitsi seisame
- Beendid ja DI ei pruugi alati töötada, kui tracerit ei kasutata teenuses vÔi komponendis, siis Tracer ei pruugi töötada ja tuleb kasutada GlobalTracer.get().
- Annotatsioonid ei tööta, kui see ei ole komponent vÔi teenus, vÔi kui meetodi kutsumine toimub sama klassi naabermetodist. Tuleb olla ettevaatlik, kontrollida, mis töötab, ja kasutada manuaalset jÀlgimise loomist, kui @Traced ei tööta. Samuti saab lisada tÀiendava kompilaatori java annotatsioonide jaoks, siis peaks need töötama igal pool.
- Vanades spring ja spring boot versioonides ei toimi opentracing spring cloud automaatne seadistamine DI vigade tÔttu, seega, kui soovite, et jÀlgimised komponentides automaatselt töötaksid, siis vÔib teha sarnaselt
- Groovy's ei toimi try with resources, tuleb kindlasti kasutada try finally.
- Iga teenuse kohta tuleb mÀÀrata oma spring.application.name, mille alusel jÀlgimised logitakse. Eraldi nimi tootmises ja testimises, et nad koos ei seguneks.
- Kui kasutada GlobalTracerit ja tomcat, siis kĂ”ik teenused, mis on selles tomcat'is kĂ€ivitatud, jagavad ĂŒhte GlobalTracerit, seega on kĂ”igil sama teenuse nimi.
- JĂ€lgimiste lisamisel meetodisse tuleb olla kindel, et seda ei kutsuta tsĂŒklis liiga sageli. Tuleb lisada ĂŒks ĂŒhine jĂ€lgimine kĂ”igile kutsetele, mis logib koguaegade kokku. Vastasel juhul tekib liigset koormust.
- Kord, kui jaeger-ui's tehti liiga suuri pÀringuid suure hulga jÀlgimiste kohta ja kuna ei oodatud vastust, tehti see uuesti. Tulemuseks oli, et jaeger-query hakkas kasutama palju mÀlu ja aeglustas elastikut. Taastas jaeger-query'i taaskÀivitamine aitas.
JÀlgimiste proovivÔtt, salvestamine ja vaatamine
On kolm tĂŒĂŒpi :
- Const, mis saadab ja salvestab kÔik jÀlgimised.
- Probabilistic, mis filtreerib jÀlgimisi kindla tÔenÀosusega.
- Ratelimiting, mis piirab tehingute arvu sekundis. Nende parameetreid saab seadistada kliendil, kas jaeger-agendis vĂ”i kogujas. Praegu on meil rakendustes kasutusel const 1, kuna pĂ€ringute arv ei ole liiga suur, kuid need vĂ”tavad aega. Edasi, kui see sĂŒsteemile liiga palju koormust tekitab, saab piirata.
Kui kasutada cassandrat, siis salvestab see tehingud vaikimisi ainult kaheks pÀevaks. Meie puhul kasutatakse ja tehingud salvestatakse kogu aeg ja ei kustutata. Igal pÀeval luuakse eraldi indeks, nÀiteks jaeger-service-2019-03-04. Tulevikus tuleb seadistada automaatne vana tehingu kustutamine.
Tehingute vaatamiseks tuleks:
- Valida teenus, mille pÔhjal soovid tehinguid filtreerida, nÀiteks tomcat7-default teenuse puhul, mis on kÀivitatud tomcat-is ega saa omada oma nime.
- SeejÀrel valida operatsioon, ajavahemik ja minimaalne operatsiooni aeg, nÀiteks alates 10 sekundist, et vÔtta ainult pikki tÀitmisperioode.

- Liikuda ĂŒhe tehingu juurde ja vaadata, mis seal takistab.

Samuti, kui on teada mÔni pÀringu ID, siis saab leida tehingu selle ID kaudu, otsides silte, kui see ID logitakse tehingu span'i.
Dokumentatsioon
- Opentracingi dokumentatsioon
- Jaegeri dokumentatsioon
- Jaegeri Java ĂŒhendamine
- Spring Opentracing ĂŒhendamine
Artiklid
- Jaeger Opentracing ja mikroteenused reaalses projektis PHP ja Golangi peal
- Evolving Distributed Tracing at Uber Engineering
- Running Jaeger Agent on bare metal
Video
- How We Used Jaeger and Prometheus to Deliver Lightning-Fast User Queries â Bryan Boreham
- Intro: Jaeger â Yuri Shkuro, Uber & Pavol Loffay, Red Hat
- Serghei Iakovlev, "VÀike lugu suurest vÔidust: OpenTracing, AWS ja Jaeger"
Allikas: habr.com



