Introduksjon til Netflix Servo

1. Oversikt

Netflix Servo er et beregningsverktøy for Java-applikasjoner. Servo ligner på Dropwizard Metrics, men mye enklere. Den bruker JMX bare for å gi et enkelt grensesnitt for å eksponere og publisere applikasjonsberegninger.

I denne artikkelen vil vi introdusere hva Servo tilbyr, og hvordan kan vi bruke det til å samle inn og publisere applikasjonsberegninger.

2. Maven-avhengigheter

Før vi dykker ned i faktisk implementering, la oss legge til Servo-avhengighet til pom.xml fil:

 com.netflix.servo servokjerne 0.12.16 

Dessuten er det mange utvidelser tilgjengelig, for eksempel Servo-Apache, Servo-AWS, etc. Vi kan trenge dem senere. Siste versjoner av disse utvidelsene finner du også på Maven Central.

3. Samle beregninger

La oss først se hvordan vi kan samle beregninger fra applikasjonen vår.

Servo tilbyr fire primære beregningstyper: Disk, Måler, Timer, og Informativ.

3.1. Metriske typer - Disk

Teller brukes til å registrere inkrementering. Vanlige implementeringer er BasicCounter, Skritt teller, og PeakRateCounter.

BasicCounter gjør hva en teller skal gjøre, ren og grei:

Counter counter = new BasicCounter (MonitorConfig.builder ("test"). Build ()); assertEquals ("telleren skal starte med 0", 0, counter.getValue (). intValue ()); counter.increment (); assertEquals ("telleren skal ha økt med 1", 1, counter.getValue (). intValue ()); counter.increment (-1); assertEquals ("telleren skal ha redusert med 1", 0, counter.getValue (). intValue ());

PeakRateCounter returnerer maksimalt antall for et gitt sekund i løpet av avstemningsintervallet:

Counter counter = new PeakRateCounter (MonitorConfig.builder ("test"). Build ()); assertEquals ("telleren skal starte med 0", 0, counter.getValue (). intValue ()); counter.increment (); SECONDS.sleep (1); counter.increment (); counter.increment (); assertEquals ("peak rate should have be 2", 2, counter.getValue (). intValue ());

I motsetning til andre tellere, Skritt teller registrerer hastighet per sekund for forrige avstemningsintervall:

System.setProperty ("servo.pollers", "1000"); Counter counter = new StepCounter (MonitorConfig.builder ("test"). Build ()); assertEquals ("telleren skal starte med hastighet 0,0", 0,0, counter.getValue ()); counter.increment (); SECONDS.sleep (1); assertEquals ("motprisen burde ha økt til 1.0", 1.0, counter.getValue ());

Legg merke til at vi setter inn servo. pollere til 1000 i koden ovenfor. Det var å sette avstemningsintervallet til 1 sekund i stedet for intervaller på 60 sekunder og 10 sekunder som standard. Vi vil dekke mer om dette senere.

3.2. Metriske typer - Måler

Måler er en enkel skjerm som returnerer gjeldende verdi. BasicGauge, MinGauge, MaxGauge, og Antall målere er gitt.

BasicGauge påkaller a Kan kalles for å få den nåværende verdien. Vi kan få størrelsen på en samling, siste verdi av en BlockingQueue eller en hvilken som helst verdi som krever små beregninger.

Gauge gauge = new BasicGauge (MonitorConfig.builder ("test") .build (), () -> 2.32); assertEquals (2.32, gauge.getValue (), 0.01);

MaxGauge og MinGauge brukes til å holde oversikt over henholdsvis maksimums- og minimumsverdiene:

MaxGauge gauge = ny MaxGauge (MonitorConfig.builder ("test"). Build ()); assertEquals (0, gauge.getValue (). intValue ()); gauge.update (4); assertEquals (4, gauge.getCurrentValue (0)); gauge.update (1); assertEquals (4, gauge.getCurrentValue (0));

NumberGauge (LongGauge, DoubleGauge) pakker en gitt Nummer (Lang, Dobbelt). For å samle beregninger ved hjelp av disse målerne, må vi sørge for at Nummer er trådsikker.

3.3. Metriske typer - Timer

Tidtakere hjelp til å måle varigheten til en bestemt hendelse. Standard implementeringer er BasicTimer, StatsTimer, og BucketTimer.

BasicTimer registrerer total tid, telling og annen enkel statistikk:

BasicTimer timer = ny BasicTimer (MonitorConfig.builder ("test"). Build (), SECONDS); Stoppeklokke stoppeklokke = timer.start (); SECONDS.sleep (1); timer.record (2, SECONDS); stopwatch.stop (); assertEquals ("tidtakeren skal telle 1 sekund", 1, timer.getValue (). intValue ()); assertEquals ("tidtakeren skal telle 3 sekunder totalt", 3.0, timer.getTotalTime (), 0.01); assertEquals ("timer skal registrere 2 oppdateringer", 2, timer.getCount (). intValue ()); assertEquals ("timer bør ha maks 2", 2, timer.getMax (), 0.01);

StatsTimer gir mye rikere statistikk ved å ta utvalg mellom avstemningsintervallene:

System.setProperty ("netflix.servo", "1000"); StatsTimer timer = new StatsTimer (MonitorConfig .builder ("test") .build (), new StatsConfig.Builder () .withComputeFrequencyMillis (2000) .withPercentiles (new double [] {99.0, 95.0, 90.0}) .withPublishMax (true) .withPublishMin (true) .withPublishCount (true) .withPublishMean (true) .withPublishStdDev (true) .withPublishVariance (true) .build (), SECONDS); Stoppeklokke stoppeklokke = timer.start (); SECONDS.sleep (1); timer.record (3, SECONDS); stopwatch.stop (); stoppeklokke = timer.start (); timer.record (6, SECONDS); SECONDS.sleep (2); stopwatch.stop (); assertEquals ("timeren skal telle 12 sekunder totalt", 12, timer.getTotalTime ()); assertEquals ("tidtakeren skal telle totalt 12 sekunder", 12, timer.getTotalMeasurement ()); assertEquals ("timer bør registrere 4 oppdateringer", 4, timer.getCount ()); assertEquals ("statistikk timer verdi tidskostnad / oppdatering skal være 2", 3, timer.getValue (). intValue ()); endelig Map metricMap = timer.getMonitors (). stream () .collect (toMap (monitor -> getMonitorTagValue (monitor, "statistic"), monitor -> (Number) monitor.getValue ())); assertThat (metricMap.keySet (), containInAnyOrder ("count", "totalTime", "max", "min", "variance", "stdDev", "avg", "percentile_99", "percentile_95", "percentile_90") );

BucketTimer gir en måte å få distribusjon av prøver etter verdiområder for skuffing:

BucketTimer timer = new BucketTimer (MonitorConfig .builder ("test") .build (), new BucketConfig.Builder () .withBuckets (new long [] {2L, 5L}) .withTimeUnit (SECONDS) .build (), SECONDS) ; timer.record (3); timer.record (6); assertEquals ("timeren skal telle totalt 9 sekunder", 9, timer.getTotalTime (). intValue ()); Kart metricMap = timer.getMonitors (). Stream () .filter (monitor -> monitor.getConfig (). GetTags (). ContainKey ("servo.bucket")) .collect (toMap (m -> getMonitorTagValue (m, ") servo.bucket "), m -> (Long) m.getValue ())); assertThat (metricMap, allOf (hasEntry ("bucket = 2s", 0L), hasEntry ("bucket = 5s", 1L), hasEntry ("bucket = overflow", 1L)));

For å spore langvarige operasjoner som kan vare i flere timer, kan vi bruke den sammensatte skjermen Varighetstid.

3.4. Metriske typer - Informativ

Vi kan også bruke Informativ overvåke for å registrere beskrivende informasjon for å hjelpe feilsøking og diagnostikk. Den eneste implementeringen er Grunnleggende informasjon, og bruken av den kan ikke være enklere:

BasicInformational informational = new BasicInformational (MonitorConfig.builder ("test"). Build ()); informational.setValue ("informasjon samlet");

3.5. MonitorRegistry

Metriske typer er alle av typen Observere, som er selve basen for Servo. Vi vet nå at slags verktøy samler rå beregninger, men for å rapportere dataene må vi registrere disse skjermene.

Merk at hver enkelt konfigurerte skjerm skal registreres en gang og bare en gang for å sikre at beregningene er riktige. Så vi kan registrere skjermene ved hjelp av Singleton-mønster.

Det meste av tiden kan vi bruke DefaultMonitorRegistry å registrere skjermer:

Gauge gauge = new BasicGauge (MonitorConfig.builder ("test") .build (), () -> 2.32); DefaultMonitorRegistry.getInstance (). Register (gauge);

Hvis vi vil registrere en skjerm dynamisk, DynamicTimer, og DynamicCounter kan bli brukt:

DynamicCounter.increment ("monitor-name", "tag-key", "tag-value");

Vær oppmerksom på at dynamisk registrering vil føre til dyre oppslagsoperasjoner hver gang verdien oppdateres.

Servo tilbyr også flere hjelpemetoder for å registrere skjermer som er erklært i objekter:

Monitors.registerObject ("testObject", dette); assertTrue (Monitors.isObjectRegistered ("testObject", dette));

Metode registerObject vil bruke refleksjon for å legge til alle forekomster av Skjermer erklært ved kommentar @Observere og legg til koder erklært av @MonitorTags:

@Monitor (name = "integerCounter", type = DataSourceType.COUNTER, beskrivelse = "Totalt antall oppdateringsoperasjoner.") Privat AtomicInteger updateCount = nytt AtomicInteger (0); @MonitorTags private TagList tags = ny BasicTagList (newArrayList (ny BasicTag ("tag-key", "tag-value"))); @Test offentlig ugyldighet givenAnnotatedMonitor_whenUpdated_thenDataCollected () kaster Unntak {System.setProperty ("servo.pollers", "1000"); Monitors.registerObject ("testObject", dette); assertTrue (Monitors.isObjectRegistered ("testObject", dette)); updateCount.incrementAndGet (); updateCount.incrementAndGet (); SECONDS.sleep (1); Liste beregninger = observer.getObservations (); assertThat (beregninger, hasSize (greaterThanOrEqualTo (1))); Iterator metricIterator = metrics.iterator (); metricIterator.next (); // hopp over første tomme observasjon mens (metricIterator.hasNext ()) {assertThat (metricIterator.next (), hasItem (hasProperty ("config", hasProperty ("name", is ("integerCounter"))))); }}

4. Publiser beregninger

Med beregningene som er samlet, kan vi publisere det i hvilket som helst format, for eksempel å gjengi tidsseriegrafer på forskjellige datavisualiseringsplattformer. For å publisere beregningene må vi avstemme dataene jevnlig fra monitorobservasjonene.

4.1. MetricPoller

MetricPoller brukes som beregningsfetcher. Vi kan hente beregninger av MonitorRegistries, JVM, JMX. Ved hjelp av utvidelser kan vi måle beregninger som Apache-serverstatus og Tomcat-beregninger.

MemoryMetricObserver observatør = ny MemoryMetricObserver (); PollRunnable pollRunnable = new PollRunnable (new JvmMetricPoller (), new BasicMetricFilter (true), observer); PollScheduler.getInstance (). Start (); PollScheduler.getInstance (). AddPoller (pollRunnable, 1, SECONDS); SECONDS.sleep (1); PollScheduler.getInstance (). Stopp (); Liste beregninger = observer.getObservations (); assertThat (beregninger, hasSize (greaterThanOrEqualTo (1))); Listenøkler = extractKeys (beregninger); assertThat (nøkler, hasItems ("loadedClassCount", "initUsage", "maxUsage", "threadCount"));

Her opprettet vi en JvmMetricPoller til måling av JVM. Når du legger til polleren i planleggeren, lar vi avstemningsoppgaven kjøre hvert sekund. Systemets standard pollerkonfigurasjoner er definert i Pollere, men vi kan spesifisere pollere som skal brukes med systemegenskap servo. pollere.

4.2. MetricObserver

Ved måling av målinger, observasjoner av registrerte MetricObservers vil bli oppdatert.

MetricObservers som standard er MemoryMetricObserver, FileMetricObserver, og AsyncMetricObserver. Vi har allerede vist hvordan du bruker MemoryMetricObserver i forrige kodeeksempel.

For tiden er flere nyttige utvidelser tilgjengelige:

  • AtlasMetricObserver: publiser beregninger til Netflix Atlas for å generere tidsseriedata i minnet for analyse
  • CloudWatchMetricObserver: skyv beregninger til Amazon CloudWatch for overvåking og sporing av beregninger
  • GraphiteObserver: publiser beregninger til grafitt for å lagre og tegne graf

Vi kan implementere en tilpasset MetricObserver å publisere applikasjonsberegninger der vi ser det som hensiktsmessig. Det eneste du trenger å bry deg om er å håndtere de oppdaterte beregningene:

offentlig klasse CustomObserver utvider BaseMetricObserver {// ... @Override public void updateImpl (List metrics) {// TODO}}

4.3. Publiser til Netflix Atlas

Atlas er et annet beregningsrelatert verktøy fra Netflix. Det er et verktøy for å administrere dimensjonale tidsseriedata, som er et perfekt sted å publisere beregningene vi samlet inn.

Nå skal vi demonstrere hvordan vi kan publisere beregningene våre til Netflix Atlas.

La oss først legge til servo-atlas avhengighet av pom.xml:

 com.netflix.servo servo-atlas $ {netflix.servo.ver} 0.12.17 

Denne avhengigheten inkluderer en AtlasMetricObserver for å hjelpe oss med å publisere beregninger til Atlas.

Deretter skal vi sette opp en Atlas-server:

$ curl -LO '//github.com/Netflix/atlas/releases/download/v1.4.4/atlas-1.4.4-standalone.jar' $ curl -LO '//raw.githubusercontent.com/Netflix/atlas/ v1.4.x / conf / memory.conf '$ java -jar atlas-1.4.4-standalone.jar memory.conf

For å spare tid for testen, la oss sette trinnstørrelsen til 1 sekund i memory.conf, slik at vi kan generere en tidsseriediagram med nok detaljer om beregningene.

De AtlasMetricObserver krever en enkel konfigurasjon og en liste over koder. Beregning av de gitte kodene blir sendt til Atlas:

System.setProperty ("servo.pollers", "1000"); System.setProperty ("servo.atlas.batchSize", "1"); System.setProperty ("servo.atlas.uri", "// localhost: 7101 / api / v1 / publish"); AtlasMetricObserver observatør = ny AtlasMetricObserver (ny BasicAtlasConfig (), BasicTagList.of ("servo", "counter")); PollRunnable oppgave = ny PollRunnable (ny MonitorRegistryMetricPoller (), ny BasicMetricFilter (true), observatør);

Etter oppstart a PollScheduler med PollRunnable oppgave, kan vi publisere beregninger til Atlas automatisk:

Counter counter = new BasicCounter (MonitorConfig .builder ("test") .withTag ("servo", "counter") .build ()); DefaultMonitorRegistry .getInstance () .register (counter); assertThat (atlasValuesOfTag ("servo"), ikke (inneholderString ("counter"))); for (int i = 0; i <3; i ++) {counter.increment (RandomUtils.nextInt (10)); SECONDS.sleep (1); counter.increment (-1 * RandomUtils.nextInt (10)); SECONDS.sleep (1); } assertThat (atlasValuesOfTag ("servo"), containString ("counter"));

Basert på beregningene kan vi generere et linjediagram ved hjelp av graf API for Atlas:

5. Sammendrag

I denne artikkelen har vi introdusert hvordan du bruker Netflix Servo til å samle og publisere applikasjonsberegninger.

Hvis du ikke har lest introduksjonen vår til Dropwizard Metrics, kan du sjekke den her for en rask sammenligning med Servo.

Som alltid kan du finne den fulle implementeringskoden for denne artikkelen på Github.


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