Pagsubaybay sa Serbisyo, OpenTracing at Jaeger

Pagsubaybay sa Serbisyo, OpenTracing at Jaeger

Gumagamit kami ng microservice architecture sa aming mga proyekto. Kapag nangyari ang mga bottleneck sa pagganap, maraming oras ang ginugugol sa pagsubaybay at pag-parse ng mga log. Kapag nagla-log ng mga timing ng mga indibidwal na operasyon sa isang log file, kadalasan ay mahirap na maunawaan kung ano ang humantong sa panawagan ng mga operasyong ito, upang subaybayan ang pagkakasunud-sunod ng mga aksyon o ang paglilipat ng oras ng isang operasyon na may kaugnayan sa isa pa sa iba't ibang mga serbisyo.

Upang mabawasan ang manu-manong paggawa, nagpasya kaming gumamit ng isa sa mga tool sa pagsubaybay. Tungkol sa kung paano at bakit mo magagamit ang pagsubaybay at kung paano namin ito ginawa, at tatalakayin sa artikulong ito.

Anong mga problema ang maaaring malutas sa pagsubaybay

  1. Maghanap ng mga bottleneck sa pagganap sa loob ng iisang serbisyo at sa buong execution tree sa pagitan ng lahat ng mga kalahok na serbisyo. Halimbawa:
    • Maraming maiikling magkakasunod na tawag sa pagitan ng mga serbisyo, halimbawa, sa geocoding o sa isang database.
    • Mahabang paghihintay ng I/O, gaya ng mga paglilipat ng network o pagbabasa ng disk.
    • Mahabang pag-parse ng data.
    • Mahabang operasyon na nangangailangan ng cpu.
    • Mga seksyon ng code na hindi kailangan para makuha ang huling resulta at maaaring alisin o maantala.
  2. Malinaw na maunawaan kung anong pagkakasunud-sunod kung ano ang tinatawag at kung ano ang mangyayari kapag isinagawa ang operasyon.
    Pagsubaybay sa Serbisyo, OpenTracing at Jaeger
    Makikita na, halimbawa, ang Kahilingan ay dumating sa serbisyo ng WS -> ang serbisyo ng WS ay nagdagdag ng data sa pamamagitan ng serbisyo ng R -> pagkatapos ay nagpadala ng isang kahilingan sa serbisyo ng V -> ang serbisyo ng V ay nag-load ng maraming data mula sa serbisyo ng R -> pumunta sa serbisyo ng P -> ang serbisyo ng P ay pumunta sa serbisyong R muli -> binalewala ng serbisyong V ang resulta at pumunta sa serbisyo ng J -> at pagkatapos ay ibinalik lamang ang tugon sa serbisyo ng WS, habang nagpapatuloy ang iba pang bagay.
    Kung walang ganoong bakas o detalyadong dokumentasyon para sa buong proseso, napakahirap maunawaan kung ano ang nangyayari kapag tinitingnan ang code sa unang pagkakataon, at ang code ay nakakalat sa iba't ibang serbisyo at nakatago sa likod ng isang bungkos ng mga bin at interface.
  3. Koleksyon ng impormasyon tungkol sa puno ng pagpapatupad para sa kasunod na ipinagpaliban na pagsusuri. Sa bawat yugto ng pagpapatupad, maaari kang magdagdag ng impormasyon sa bakas na magagamit sa yugtong ito at pagkatapos ay malaman kung anong data ng input ang humantong sa isang katulad na sitwasyon. Halimbawa:
    • User ID
    • Mga Karapatan
    • Uri ng napiling paraan
    • Log o error sa pagpapatupad
  4. Ang paggawa ng mga bakas sa isang subset ng mga sukatan at karagdagang pagsusuri ay nasa anyo na ng mga sukatan.

Anong bakas ang maaaring i-log. Span

Sa pagsubaybay doon ay ang konsepto ng isang span, ito ay isang analogue ng isang log, sa console. Ang spa ay may:

  • Pangalan, kadalasan ang pangalan ng pamamaraan na isinagawa
  • Ang pangalan ng serbisyo kung saan nabuo ang span
  • Sariling natatanging ID
  • Ilang uri ng meta information sa anyo ng isang key/value na naka-log in dito. Halimbawa, ang mga parameter ng pamamaraan o ang pamamaraan ay natapos sa isang error o hindi
  • Mga oras ng pagsisimula at pagtatapos para sa span na ito
  • ID ng parent span

Ang bawat span ay ipinapadala sa span collector upang maiimbak sa database para sa pagsusuri sa ibang pagkakataon sa sandaling makumpleto nito ang pagpapatupad nito. Sa hinaharap, maaari kang bumuo ng isang puno ng lahat ng mga span sa pamamagitan ng pagkonekta sa pamamagitan ng parent id. Kapag nagsusuri, mahahanap mo, halimbawa, ang lahat ng mga span sa ilang serbisyo na tumagal nang higit sa ilang oras. Dagdag pa, sa pamamagitan ng pagpunta sa isang partikular na span, tingnan ang buong puno sa itaas at ibaba ng span na ito.

Pagsubaybay sa Serbisyo, OpenTracing at Jaeger

Opentrace, Jagger at kung paano namin ito ipinatupad para sa aming mga proyekto

Mayroong karaniwang pamantayan opentrace, na naglalarawan kung paano at ano ang dapat kolektahin, nang hindi nakatali sa pamamagitan ng pagsubaybay sa isang partikular na pagpapatupad sa anumang wika. Halimbawa, sa Java, ang lahat ng trabaho na may mga bakas ay isinasagawa sa pamamagitan ng karaniwang Opentrace API, at sa ilalim nito, halimbawa, ang Jaeger o isang walang laman na default na pagpapatupad na walang ginagawa ay maaaring maitago.
Ginagamit namin Snayper bilang isang pagpapatupad ng Opentrace. Binubuo ito ng ilang bahagi:

Pagsubaybay sa Serbisyo, OpenTracing at Jaeger

  • Ang Jaeger-agent ay isang lokal na ahente na karaniwang naka-install sa bawat makina at ang mga serbisyo ay naka-log in dito sa lokal na default na port. Kung walang ahente, karaniwang hindi pinagana ang mga bakas ng lahat ng serbisyo sa makinang ito
  • Jaeger-collector - lahat ng ahente ay nagpapadala ng mga nakolektang bakas dito, at inilalagay sila sa napiling database
  • Ang database ay ang kanilang ginustong cassandra, ngunit gumagamit kami ng elasticsearch, may mga pagpapatupad para sa ilang iba pang mga database at isang in-memory na pagpapatupad na hindi nagse-save ng kahit ano sa disk
  • Ang Jaeger-query ay isang serbisyo na pumupunta sa database at nagbabalik ng mga nakolekta na bakas para sa pagsusuri
  • Ang Jaeger-ui ay isang web interface para sa paghahanap at pagtingin sa mga bakas, napupunta ito sa jaeger-query

Pagsubaybay sa Serbisyo, OpenTracing at Jaeger

Ang isang hiwalay na bahagi ay maaaring tawaging pagpapatupad ng opentrace jaeger para sa mga partikular na wika, kung saan ipinapadala ang mga span sa jaeger-agent.
Pagkonekta ng Jagger sa Java bumababa sa pagpapatupad ng interface ng io.opentracing.Tracer, pagkatapos nito ang lahat ng mga bakas sa pamamagitan nito ay lilipad sa tunay na ahente.

Pagsubaybay sa Serbisyo, OpenTracing at Jaeger

Gayundin para sa bahagi ng tagsibol, maaari kang kumonekta opentracing-spring-cloud-starter at pagpapatupad mula kay Jaeger opentracing-spring-jaeger-cloud-starter na awtomatikong magko-configure ng pagsubaybay para sa lahat ng dumadaan sa mga bahaging ito, halimbawa mga kahilingan ng http sa mga controller, mga kahilingan sa database sa pamamagitan ng jdbc, atbp.

Mga bakas ng pag-log in sa Java

Sa isang lugar sa pinakamataas na antas, dapat gawin ang unang Span, maaari itong awtomatikong gawin, halimbawa, ng spring controller kapag natanggap ang isang kahilingan, o manu-mano kung wala. Pagkatapos ay ipinapadala ito sa pamamagitan ng Saklaw sa ibaba. Kung ang alinman sa mga pamamaraan sa ibaba ay gustong magdagdag ng Span, kukunin nito ang kasalukuyang activeSpan mula sa Saklaw, gagawa ng bagong Span at nagsasabing ang magulang nito ay ang nagreresultang activeSpan, at ginagawang aktibo ang bagong Span. Kapag tumatawag sa mga panlabas na serbisyo, ang kasalukuyang aktibong span ay ipinapasa sa kanila, at ang mga serbisyong iyon ay lumikha ng mga bagong span na may reference sa span na ito.
Ang lahat ng trabaho ay dumadaan sa Tracer instance, makukuha mo ito sa pamamagitan ng DI mechanism, o GlobalTracer.get () bilang global variable kung hindi gumana ang DI mechanism. Bilang default, kung hindi pa nasimulan ang tracer, babalik ang NoopTracer na walang ginagawa.
Dagdag pa, ang kasalukuyang saklaw ay nakuha mula sa tracer sa pamamagitan ng ScopeManager, isang bagong saklaw ay nilikha mula sa kasalukuyang isa na may isang pagbubuklod ng bagong span, at pagkatapos ay ang nilikha na Saklaw ay sarado, na magsasara sa nilikha na span at ibabalik ang nakaraang Saklaw sa aktibong estado. Ang saklaw ay nakatali sa isang thread, kaya kapag multi-threaded programming, hindi mo dapat kalimutang ilipat ang aktibong span sa isa pang thread, para sa karagdagang pag-activate ng Saklaw ng isa pang thread na may reference sa span na ito.

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

Para sa multi-threaded programming, mayroon ding TracedExecutorService at mga katulad na wrapper na awtomatikong nagpapasa ng kasalukuyang span sa thread kapag inilunsad ang mga asynchronous na gawain:

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

Para sa mga panlabas na kahilingan sa http ay mayroon TracingHttpClient

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

Mga problemang ating kinaharap

  • Ang beans at DI ay hindi palaging gumagana kung ang tracer ay hindi ginagamit sa isang serbisyo o bahagi, kung gayon Autowired Maaaring hindi gumana ang tracer at kakailanganin mong gumamit ng GlobalTracer.get().
  • Ang mga anotasyon ay hindi gagana kung ito ay hindi isang bahagi o serbisyo, o kung ang pamamaraan ay tinawag mula sa isang kalapit na pamamaraan ng parehong klase. Kailangan mong mag-ingat upang suriin kung ano ang gumagana at gumamit ng manu-manong paggawa ng bakas kung hindi gumana ang @Traced. Maaari ka ring mag-attach ng karagdagang compiler para sa mga java annotation, pagkatapos ay dapat gumana ang mga ito kahit saan.
  • Sa lumang spring at spring boot, hindi gumagana ang opentraing spring cloud autoconfiguration dahil sa mga bug sa DI, kung gusto mong awtomatikong gumana ang mga bakas sa mga bahagi ng spring, magagawa mo ito sa pamamagitan ng pagkakatulad sa 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
  • Subukan sa mga mapagkukunan ay hindi gumagana sa groovy, dapat mong gamitin subukan sa wakas.
  • Ang bawat serbisyo ay dapat magkaroon ng sarili nitong spring.application.name kung saan ang mga bakas ay mai-log. Ano ang isang hiwalay na pangalan para sa pagbebenta at pagsubok, upang hindi makagambala sa kanila nang magkasama.
  • Kung gagamit ka ng GlobalTracer at tomcat, lahat ng serbisyong tumatakbo sa tomcat na ito ay may isang GlobalTracer, kaya lahat sila ay magkakaroon ng parehong pangalan ng serbisyo.
  • Kapag nagdaragdag ng mga bakas sa isang pamamaraan, kailangan mong tiyakin na hindi ito tinatawag nang maraming beses sa isang loop. Kinakailangang magdagdag ng isang karaniwang bakas para sa lahat ng mga tawag, na ginagarantiyahan ang kabuuang oras ng trabaho. Kung hindi, magkakaroon ng labis na pagkarga.
  • Sa sandaling nasa jaeger-ui, napakaraming kahilingan ang ginawa para sa isang malaking bilang ng mga bakas, at dahil hindi sila naghintay ng tugon, ginawa nila itong muli. Bilang resulta, ang jaeger-query ay nagsimulang kumain ng maraming memorya at bumagal ang pagkalastiko. Nakatulong sa pamamagitan ng pag-restart ng jaeger-query

Pag-sample, pag-iimbak at pagtingin sa mga bakas

May tatlong uri mga bakas ng sampling:

  1. Const na nagpapadala at nagse-save ng lahat ng mga bakas.
  2. Probabilistic na nagsasala ng mga bakas na may ilang ibinigay na posibilidad.
  3. Ratelimting na naglilimita sa bilang ng mga bakas bawat segundo. Maaari mong i-configure ang mga setting na ito sa client, alinman sa jaeger-agent o sa collector. Ngayon ginagamit namin ang const 1 sa valuator stack, dahil walang masyadong mga kahilingan, ngunit tumatagal sila ng mahabang panahon. Sa hinaharap, kung magkakaroon ito ng labis na pagkarga sa system, maaari mo itong limitahan.

Kung gumagamit ka ng cassandra, pagkatapos ay sa pamamagitan ng default ay nag-iimbak lamang ito ng mga bakas sa loob ng dalawang araw. Ginagamit namin nababanat at ang mga bakas ay iniimbak para sa lahat ng oras at hindi tinatanggal. Ang isang hiwalay na index ay ginawa para sa bawat araw, halimbawa jaeger-service-2019-03-04. Sa hinaharap, kailangan mong i-configure ang awtomatikong paglilinis ng mga lumang bakas.

Upang makita ang mga bakas na kailangan mo:

  • Piliin ang serbisyo kung saan mo gustong mag-filter ng mga bakas, halimbawa, tomcat7-default para sa isang serbisyo na tumatakbo sa tomcat at hindi maaaring magkaroon ng sarili nitong pangalan.
  • Pagkatapos ay piliin ang operasyon, ang agwat ng oras at ang pinakamababang oras ng pagpapatakbo, halimbawa mula sa 10 segundo, upang tumagal lamang ng mahabang pagpapatupad.
    Pagsubaybay sa Serbisyo, OpenTracing at Jaeger
  • Pumunta sa isa sa mga bakas at tingnan kung ano ang bumabagal doon.
    Pagsubaybay sa Serbisyo, OpenTracing at Jaeger

Gayundin, kung alam ang ilang request id, makakahanap ka ng trace sa pamamagitan ng id na ito sa pamamagitan ng paghahanap ng tag, kung naka-log ang id na ito sa trace span.

Records

Artikulo

video

Pinagmulan: www.habr.com

Magdagdag ng komento