Beknopte handleiding voor schroefmaat

1. Inleiding

Micrometer biedt een eenvoudige façade over de instrumentatieclients voor een aantal populaire monitoringsystemen. Momenteel ondersteunt het de volgende monitoringsystemen: Atlas, Datadog, Graphite, Ganglia, Influx, JMX en Prometheus.

In dit artikel introduceren we het basisgebruik van Micrometer en de integratie met Spring.

Eenvoudigheidshalve nemen we Micrometer Atlas als voorbeeld om de meeste van onze gebruiksscenario's te demonstreren.

2. Maven Afhankelijkheid

Laten we om te beginnen de volgende afhankelijkheid toevoegen aan het pom.xml:

 io.micrometer micrometer-register-atlas 0.12.0.RELEASE 

De laatste versie vind je hier.

3. MeterRegistry

In micrometer, een MeterRegistry is de kerncomponent die wordt gebruikt voor het registreren van meters. We kunnen het register herhalen en de statistieken van elke meter verder uitbreiden om een ​​tijdreeks in de backend te genereren met combinaties van statistieken en hun dimensiewaarden.

De eenvoudigste vorm van het register is SimpleMeterRegistry. Maar in de meeste gevallen moeten we een MeterRegistry expliciet ontworpen voor ons monitoringsysteem; voor Atlas is het AtlasMeterRegistry.

CompositeMeterRegistry maakt het mogelijk om meerdere registers toe te voegen. Het biedt een oplossing voor het gelijktijdig publiceren van toepassingsstatistieken naar verschillende ondersteunde controlesystemen.

We kunnen er een toevoegen MeterRegistry nodig om de gegevens naar meerdere platforms te uploaden:

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

Er is een statische wereldwijde registerondersteuning in Micrometer: Metrics.globalRegistry. Er wordt ook een set statische builders geleverd op basis van dit wereldwijde register om meters in Metrische gegevens:

@Test openbare leegte gegevenGlobalRegistry_whenIncrementAnywhere_thenCounted () {class CountedObject {privé CountedObject () {Metrics.counter ("objects.instance"). Increment (1.0); }} Metrics.addRegistry (nieuwe SimpleMeterRegistry ()); Metrics.counter ("objects.instance"). Increment (); nieuwe CountedObject (); Optioneel counterOptional = Metrics.globalRegistry .find ("objects.instance"). Counter (); assertTrue (counterOptional.isPresent ()); assertTrue (counterOptional.get (). count () == 2.0); }

4. Tags en Meters

4.1. Tags

Een identifier van een Meter bestaat uit een naam en tags. We raden aan om een ​​naamgevingsconventie te volgen waarbij woorden worden gescheiden door een punt, om de overdraagbaarheid van metrische namen over meerdere controlesystemen te helpen garanderen.

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

Tags kan worden gebruikt voor het opdelen van de metriek om te redeneren over de waarden. In de bovenstaande code, pagina.bezoekers is de naam van de meter, met leeftijd = 20s als tag. In dit geval is de teller bedoeld om de bezoekers van de pagina met een leeftijd tussen 20 en 30 te tellen.

Voor een groot systeem kunnen we algemene tags aan een register toevoegen, bijvoorbeeld dat de statistieken afkomstig zijn uit een specifieke regio:

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

4.2. Teller

EEN Teller rapporteert slechts een telling over een gespecificeerde eigenschap van een applicatie. We kunnen een aangepaste balie bouwen met de vloeiende bouwer of de hulpmethode van wie dan ook MetricRegistry:

Counter counter = Counter .builder ("instance") .description ("geeft het aantal exemplaren van het object aan") .tags ("dev", "performance") .register (registry); counter.increment (2.0); assertTrue (counter.count () == 2); counter.increment (-1); assertTrue (counter.count () == 2);

Zoals te zien is in het bovenstaande fragment, hebben we geprobeerd de teller met één maar te verlagen we kunnen de teller alleen monotoon verhogen met een vast positief bedrag.

4.3. Timers

Om latenties of frequentie van gebeurtenissen in ons systeem te meten, kunnen we gebruiken Timers. EEN Timer rapporteert ten minste de totale tijd en het aantal gebeurtenissen van specifieke tijdreeksen.

We kunnen bijvoorbeeld een toepassingsgebeurtenis opnemen die enkele seconden kan duren:

SimpleMeterRegistry registry = nieuwe SimpleMeterRegistry (); Timer timer = registry.timer ("app.event"); timer.record (() -> {probeer {TimeUnit.MILLISECONDS.sleep (1500);} catch (InterruptedException genegeerd) {}}); timer.record (3000, MILLISECONDS); assertTrue (2 == timer.count ()); assertTrue (4510> timer.totalTime (MILLISECONDS) && 4500 <= timer.totalTime (MILLISECONDS));

Om langlopende evenementen vast te leggen, gebruiken we LongTaskTimer:

SimpleMeterRegistry registry = nieuwe SimpleMeterRegistry (); LongTaskTimer longTaskTimer = LongTaskTimer .builder ("3rdPartyService") .register (registry); lang currentTaskId = longTaskTimer.start (); probeer {TimeUnit.SECONDS.sleep (2); } catch (InterruptedException genegeerd) {} ​​long timeElapsed = longTaskTimer.stop (currentTaskId); assertTrue (timeElapsed / (int) 1e9 == 2);

4.4. Meter

Een meter toont de huidige waarde van een meter.

Anders dan andere meters, Meters mogen alleen gegevens rapporteren wanneer ze worden waargenomen. Meters kan handig zijn bij het monitoren van cachestatistieken, verzamelingen, enz .:

SimpleMeterRegistry registry = nieuwe SimpleMeterRegistry (); Lijstlijst = nieuwe 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. Distributie Samenvatting

Verdeling van evenementen en een eenvoudige samenvatting wordt verzorgd door DistributieSamenvatting:

SimpleMeterRegistry registry = nieuwe 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 ());

Bovendien, Distributie Samenvatting en Timers kan worden verrijkt met kwantielen:

SimpleMeterRegistry registry = nieuwe SimpleMeterRegistry (); Timer timer = Timer.builder ("test.timer") .quantiles (WindowSketchQuantiles .quantiles (0.3, 0.5, 0.95) .create ()) .register (registry);

In het bovenstaande fragment drie meters met tags kwantiel = 0,3, kwantiel = 0,5 en kwantiel = 0,95 zal beschikbaar zijn in het register, met vermelding van de waarden waaronder respectievelijk 95%, 50% en 30% van de waarnemingen vallen.

Laten we de volgende records toevoegen om deze kwantielen in actie te zien:

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);

Vervolgens kunnen we verifiëren door waarden in die drie kwantielen te extraheren Meters:

Lijst quantileGauges = registry.getMeters (). Stream () .filter (m -> m.getType (). Name (). Is gelijk aan ("Gauge")) .map (meter -> (Gauge) meter) .collect (Collectors .toList ()); assertTrue (3 == quantileGauges.size ()); Map quantileMap = extractTagValueMap (register, Type.Gauge, 1e9); assertThat (quantileMap, allOf (hasEntry ("quantile = 0.3", 2), hasEntry ("quantile = 0.5", 3), hasEntry ("quantile = 0.95", 8)));

Trouwens, Micrometer ondersteunt ook histogrammen:

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

Net als bij kwantielen, kunnen we na het toevoegen van verschillende records zien dat het histogram de berekening redelijk goed afhandelt:

Kaarthistogrammen = extractTagValueMap (register, Type.Counter, 1.0); assertThat (histogrammen, 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)));

Over het algemeen kunnen histogrammen helpen bij het illustreren van een directe vergelijking in afzonderlijke segmenten. Histogrammen kunnen ook in de tijd worden geschaald, wat erg handig is voor het analyseren van de responstijd van de backend-service:

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

5. Bindmiddelen

De schroefmaat heeft meerdere ingebouwde binders om de JVM, caches, ExecutorService en logboekdiensten.

Als het gaat om JVM en systeembewaking, kunnen we de statistieken van de lader van de klasse controleren (ClassLoaderMetrics), JVM-geheugenpool (JvmMemoryMetrics) en GC-statistieken (JvmGcMetrics), thread- en CPU-gebruik (JvmThreadMetrics, ProcessorMetrics).

Cachemonitoring (momenteel worden alleen Guava, EhCache, Hazelcast en Caffeine ondersteund) wordt ondersteund door instrumentatie met GuavaCacheMetrics, EhCache2Metrics, HazelcastCacheMetrics, en CaffeineCacheMetrics. En om de logback-service te controleren, kunnen we binden LogbackMetrics naar een geldig register:

nieuwe LogbackMetrics (). bind (registry);

Het gebruik van bovenstaande bindmiddelen lijkt veel op LogbackMetrics en zijn allemaal vrij eenvoudig, dus we gaan hier niet verder in op details.

6. Lente-integratie

Spring Boot Actuator biedt afhankelijkheidsbeheer en automatische configuratie voor Micrometer. Nu wordt het ondersteund in Spring Boot 2.0 / 1.x en Spring Framework 5.0 / 4.x.

We hebben de volgende afhankelijkheid nodig (de nieuwste versie is hier te vinden):

 io.micrometer micrometer-veer-legacy 0.12.0.RELEASE 

Zonder enige verdere wijziging van de bestaande code hebben we Spring-ondersteuning ingeschakeld met de schroefmaat. JVM-geheugenstatistieken van onze Spring-applicatie worden automatisch geregistreerd in het globale register en gepubliceerd naar het standaardatlas-eindpunt: // localhost: 7101 / api / v1 / publish.

Er zijn verschillende configureerbare eigenschappen beschikbaar om het exportgedrag van metrische gegevens te regelen, te beginnen met spring.metrics.atlas. *. Controleren AtlasConfig voor een volledige lijst met configuratie-eigenschappen voor publicatie in Atlas.

Als we meer statistieken moeten binden, voegt u ze alleen toe als @Boon naar de toepassingscontext.

Stel dat we de JvmThreadMetrics:

@Bean JvmThreadMetrics threadMetrics () {retourneer nieuwe JvmThreadMetrics (); }

Wat betreft webmonitoring, het is automatisch geconfigureerd voor elk eindpunt in onze applicatie, maar toch te beheren via een configuratie-eigenschap: spring.metrics.web.autoTimeServerRequests.

De standaardimplementatie biedt vier dimensies van metrische gegevens voor eindpunten: HTTP-verzoekmethode, HTTP-antwoordcode, eindpunt-URI en informatie over uitzonderingen.

Wanneer verzoeken worden beantwoord, statistieken met betrekking tot de verzoekmethode (KRIJGEN, POST, etc.) worden gepubliceerd in Atlas.

Met Atlas Graph API kunnen we een grafiek genereren om de responstijd voor verschillende methoden te vergelijken:

Standaard zijn responscodes van 20x, 30x, 40x, 50x zal ook worden gerapporteerd:

We kunnen ook verschillende URI's vergelijken:

of bekijk de uitzonderingsstatistieken:

Merk op dat we ook gebruik kunnen maken van @Timed op de controllerklasse of specifieke eindpuntmethoden om tags, lange taken, kwantielen en percentielen van de metrische gegevens aan te passen:

@RestController @Timed ("people") openbare klasse PeopleController {@GetMapping ("/ people") @Timed (value = "people.all", longTask = true) openbare lijst listPeople () {// ...}}

Op basis van de bovenstaande code kunnen we de volgende tags zien door het Atlas-eindpunt te controleren // localhost: 7101 / api / v1 / tags / naam:

["mensen", "mensen.all", "jvmBufferCount", ...]

Micrometer werkt ook in het functie-webframework dat is geïntroduceerd in Spring Boot 2.0. Metrische gegevens kunnen worden ingeschakeld door de RouterFunctie:

RouterFunctionMetrics metrics = nieuwe RouterFunctionMetrics (register); RouterFunctions.route (...) .filter (metrics.timer ("server.requests"));

Metrische gegevens uit de gegevensbron en geplande taken kunnen ook worden verzameld. Raadpleeg de officiële documentatie voor meer details.

7. Conclusie

In dit artikel hebben we de metrische gevelmicrometer geïntroduceerd. Door weg te abstraheren en meerdere monitoringsystemen onder gemeenschappelijke semantiek te ondersteunen, maakt de tool het schakelen tussen verschillende monitoringplatforms vrij eenvoudig.

Zoals altijd is de volledige implementatiecode van dit artikel te vinden op Github.