Jaeger Integration With Spring Boot Application

(Himank Batra) (9. september , 2020)

Jaeger Integration med spring boot-applikation

Lad os først forstå, hvad der er Jaeger

Jaeger er open source-software til sporing af transaktioner mellem distribuerede tjenester.

Det bruges til overvågning og fejlfinding af komplekse mikrotjenestemiljøer.

Ridesharing-firma Uber udviklede Jaeger som et open source-projekt i 2015. Det blev accepteret som en sky Native Computing Foundation (CNCF) inkubationsprojekt i 2017 og forfremmet til gradueret status i 2019.

Hvad er distribueret sporing?

Distribueret sporing er en måde at se og forstå hele kæden af ​​begivenheder i et komplekst samspil mellem mikrotjenester.

Moderne, cloud-native softwareudvikling er afhængig af mikrotjenester: uafhængige tjenester, som hver især har en anden kernefunktion. Når en bruger fremsætter en anmodning i en app, svarer mange individuelle tjenester for at producere et resultat.

Et enkelt opkald i en app kan påkalde snesevis af forskellige tjenester, der interagerer med hinanden. Hvordan kan udviklere og ingeniører isolere et problem, når noget går galt, eller en anmodning kører langsomt? Vi har brug for en måde at holde styr på alle forbindelser.

Det er her distribueret sporing kommer ind. Det køres ofte som en del af et servicenetværk, hvilket er en måde at styre og observere mikroservices på.

Jaeger bruger distribueret sporing til at følge stien til en anmodning gennem forskellige mikrotjenester. I stedet for at gætte kan vi se en visuel repræsentation af opkaldsstrømmene.

Organiseret information om transaktioner er nyttig til debugging og optimering. Jaeger inkluderer værktøjer til at overvåge distribuerede transaktioner, optimere ydeevne og latens og udføre rodårsagsanalyse (RCA), en metode til problemløsning.

Jaeger-terminologi og komponenter

Jaeger præsenterer eksekveringsanmodninger som spor . Et spor viser data / udførelsesstien gennem et system.

Et spor består af et eller flere spænd . Et span er en logisk enhed af arbejde i Jaeger. Hvert interval inkluderer operationens navn, starttidspunkt og varighed. Spænd kan være indlejret og bestilt.

Jaeger indeholder flere komponenter, der arbejder sammen for at samle, gemme og visualisere spænd og spor.

Jaeger Client inkluderer sprog -specifikke implementeringer af OpenTracing API til distribueret sporing. Disse kan bruges manuelt eller med en række open source-rammer.

Jaeger Agent er en netværksdemon, der lytter til spændinger sendt over User Datagram Protocol. Det er meningen, at agenten skal placeres på samme vært som den instrumenterede applikation. Dette implementeres normalt gennem et sidevogn i containermiljøer som Kubernetes.

Jaeger Collector modtager spændvidder og placerer dem i en kø til behandling.

Samlere kræver en vedvarende opbevaringsbackend, så Jaeger har også en tilslutningsbar mekanisme til span opbevaring.

Forespørgsel er en tjeneste, der henter spor fra lager.

Jaeger Console er en brugergrænseflade, der giver dig mulighed for at visualisere dine distribuerede sporingsdata.

Hvorfor Jaeger?

Som mikrotjenesteudøvere på stedet hurtigt er klar over, er de fleste operationelle problemer, der opstår, når de flytter til en distribueret arkitektur, i sidste ende jordet i to områder: netværk og observerbarhed. Det er simpelthen et større størrelsesordens problem at netværke og debugge et sæt sammenflettede distribuerede tjenester versus en enkelt monolitisk applikation.

Jaeger i aktion

Vi integrerer jaeger i en spring-boot-applikation.

Først skal vi hurtigt opsætte vores spring-boot-applikationer.

Ideen her er at generere navne ved at sammenkæde berømte videnskabsmandsnavne med dyrenavne.

Så vi bygger 3 mikrotjenester ved hjælp af springboot, dvs. animal-name-service , navnegenerator-service, og videnskabsmand- navn- service.

Klientanmodning om et videnskabsmand og sammenkædet dyr fra navnegenerator-service som internt kalder animal-name-service og scientist-name-service.

Det samme vises i nedenstående diagram.

Eksempel på mikroservice

Lad os hurtigt opbygge vores tre mikrotjenester ved hjælp af forår initialiseret r.

Vi tilføjer spring-boot-starter-web afhængighed mens vi genererer spring boot-applikationer.

Nu har vi 3 spring-boot-applikationer klar. Lad os tilføje disse 3 mikrotjenester til en mappe ved navn opentracing-microservices-example.

Og importere denne mappe i din yndlingseditor. Jeg bruger IntelliJ .

Som vi er nødt til at kalde animal-name-service og scientist- name-service fra name-generator-service.

vi vælger at feignere klienten til dette. Så lad os tilføje spring-cloud-starter-openfeign: 2.2.3.RELEASE afhængighed i name-generator-service.

Her er koden til alle 3 mikrotjenester.

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:

Her bruger jeg com.shekhargulati: strman: 0.4 .0 bibliotek til konvertering af dyre- og videnskabsmandsnavn til kebab-sag.

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

Nu kører vi alle 3 applikationer og går til http: // localhost: 8080 / api / v1 / names / tilfældig i en browser.

Vi får et eksempel på tilfældigt navn: john-cockcroft-snapping-skildpadde

Så nu er vores ansøgning opsætningen er færdig.

Lad os nu integrere jaeger i disse applikationer, så vi kan tra ce hver anmodning.

Vi skal bare tilføje nedenstående afhængighed til alle 3 pom.xml.


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

Og vi er nødt til at tilføje nedenstående egenskaber i filen application.properties til alle 3 applikationer.

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

Kør Jaeger i docker via nedenstående kommando:

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

Genstart applikationen. Og gå til localhost: 9090 i en browser. Vi får en jaeger-startside.

Gå også til http: // localhost: 8080 / api / v1 / names / random i en browser. På samme måde får du noget tilfældigt navn.

Men nu kan vi spore anmodningen. Tjek i jaeger-dashboardet, vælg service name-generator-service.

og klik derefter på find spor. vi får spor som vist i nedenstående billede for name-generator-service .

Jaeger Name Generator Service

Vi kan tydeligt se, at der er 5 spænd, når vi går nærmere ned på dette.

name-generator-service (1 span)

name-generator-service-> animal-name-service (2 span)

name-generator-service-> scientist- name-service (2 spænd)

Dette vises i nedenstående billede.

Jaeger Name Generator Service Trace

Her konfigureres alt automatisk af opentracing-spring-jaeger-cloud-starter bibliotek, der har en klasse med navnet TracingAspect, der grundlæggende laver magi.

@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();
}
}
}

Jeg har tilføjet Dockerfile, docker-compose og docker- setup.sh for at gøre det lettere at køre denne applikation. kassekode og kør docker-setup.sh direkte.

Du kan finde koden i mit Github-lager link .

Dette er inspireret af Shekhar Gulatis blog .

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *