Proljetni oblak u oblaku u monolitnoj aplikaciji

1. Pregled

U ovom članku uvodimo Proljetni oblak - moćan alat za poboljšanje zapisnika u bilo kojoj aplikaciji, ali posebno u sustavu izgrađenom od više usluga.

A za ovaj članak usredotočit ćemo se na upotrebu Sleutha u monolitnoj aplikaciji, a ne u mikroservisima.

Svi smo imali nesretno iskustvo pokušaja dijagnosticiranja problema s planiranim zadatkom, operacijom s više niti ili složenim web zahtjevom. Često je čak i kad postoji evidentiranje, teško reći koje radnje trebaju biti povezane zajedno da bi se stvorio jedan zahtjev.

Ovo može učiniti dijagnosticiranje složene akcije vrlo teško ili čak nemoguće. Često rezultiraju rješenjima poput prosljeđivanja jedinstvenog ID-a svakoj metodi u zahtjevu za identifikaciju dnevnika.

U dolazi Detektiv. Ova knjižnica omogućuje prepoznavanje dnevnika koji se odnose na određeni posao, nit ili zahtjev. Sleuth se bez napora integrira s okvirima za bilježenje poput Povratna informacija i SLF4J za dodavanje jedinstvenih identifikatora koji pomažu u praćenju i dijagnosticiranju problema pomoću dnevnika.

Pogledajmo kako to funkcionira.

2. Postavljanje

Počet ćemo s izradom a Proljetni čizme web projekt u našem omiljenom IDE-u i dodajući ovu ovisnost našem pom.xml datoteka:

 org.springframework.cloud proljeće-oblak-starter-sleut 

Naša aplikacija radi sa Proljetni čizme a roditelj pom pruža verzije za svaki unos. Najnoviju verziju ove ovisnosti možete pronaći ovdje: spring-cloud-starter-sleuth. Da biste vidjeli cijeli POM, pogledajte projekt na Githubu.

Uz to, dodamo naziv aplikacije za upute Detektiv za prepoznavanje dnevnika ove aplikacije.

U našem primjena.svojstva datoteka dodaj ovaj redak:

spring.application.name = Vodič za Baeldung Sleuth

3. Konfiguracije Sleuth

Detektiv je sposoban poboljšati zapisnike u mnogim situacijama. Počevši od verzije 2.0.0, Spring Cloud Sleuth koristi Brave kao biblioteku za praćenje koja dodaje jedinstvene ID-ove svakom web-zahtjevu koji uđe u našu aplikaciju. Nadalje, Spring tim je dodao podršku za dijeljenje ovih ID-ova preko granica niti.

Tragove možemo smatrati jednim zahtjevom ili poslom koji se pokreće u aplikaciji. Svi različiti koraci u tom zahtjevu, čak i preko granica aplikacije i niti, imat će isti traceId.

S druge strane, rasponi se mogu smatrati dijelovima posla ili zahtjeva. Pojedinačni trag može se sastojati od više raspona, svaki koji se odnosi na određeni korak ili odjeljak zahtjeva. Korištenjem ID-ova praćenja i raspona možemo točno odrediti kada i gdje je naša aplikacija dok obrađuje zahtjev. Puno olakšavanje čitanja naših dnevnika.

U našim ćemo primjerima istražiti te mogućnosti u jednoj aplikaciji.

3.1. Jednostavan web zahtjev

Prvo, stvorimo klasu kontrolera koja će biti ulazna točka za rad:

@RestController javna klasa SleuthController {@GetMapping ("/") javni niz helloSleuth () {logger.info ("Hello Sleuth"); povratak "uspjeh"; }}

Pokrenimo našu aplikaciju i idite na “// localhost: 8080”. Pogledajte zapisnike za izlaz koji izgleda ovako:

2017-01-10 22: 36: 38.254 INFO [Vodič za Baeldung Sleuth, 4e30f7340b3fb631,4e30f7340b3fb631, false] 12516 --- [nio-8080-exec-1] c.b.spring.session.SleuthController: Hello Sleuth

Ovo izgleda kao uobičajeni zapisnik, osim dijela na početku između zagrada. Ovo je temeljna informacija koja Spring Sleuth je dodao. Ovi podaci slijede format:

[naziv aplikacije, traceId, spanId, izvoz]

  • Naziv aplikacije - Ovo je ime koje smo postavili u datoteci svojstava i može se koristiti za agregiranje zapisnika iz više instanci iste aplikacije.
  • TragId - Ovo je ID koji se dodjeljuje jednom zahtjevu, poslu ili radnji. Nešto poput svakog web zahtjeva koji pokreće jedinstveni korisnik imat će svoj vlastiti traceId.
  • SpanId - Prati jedinicu rada. Zamislite zahtjev koji se sastoji od više koraka. Svaki korak mogao bi imati svoj spanId i pratiti pojedinačno. Prema zadanim postavkama, svaki tok aplikacije započet će s istim TraceId i SpanId.
  • Izvoz - Ovo je svojstvo logička vrijednost koja pokazuje je li ovaj zapisnik izvezen u agregator poput Zipkin. Zipkin je izvan dosega ovog članka, ali igra važnu ulogu u analiziranju dnevnika koje je izradio Detektiv.

Do sada biste trebali imati predodžbu o snazi ​​ove knjižnice. Pogledajmo još jedan primjer kako bismo dalje pokazali koliko je ova knjižnica integralna za bilježenje.

3.2. Jednostavan web zahtjev s pristupom usluzi

Počnimo s izradom usluge s jednom metodom:

@Service javna klasa SleuthService {public void doSomeWorkSameSpan () {Thread.sleep (1000L); logger.info ("Raditi na nekom poslu"); }}

Sada ubrizgamo našu uslugu u naš kontroler i dodajte metod preslikavanja zahtjeva koji joj pristupa:

@Autowired private SleuthService sleuthService; @GetMapping ("/ same-span") javni niz helloSleuthSameSpan () baca InterruptedException {logger.info ("Isti raspon"); sleuthService.doSomeWorkSameSpan (); povratak "uspjeh"; }

Na kraju, ponovo pokrenite aplikaciju i idite na “// localhost: 8080 / same-span”. Pripazite na izlaz iz dnevnika koji izgleda ovako:

2017-01-10 22: 51: 47.664 INFO [Vodič za Baeldung Sleuth, b77a5ea79036d5b9, b77a5ea79036d5b9, false] 12516 --- [nio-8080-exec-3] cbspring.session.SleuthController: Isti raspon 2017-01-10 22 : 51: 48.664 INFO [Vodič za Baeldung Sleuth, b77a5ea79036d5b9, b77a5ea79036d5b9, false] 12516 --- [nio-8080-exec-3] c.baeldung.spring.session.SleuthService: Obavljanje nekih poslova

Imajte na umu da su ID-ovi traga i raspona jednaki između dva dnevnika iako poruke potječu iz dvije različite klase. Zbog toga je trivijalno identificirati svaki zapisnik tijekom zahtjeva pretraživanjem traceId tog zahtjeva.

Ovo je zadano ponašanje, jedan zahtjev dobiva jedan traceId i spanId. Ali možemo ručno dodati raspone kako smatramo potrebnim. Pogledajmo primjer koji koristi ovu značajku.

3.3. Ručno dodavanje raspona

Za početak dodamo novi kontroler:

@GetMapping ("/ new-span") javni niz helloSleuthNewSpan () {logger.info ("Novi raspon"); sleuthService.doSomeWorkNewSpan (); povratak "uspjeh"; }

A sada dodajmo novu metodu u našu uslugu:

@Autowired private Tracer tracer; // ... javna praznina doSomeWorkNewSpan () baca InterruptedException {logger.info ("Ja sam u izvornom rasponu"); Raspon newSpan = tracer.nextSpan (). Name ("newSpan"). Start (); probajte (SpanInScope ws = tracer.withSpanInScope (newSpan.start ())) {Thread.sleep (1000L); logger.info ("Ja sam u novom rasponu i radim neki kul posao koji treba svoj raspon"); } napokon {newSpan.finish (); } logger.info ("U originalnom sam rasponu"); }

Imajte na umu da smo dodali i novi objekt, Tracer. The tragač instancu kreira Spring Sleuth tijekom pokretanja i dostupan je našoj klasi putem ubrizgavanja ovisnosti.

Tragovi se moraju ručno pokretati i zaustavljati. Da bi se to postiglo, kôd koji se izvodi u ručno stvorenom raspon nalazi se unutar a probaj-napokon blok kako bi se osiguralo raspon je zatvorena bez obzira na uspjeh operacije. Također, imajte na umu da se mora obuhvatiti novi raspon.

Ponovo pokrenite aplikaciju i idite na "// localhost: 8080 / new-span". Pripazite na izlaz iz dnevnika koji izgleda ovako:

11.01.2017 21: 07: 54,924 INFO [Vodič za Baeldung Sleuth, 9cdebbffe8bbbade, 9cdebbffe8bbbade, false] 12516 --- [nio-8080-exec-6] cbspring.session.SleuthController: New Span 2017-01-11 21 : 07: 54.924 INFO [Vodič za Baeldung Sleuth, 9cdebbffe8bbbade, 9cdebbffe8bbbade, false] 12516 --- [nio-8080-exec-6] c.baeldung.spring.session.SleuthService: U originalnom sam rasponu 2017-01- 11 21: 07: 55.924 INFO [Vodič za Baeldung Sleuth, 9cdebbffe8bbbade, 1e706f252a0ee9c2, false] 12516 --- [nio-8080-exec-6] c.baeldung.spring.session.SleuthService: U novom sam rasponu i radim neke cool posao koji treba svoj raspon 2017-01-11 21: 07: 55.924 INFO [Baeldung Sleuth Tutorial, 9cdebbffe8bbbade, 9cdebbffe8bbbade, false] 12516 --- [nio-8080-exec-6] c.baeldung.spring.session. SleuthService: U originalnom sam rasponu

Možemo vidjeti da treći zapisnik dijeli traceId s ostalima, ali ima jedinstvenu spanId. To se može koristiti za lociranje različitih odjeljaka u jednom zahtjevu za preciznije praćenje.

Pogledajmo sada Sleuth's potpora nitima.

3.4. Spanning Runnables

Da bi se demonstrirale mogućnosti navoja Detektiv prvo dodamo klasu konfiguracije za postavljanje spremišta niti:

@Configuration javna klasa ThreadConfig {@Autowired private BeanFactory beanFactory; @Bean javni izvršitelj izvršitelj () {ThreadPoolTaskExecutor threadPoolTaskExecutor = novi ThreadPoolTaskExecutor (); threadPoolTaskExecutor.setCorePoolSize (1); threadPoolTaskExecutor.setMaxPoolSize (1); threadPoolTaskExecutor.initialize (); vratiti novi LazyTraceExecutor (beanFactory, threadPoolTaskExecutor); }}

Ovdje je važno napomenuti upotrebu LazyTraceExeecuter. Ova klasa dolazi iz Detektiv knjižnica i posebna je vrsta izvršitelja koji će propagirati naš traceIds na nove niti i stvorite nove spanIds u procesu.

Sad povežimo ovog izvršitelja u naš kontroler i upotrijebimo ga u novom načinu mapiranja zahtjeva:

@Automobilski privatni izvršitelj izvršitelj; @GetMapping ("/ new-thread") javni niz helloSleuthNewThread () {logger.info ("Nova nit"); Izvodljivo izvodljivo = () -> {try {Thread.sleep (1000L); } catch (InterruptedException e) {e.printStackTrace (); } logger.info ("Unutar sam nove niti - s novim rasponom"); }; izvršitelj.izvršiti (pokrenuti); logger.info ("Gotov sam - s originalnim rasponom"); povratak "uspjeh"; }

S našim pokretanim sustavom, ponovo pokrenimo našu aplikaciju i idemo na “// localhost: 8080 / new-thread”. Pripazite na izlaz iz dnevnika koji izgleda ovako:

2017-01-11 21: 18: 15.949 INFO [Vodič za Baeldung Sleuth, 96076a78343c364d, 96076a78343c364d, false] 12516 --- [nio-8080-exec-9] cbspring.session.SleuthController: Nova tema 11.01.2017 21 : 18: 15.950 INFO [Vodič za Baeldung Sleuth, 96076a78343c364d, 96076a78343c364d, false] 12516 --- [nio-8080-exec-9] cbspring.session.SleuthController: Gotov sam - s originalnim rasponom 11. januara 2017. 21: 18: 16.953 INFO [Vodič za Baeldung Sleuth, 96076a78343c364d, e3b6a68013ddfeea, false] 12516 --- [lTaskExecutor-1] cbspring.session.SleuthController: Ušao sam u novu nit - s novim rasponom

Slično kao i u prethodnom primjeru, možemo vidjeti da svi zapisnici dijele isto traceId. Ali zapisnik koji dolazi iz pokretačkog programa ima jedinstveni raspon koji će pratiti rad obavljen u toj niti. Zapamtite da se to događa zbog LazyTraceExeecuter, ako bismo koristili normalnog izvršitelja, i dalje bismo to isto vidjeli spanId koristi se u novoj niti.

Pogledajmo sada Sleuth's podrška za @Async metode.

3.5. @Async Podrška

Da bismo dodali podršku za asinkronizaciju, prvo izmijenimo našu ThreadConfig klasa za omogućavanje ove značajke:

@Configuration @EnableAsync javna klasa ThreadConfig proširuje AsyncConfigurerSupport {// ... @Override javni izvršitelj getAsyncExecutor () {ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor (); threadPoolTaskExecutor.setCorePoolSize (1); threadPoolTaskExecutor.setMaxPoolSize (1); threadPoolTaskExecutor.initialize (); vratiti novi LazyTraceExecutor (beanFactory, threadPoolTaskExecutor); }}

Imajte na umu da produžujemo AsyncConfigurerSupport da odredimo našeg async izvršitelja i upotrebu LazyTraceExeecuter kako bi se osiguralo da se traceIds i spanIds pravilno šire. Također smo dodali @EnableAsync na vrh naše klase.

Dodajmo sada async metodu u našu uslugu:

@Async javna void asyncMethod () {logger.info ("Pokreni Async metodu"); Navoj.spavanje (1000L); logger.info ("End Async Method"); }

Sada pozovimo ovu metodu iz našeg kontrolera:

@GetMapping ("/ async") javni niz helloSleuthAsync () {logger.info ("Prije poziva Async metode"); sleuthService.asyncMethod (); logger.info ("Nakon poziva Async metode"); povratak "uspjeh"; }

Na kraju, ponovno pokrenimo našu uslugu i idimo na “// localhost: 8080 / async”. Pripazite na izlaz iz dnevnika koji izgleda ovako:

2017-01-11 21: 30: 40.621 INFO [Vodič za Baeldung Sleuth, c187f81915377fff, c187f81915377fff, false] 10072 --- [nio-8080-exec-2] cbspring.session.SleuthController: Before Async Method Call 2017-01- 11 21: 30: 40,622 INFO [Vodič za Baeldung Sleuth, c187f81915377fff, c187f81915377fff, false] 10072 --- [nio-8080-exec-2] cbspring.session.SleuthController: Nakon Async Method Call 2017-01-11 21:30 : 40.622 INFO [Vodič za Baeldung Sleuth, c187f81915377fff, 8a9f3f097dca6a9e, false] 10072 --- [lTaskExecutor-1] c.baeldung.spring.session.SleuthService: Start Async Method 2017-01-11 21: 30: 41.622 INFO Sleuth Ba Vodič, c187f81915377fff, 8a9f3f097dca6a9e, false] 10072 --- [lTaskExecutor-1] c.baeldung.spring.session.SleuthService: End Async Method

Ovdje možemo vidjeti mnogo poput našeg primjera za vođenje, Detektiv propagira traceId u async metodu i dodaje jedinstveni spanId.

Poradimo sada na primjeru pomoću proljetne podrške za planirane zadatke.

3.6. @ Na rasporedu Podrška

Napokon, pogledajmo kako Detektiv radi s @ Na rasporedu metode. Da bismo to učinili, ažurirajmo našu ThreadConfig klasa za omogućavanje zakazivanja:

@Configuration @EnableAsync @EnableScheduling javne klase ThreadConfig proširuje AsyncConfigurerSupport implementira SchedulingConfigurer {// ... @Override public void configureTasks (ScheduledTaskRegistrar rasporedTaskRegistrar) {rasporedTaskRegistcheregulator (planirano) } @Bean (killMethod = "shutdown") javni izvršitelj schedulingExecutor () {return Executors.newScheduledThreadPool (1); }}

Imajte na umu da smo implementirali ZakazivanjeConfigurer sučelje i nadjačao njegovu metodu configureTasks. Također smo dodali @EnableScheduling na vrh naše klase.

Dalje, dodajmo uslugu za naše planirane zadatke:

@Service javna klasa SchedulingService {private Logger logger = LoggerFactory.getLogger (this.getClass ()); @Autowired private SleuthService sleuthService; @Scheduled (fixedDelay = 30000) public void rasporedWork () baca InterruptedException {logger.info ("Pokreni neki posao iz zakazanog zadatka"); sleuthService.asyncMethod (); logger.info ("Završi posao iz zakazanog zadatka"); }}

U ovoj smo klasi stvorili jedan planirani zadatak s fiksnim kašnjenjem od 30 sekundi.

Ponovno pokrenimo našu aplikaciju i pričekajmo da se izvrši naš zadatak. Pogledajte konzolu za izlaz ovako:

2017-01-11 21: 30: 58.866 INFO [Vodič za Baeldung Sleuth, 3605f5deaea28df2,3605f5deaea28df2, false] 10072 --- [pool-1-thread-1] cbspring.session.SchedulingService: Započnite neki posao iz zakazanog zadatka 2017. -01-11 21: 30: 58,866 INFO [Vodič za Baeldung Sleuth, 3605f5deaea28df2,3605f5deaea28df2, false] 10072 --- [pool-1-thread-1] cbspring.session.SchedulingService: Završi rad iz zakazanog zadatka

Ovdje to možemo vidjeti Detektiv je stvorio nove ID-ove praćenja i raspona za naš zadatak. Svaka instanca zadatka dobit će svoj vlastiti trag i raspon prema zadanim postavkama.

4. Zaključak

U zaključku smo vidjeli kako Spring Sleuth može se koristiti u raznim situacijama unutar jedne web aplikacije. Ovu tehnologiju možemo koristiti za lako povezivanje zapisnika iz jednog zahtjeva, čak i kada se taj zahtjev proteže na više niti.

Do sada možemo vidjeti kako Proljetni oblak može nam pomoći da sačuvamo razum pri otklanjanju pogrešaka u okruženju s više niti. Identificiranjem svake operacije u a traceId i svaki korak u a spanId uistinu možemo početi razbijati našu analizu složenih poslova u svojim zapisnicima.

Čak i ako ne odemo u oblak, Spring Sleuth vjerojatno je kritična ovisnost u gotovo svakom projektu; besprijekorno je integrirati i je ogroman dodatak vrijednosti.

Odavde ćete možda htjeti istražiti druge značajke Detektiv. Može podržati praćenje u distribuiranim sustavima pomoću RestTemplate, u protokolima za razmjenu poruka koje koristi RabbitMQ i Redis, i kroz prolaz poput Zuula.

Kao i uvijek, izvorni kod možete pronaći na Githubu.


$config[zx-auto] not found$config[zx-overlay] not found