Hurtig guide til mikrometer

1. Introduktion

Mikrometer giver en enkel facade over instrumenteringsklienterne til en række populære overvågningssystemer. I øjeblikket understøtter den følgende overvågningssystemer: Atlas, Datadog, Graphite, Ganglia, Influx, JMX og Prometheus.

I denne artikel introducerer vi den grundlæggende brug af Micrometer og dens integration med Spring.

Af hensyn til enkelheden tager vi Micrometer Atlas som et eksempel for at demonstrere de fleste af vores brugssager.

2. Maven-afhængighed

Til at begynde med skal vi tilføje følgende afhængighed af pom.xml:

 io.mikrometer mikrometer-registry-atlas 0.12.0.RELEASE 

Den seneste version kan findes her.

3. MeterRegistry

I mikrometer er en MeterRegistry er kernekomponenten, der bruges til registrering af målere. Vi kan gentage over registreringsdatabasen og fremme hver målers metrics for at generere en tidsserie i backend med kombinationer af metrics og deres dimensionværdier.

Den enkleste form for registreringsdatabasen er SimpleMeterRegistry. Men i de fleste tilfælde skal vi bruge en MeterRegistry eksplicit designet til vores overvågningssystem for Atlas er det AtlasMeterRegistry.

CompositeMeterRegistry tillader, at flere registre tilføjes. Det giver en løsning til at offentliggøre applikationsmålinger til forskellige understøttede overvågningssystemer samtidigt.

Vi kan tilføje enhver MeterRegistry nødvendigt for at uploade dataene til flere platforme:

CompositeMeterRegistry compositeRegistry = ny CompositeMeterRegistry (); SimpleMeterRegistry oneSimpleMeter = ny SimpleMeterRegistry (); AtlasMeterRegistry atlasMeterRegistry = nyt AtlasMeterRegistry (atlasConfig, Clock.SYSTEM); compositeRegistry.add (oneSimpleMeter); compositeRegistry.add (atlasMeterRegistry);

Der er en statisk global registersupport i Micrometer: Metrics.globalRegistry. Der leveres også et sæt statiske bygherrer baseret på dette globale register til at generere målere i Metrics:

@Test offentlig ugyldighed givenGlobalRegistry_whenIncrementAnywhere_thenCounted () {class CountedObject {private CountedObject () {Metrics.counter ("objects.instance"). Increment (1.0); }} Metrics.addRegistry (ny SimpleMeterRegistry ()); Metrics.counter ("objects.instance"). Stigning (); nyt CountedObject (); Valgfri counterOptional = Metrics.globalRegistry .find ("objects.instance"). Tæller (); assertTrue (counterOptional.isPresent ()); assertTrue (counterOptional.get (). count () == 2.0); }

4. Mærker og Meter

4.1. Mærker

En identifikator af en Måler består af et navn og tags. Det foreslås, at vi skal følge en navngivningskonvention, der adskiller ord med en prik for at hjælpe med at garantere bærbarhed af metriske navne på tværs af flere overvågningssystemer.

Counter counter = registry.counter ("page.visitors", "age", "20s");

Mærker kan bruges til at skære metricen for at ræsonnere om værdierne. I koden ovenfor, page.visitors er navnet på måleren, med alder = 20s som sit mærke. I dette tilfælde er tælleren beregnet til at tælle de besøgende på siden med alderen 20 til 30 år.

For et stort system kan vi føje almindelige tags til et register, siger metrics er fra en bestemt region:

registry.config (). commonTags ("region", "ua-øst");

4.2. Tæller

EN Tæller rapporterer kun en optælling over en bestemt egenskab ved en applikation. Vi kan bygge en brugerdefineret tæller med den flydende bygherre eller hjælpemetoden til enhver Metrisk registrering:

Counter counter = Counter .builder ("instance") .description ("indicates instance count of the object") .tags ("dev", "performance") .register (registry); counter.increment (2.0); assertTrue (counter.count () == 2); counter.increment (-1); assertTrue (counter.count () == 2);

Som det ses fra uddraget ovenfor, forsøgte vi at reducere tælleren med et, men vi kan kun øge tælleren monotont med et fast positivt beløb.

4.3. Timere

For at måle ventetid eller hyppighed af begivenheder i vores system kan vi bruge Timere. EN Timer rapporterer mindst den samlede tid og antallet af begivenheder for specifikke tidsserier.

For eksempel kan vi optage en applikationsbegivenhed, der kan vare flere sekunder:

SimpleMeterRegistry registry = ny SimpleMeterRegistry (); Timer timer = registry.timer ("app.event"); timer.record (() -> {prøv {TimeUnit.MILLISECONDS.sleep (1500);} fangst (InterruptedException ignoreret) {}}); timer.record (3000, MILLISEKONDER); assertTrue (2 == timer.count ()); assertTrue (4510> timer.totalTime (MILLISECONDS) && 4500 <= timer.totalTime (MILLISECONDS));

For at registrere begivenheder, der kører i lang tid, bruger vi LongTaskTimer:

SimpleMeterRegistry registry = ny SimpleMeterRegistry (); LongTaskTimer longTaskTimer = LongTaskTimer .builder ("3rdPartyService") .register (registreringsdatabase); long currentTaskId = longTaskTimer.start (); prøv {TimeUnit.SECONDS.sleep (2); } fangst (InterruptedException ignoreret) {} long timeElapsed = longTaskTimer.stop (currentTaskId); assertTrue (timeElapsed / (int) 1e9 == 2);

4.4. Målestok

En måler viser den aktuelle værdi af en meter.

Forskellig fra andre målere, Målere bør kun rapportere data, når de observeres. Målere kan være nyttigt, når du overvåger statistik over cache, samlinger osv .:

SimpleMeterRegistry registry = ny SimpleMeterRegistry (); Liste liste = ny ArrayList (4); Gauge gauge = Gauge .builder ("cache.size", list, List :: size) .register (registry); assertTrue (gauge.value () == 0.0); list.add ("1"); assertTrue (gauge.value () == 1.0);

4.5. DistributionSummary

Fordeling af begivenheder og et simpelt resume er leveret af DistributionSummary:

SimpleMeterRegistry registry = ny SimpleMeterRegistry (); DistributionSummary distributionSummary = DistributionSummary .builder ("request.size") .baseUnit ("bytes") .register (registry); distributionSummary.record (3); distributionSummary.record (4); distributionSummary.record (5); assertTrue (3 == distributionSummary.count ()); assertTrue (12 == distributionSummary.totalAmount ());

I øvrigt, DistributionSummary og Timere kan beriges af kvantiler:

SimpleMeterRegistry registry = ny SimpleMeterRegistry (); Timer timer = Timer.builder ("test.timer") .kvantiler (WindowSketchQuantiles .kvantiler (0,3, 0,5, 0,95) .create ()) .register (registry);

I uddraget ovenfor er tre målere med tags kvantil = 0,3, kvantil = 0,5 og kvantil = 0,95 vil være tilgængelig i registreringsdatabasen, der angiver de værdier, under hvilke henholdsvis 95%, 50% og 30% af observationer falder.

For at se disse kvantiler i aktion, lad os tilføje følgende poster:

timer.record (2, TimeUnit.SECONDS); timer.record (2, TimeUnit.SECONDS); timer.record (3, TimeUnit.SECONDS); timer.record (4, TimeUnit.SECONDS); timer.record (8, TimeUnit.SECONDS); timer.record (13, TimeUnit.SECONDS);

Så kan vi verificere ved at udtrække værdier i disse tre kvantiler Målere:

Liste quantileGauges = registry.getMeters (). Stream () .filter (m -> m.getType (). Navn (). Er lig med ("Gauge")). Kort (meter -> (Gauge) meter) .collect (Collectors .toList ()); assertTrue (3 == quantileGauges.size ()); Kort quantileMap = extractTagValueMap (registreringsdatabase, Type.Gauge, 1e9); assertThat (quantileMap, allOf (hasEntry ("quantile = 0.3", 2), hasEntry ("quantile = 0.5", 3), hasEntry ("quantile = 0.95", 8)));

Desuden understøtter mikrometer også histogrammer:

DistributionSummary hist = DistributionSummary .builder ("resume"). Histogram (Histogram.linear (0, 10, 5)) .register (registry);

I lighed med kvantiler kan vi, efter at have tilføjet flere poster, se, at histogram håndterer beregningen ret godt:

Korthistogrammer = extractTagValueMap (registreringsdatabase, Type.Tæller, 1.0); assertThat (histogrammer, allOf (hasEntry ("bucket = 0.0", 0), hasEntry ("bucket = 10.0", 2), hasEntry ("bucket = 20.0", 2), hasEntry ("bucket = 30.0", 1), hasEntry ("bucket = 40.0", 1), hasEntry ("bucket = Infinity", 0)));

Generelt kan histogrammer hjælpe med at illustrere en direkte sammenligning i separate spande. Histogrammer kan også tidsskaleres, hvilket er ret nyttigt til analyse af backend-servicetid:

SimpleMeterRegistry registry = ny SimpleMeterRegistry (); Timer timer = Timer .builder ("timer"). Histogram (Histogram.linearTime (TimeUnit.MILLISECONDS, 0, 200, 3)) .register (registry); // ... assertThat (histogrammer, allOf (hasEntry ("bucket = 0.0", 0), hasEntry ("bucket = 2.0E8", 1), hasEntry ("bucket = 4.0E8", 1), hasEntry ("bucket = Uendelig ", 3)));

5. Bindemidler

Mikrometeret har flere indbyggede bindere til at overvåge JVM, cacher, ExecutorService og logningstjenester.

Når det kommer til JVM og systemovervågning, kan vi overvåge klasselæssermetrik (ClassLoaderMetrics), JVM-hukommelsespulje (JvmMemoryMetrics) og GC-metrics (JvmGcMetrics), tråd- og CPU-udnyttelse (JvmThreadMetrics, ProcessorMetrics).

Cacheovervågning (i øjeblikket understøttes kun Guava, EhCache, Hazelcast og koffein) understøttes af instrumentering med GuavaCacheMetrics, EhCache2Metrics, HazelcastCacheMetricsog KoffeinCacheMetrics. Og for at overvåge tilbagekoblingstjeneste kan vi binde LogbackMetrics til ethvert gyldigt register:

nye LogbackMetrics (). bind (registry);

Brugen af ​​ovenstående bindemidler er meget lig LogbackMetrics og er alle ret enkle, så vi dykker ikke ned i yderligere detaljer her.

6. Integration af foråret

Spring Boot Actuator leverer afhængighedsstyring og automatisk konfiguration til Micrometer. Nu understøttes det i Spring Boot 2.0 / 1.x og Spring Framework 5.0 / 4.x.

Vi har brug for følgende afhængighed (den nyeste version kan findes her):

 io.mikrometer mikrometer-fjeder-arv 0.12.0.RELEASE 

Uden yderligere ændringer af eksisterende kode har vi aktiveret Spring support med Micrometer. JVM-hukommelsesmålinger i vores Spring-applikation registreres automatisk i det globale register og offentliggøres til standardatlasendepunktet: // localhost: 7101 / api / v1 / publish.

Der er flere konfigurerbare egenskaber til rådighed til at kontrollere metrics eksportadfærd, begyndende med spring.metrics.atlas. *. Kontrollere AtlasConfig for at se en komplet liste over konfigurationsegenskaber til Atlas-udgivelse.

Hvis vi har brug for at binde flere målinger, skal du kun tilføje dem som @Bønne til applikationskonteksten.

Sig, vi har brug for JvmThreadMetrics:

@Bean JvmThreadMetrics threadMetrics () {returner nye JvmThreadMetrics (); }

Hvad angår webovervågning, konfigureres den automatisk til hvert slutpunkt i vores applikation, men alligevel håndterbar via en konfigurationsegenskab: spring.metrics.web.autoTimeServerRequests.

Standardimplementeringen indeholder fire dimensioner af metrics for slutpunkter: HTTP-anmodningsmetode, HTTP-svarkode, slutpunkts-URI og undtagelsesoplysninger.

Når anmodninger besvares, målinger angående anmodningsmetode (, STOLPEosv.) vil blive offentliggjort i Atlas.

Med Atlas Graph API kan vi generere en graf for at sammenligne svartiden for forskellige metoder:

Som standard er svarkoder på 20x, 30x, 40x, 50x vil også blive rapporteret:

Vi kan også sammenligne forskellige URI'er:

eller tjek undtagelsesmålinger:

Bemærk, at vi også kan bruge @Tidsbestemt på controller-klassen eller specifikke slutpunktsmetoder til at tilpasse tags, lang opgave, kvantiler og percentiler af metrics:

@RestController @Timed ("people") offentlig klasse PeopleController {@GetMapping ("/ people") @Timed (value = "people.all", longTask = true) offentlig Liste listePeople () {// ...}}

Baseret på ovenstående kode kan vi se følgende tags ved at kontrollere Atlas slutpunkt // localhost: 7101 / api / v1 / tags / name:

["folk", "folk.all", "jvmBufferCount", ...]

Micrometer fungerer også i funktionsweb-rammen, der blev introduceret i Spring Boot 2.0. Metrics kan aktiveres ved at filtrere RouterFunktion:

RouterFunctionMetrics metrics = nye RouterFunctionMetrics (registry); RouterFunctions.route (...) .filter (metrics.timer ("server.requests"));

Metrics fra datakilden og planlagte opgaver kan også indsamles. Se den officielle dokumentation for flere detaljer.

7. Konklusion

I denne artikel introducerede vi metrics facade Micrometer. Ved at abstrahere væk og understøtte flere overvågningssystemer under almindelig semantik gør værktøjet det nemt at skifte mellem forskellige overvågningsplatforme.

Som altid kan den fulde implementeringskode for denne artikel findes på Github.