Integrace Jaeger s aplikací Spring Boot

(Himank Batra) (9. září) , 2020)

Jaeger Integration with Spring Boot Application

Pojďme nejprve pochopit, co je Jaeger

Jaeger je open source software pro sledování transakcí mezi distribuovanými službami.

Používá se pro monitorování a řešení problémů komplexních prostředí mikroslužeb.

Společnost Uber pro spolujízdu vyvinula Jaeger jako projekt open source v roce 2015. Byl přijat jako cloud Inkubační projekt Native Computing Foundation (CNCF) v roce 2017 a v roce 2019 povýšený na status absolventa.

Co je distribuované trasování?

Distribuované trasování je způsob, jak vidět a porozumět Celý řetězec událostí ve složité interakci mezi mikroslužbami.

Moderní vývoj softwaru založeného na cloudu se opírá o mikroslužby: nezávislé služby, z nichž každá poskytuje jinou základní funkci. Když uživatel odešle požadavek v aplikaci, mnoho jednotlivých služeb odpoví a vytvoří výsledek.

Jediné volání v aplikaci může vyvolat desítky různých služeb, které spolu interagují. Jak mohou vývojáři a inženýři izolovat problém, když se něco pokazí nebo požadavek běží pomalu? Potřebujeme způsob, jak sledovat všechna připojení.

Odtud přichází distribuované trasování. Často se spouští jako součást sítě služeb, což je způsob, jak spravovat a sledovat mikroslužby.

Jaeger používá distribuované trasování, aby sledoval cestu požadavku prostřednictvím různých mikroslužeb. Místo hádání vidíme vizuální znázornění toků volání.

Organizované informace o transakcích jsou užitečné pro ladění a optimalizaci. Jaeger zahrnuje nástroje pro sledování distribuovaných transakcí, optimalizaci výkonu a latence a provádění analýzy kořenových příčin (RCA), což je metoda řešení problémů.

Jaegerova terminologie a komponenty

Jaeger předkládá žádosti o provedení jako stopy . Trasa zobrazuje cestu k datům / provádění v systému.

Trasa se skládá z jednoho nebo více rozpětí . Rozpětí je logická jednotka práce v Jaegeru. Každé rozpětí zahrnuje název operace, čas zahájení a dobu trvání. Rozpětí mohou být vnořena a uspořádána.

Jaeger obsahuje několik komponent, které společně shromažďují, ukládají a vizualizují rozpětí a stopy.

Jaeger Client zahrnuje jazyk -špecifické implementace OpenTracing API pro distribuované trasování. Lze je použít ručně nebo s řadou open-source frameworků.

Jaeger Agent je síťový démon, který poslouchá rozpětí zasílaná přes User Datagram Protocol. Agent má být umístěn na stejném hostiteli jako instrumentovaná aplikace. To je obvykle implementováno pomocí postranního vozíku v prostředích kontejnerů, jako je Kubernetes.

Jaeger Collector přijímá rozpětí a umístí je do fronty ke zpracování.

Sběratelé vyžadují trvalý back-end úložiště, takže Jaeger má také zásuvný mechanismus pro span storeage.

Query je služba, která načítá stopy z úložiště.

Jaeger Console je uživatelské rozhraní, které vám umožní vizualizovat distribuovaná sledovací data.

Proč Jaeger?

Jak si praktičtí pracovníci mikroslužeb v terénu rychle uvědomují, většina provozních problémů, které vzniknou při přechodu na distribuovanou architekturu, je nakonec zakotvena ve dvou oblastech: síť a pozorovatelnost. Je to prostě řádově větší problém se sítí a laděním sady propletených distribuovaných služeb oproti jediné monolitické aplikaci.

Jaeger v akci

Budeme integrovat jaeger do jarních zaváděcích aplikací.

Nejprve si pojďme rychle nastavit naše jarní zaváděcí aplikace.

Myšlenkou zde je generování jmen spojením slavných vědeckých jmen se jmény zvířat.

Takže vytvoříme 3 mikroslužby pomocí jarního bootování, tj. animal-name-service , name-generator-service, a scientist-name-service.

Požadavek klienta na jméno zřetězeného vědce a zvířete z name-generator-service který interně volá název-zvířete-služba a vědecký_název_služby.

To samé ukazuje následující diagram.

Příklad mikroslužby

Pojďme rychle vytvořit naše tři mikroslužby pomocí jarní inicializace r.

Přidáme závislost spring-boot-starter-web při generování jarních zaváděcích aplikací.

Nyní máme připraveny 3 jarní zaváděcí aplikace. Přidejte tyto 3 mikroslužby do složky s názvem opentracing-microservices-example.

A importujte tuto složku do svého oblíbeného editoru. Používám IntelliJ .

Jak musíme zavolat animal-name-service a scientist- name-service from name-generator-service.

Za tímto účelem jsme se rozhodli předstírat klienta. Pojďme tedy přidat spring-cloud-starter-openfeign: 2.2.3.RELEASE závislost v name-generator-service.

Zde je kód pro všechny 3 mikroslužby.

AnimalNameService :

package com.example.ans;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.core.io.ClassPathResource;import org.springframework.http.HttpHeaders;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestHeader;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.List;import java.util.Random;import java.util.stream.Collectors;@SpringBootApplication
public class AnimalNameService {public static void main(String[] args) {SpringApplication.run(AnimalNameService.class, args);}}@RestController
@RequestMapping("/api/v1/animals")
class AnimalNameResource {private final List animalNames;private Random random;public AnimalNameResource() throws IOException {InputStream inputStream = new ClassPathResource("/animals.txt").getInputStream();try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {animalNames = reader.lines().collect(Collectors.toList());}random = new Random();}@GetMapping(path = "/random")
public String name(@RequestHeader HttpHeaders headers) {String name = animalNames.get(random.nextInt(animalNames.size()));return name;}}

application.properties:

server.port=9000

NameGeneratorService:

Zde používám com.shekhargulati: strman: 0,4 Knihovna .0 pro převod názvu zvířete a vědce na případ kebabu.

package com.example.ngs;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.openfeign.EnableFeignClients;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import static strman.Strman.toKebabCase;@SpringBootApplication
@EnableFeignClients
public class NameGeneratorService {public static void main(String[] args) {SpringApplication.run(NameGeneratorService.class, args);}}@FeignClient(name = "scientist-service-client", url = "${scientist.service.prefix.url}")
interface ScientistServiceClient {@GetMapping("/api/v1/scientists/random")
String randomScientistName();}@FeignClient(name = "animal-service-client", url = "${animal.service.prefix.url}")
interface AnimalServiceClient {@GetMapping("/api/v1/animals/random")
String randomAnimalName();}@RestController
@RequestMapping("/api/v1/names")
class NameResource {@Autowired
private AnimalServiceClient animalServiceClient;@Autowired
private ScientistServiceClient scientistServiceClient;@GetMapping(path = "/random")
public String name() throws Exception {String animal = animalServiceClient.randomAnimalName();String scientist = scientistServiceClient.randomScientistName();String name = toKebabCase(scientist) + "-" + toKebabCase(animal);return name;}}

application.properties:

server.port=8080scientist.service.prefix.url=http://localhost:8090animal.service.prefix.url=http://localhost:9000

ScientistNameService:

package com.example.sns;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.core.io.ClassPathResource;import org.springframework.http.HttpHeaders;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestHeader;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.List;import java.util.Random;import java.util.stream.Collectors;@SpringBootApplication
public class ScientistNameService {public static void main(String[] args) {SpringApplication.run(ScientistNameService.class, args);}}@RestController
@RequestMapping("/api/v1/scientists")
class ScientistNameResource {private final List scientistsNames;private Random random;public ScientistNameResource() throws IOException {InputStream inputStream = new ClassPathResource("/scientists.txt").getInputStream();try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {scientistsNames = reader.lines().collect(Collectors.toList());}random = new Random();}@GetMapping(path = "/random")
public String name(@RequestHeader HttpHeaders headers) {String name = scientistsNames.get(random.nextInt(scientistsNames.size()));return name;}}

application.properties :

server.port=8090

Nyní spustíme všechny 3 aplikace a přejdeme na http: // localhost: 8080 / api / v1 / names / random v prohlížeči.

Dostaneme příklad náhodného jména: john-cockcroft-snapping-turtle

Takže teď naše aplikace nastavení je hotovo.

Nyní integrujme jaeger do těchto aplikací, abychom mohli sledovat Každý požadavek.

Do všech 3 pom.xml stačí přidat níže uvedenou závislost.


io.opentracing.contrib
opentracing-spring-jaeger-cloud-starter3.1.2

A musíme přidat níže uvedené vlastnosti do souboru application.properties pro všechny 3 aplikace.

spring.application.name= // example : name-generator-service (this will be displayed in jaeger for respective service)opentracing.jaeger.udp-sender.host=localhost //udp host for sender. By default Jaeger libraries use a UDP sender to report finished spans to the jaeger-agent daemonopentracing.jaeger.udp-sender.port=6831 // udp portopentracing.jaeger.log-spans=true // logs the spans in console

Spustit Jaeger v ukotvitelném panelu pomocí následujícího příkazu:

docker run -p 9090:16686 — name jaeger -d jaegertracing/all-in-one:1.17

Nyní restartujte aplikaci. A v prohlížeči přejděte na localhost: 9090. Dostaneme domovskou stránku Jaeger.

V prohlížeči také přejděte na http: // localhost: 8080 / api / v1 / names / random . Podobně získáte náhodné jméno.

Ale nyní můžeme požadavek vystopovat. Zaškrtněte na palubní desce Jaeger, vyberte službu name-generator-service.

a poté klikněte na stopy hledání. získáme stopy, jak je znázorněno na následujícím obrázku pro název-generátor-služby .

Služba generátoru jmen Jaeger

Jasně vidíme, že při podrobném zkoumání máme 5 rozpětí.

název-generátor-služba (1 rozpětí)

název-generátor-služba-> zvíře-název-služba (2 rozpětí)

název-generátor-služba-> vědec- name-service (2 rozpětí)

Toto je znázorněno na následujícím obrázku.

Trasování služby generátoru názvu Jaeger

Zde je vše automaticky konfigurováno opentracing-spring-jaeger-cloud-starter knihovna, která má třídu s názvem TracingAspect v podstatě dělá magii.

@Aspect
class TracingAspect {
TracingAspect() {
}

@Around("execution (* feign.Client.*(..)) && !within(is(FinalType))")
public Object feignClientWasCalled(ProceedingJoinPoint pjp) throws Throwable {
Object bean = pjp.getTarget();
if (!(bean instanceof TracingClient)) {
Object[] args = pjp.getArgs();
return (new TracingClientBuilder((Client)bean, FeignTracingAutoConfiguration.this.tracer)).withFeignSpanDecorators(FeignTracingAutoConfiguration.this.spanDecorators).build().execute((Request)args[0], (Options)args[1]);
} else {
return pjp.proceed();
}
}
}

Přidal jsem Dockerfile, docker-compose a docker- setup.sh pro snazší spuštění této aplikace. pokladní kód a spusťte přímo docker-setup.sh.

Kód najdete na mém úložišti Github odkazu .

Toto je inspirováno blogem Shekhara Gulatiho .

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *