Uvod u Netflix Servo

1. Pregled

Netflix Servo je mjerni alat za Java programe. Servo je sličan Dropwizard Metrics, ali puno jednostavniji. Koristi JMX samo za pružanje jednostavnog sučelja za izlaganje i objavljivanje mjernih podataka aplikacije.

U ovom ćemo članku predstaviti što Servo pruža i kako ga možemo koristiti za prikupljanje i objavljivanje mjernih podataka aplikacije.

2. Ovisnosti Mavena

Prije nego što krenemo u stvarnu implementaciju, dodajmo ovisnost Servoa na pom.xml datoteka:

 com.netflix.servo servo-jezgra 0.12.16 

Osim toga, na raspolaganju su mnoga proširenja, kao što su Servo-Apache, Servo-AWS itd. Možda će nam zatrebati kasnije. Najnovije verzije ovih proširenja također se mogu naći na Maven Central.

3. Prikupiti metriku

Prvo, pogledajmo kako prikupiti mjerne podatke iz naše aplikacije.

Servo pruža četiri osnovne metričke vrste: Brojač, Mjerač, Mjerač vremena, i Informativni.

3.1. Vrste metrika - Brojač

Brojači koriste se za bilježenje prirasta. Uobičajeno korištene implementacije su BasicCounter, StepCounter, i PeakRateCounter.

BasicCounter čini ono što bi brojač trebao učiniti, jednostavno i izravno:

Brojač brojača = novi BasicCounter (MonitorConfig.builder ("test"). Build ()); assertEquals ("brojač treba započeti s 0", 0, counter.getValue (). intValue ()); counter.increment (); assertEquals ("brojač se trebao povećati za 1", 1, counter.getValue (). intValue ()); brojač.prirast (-1); assertEquals ("brojač se trebao smanjiti za 1", 0, counter.getValue (). intValue ());

PeakRateCounter vraća maksimalno brojanje u određenoj sekundi tijekom intervala glasanja:

Brojač brojača = novi PeakRateCounter (MonitorConfig.builder ("test"). Build ()); assertEquals ("brojač treba započeti s 0", 0, counter.getValue (). intValue ()); counter.increment (); SEKUNDE.spavanje (1); counter.increment (); counter.increment (); assertEquals ("vršna stopa trebala bi biti 2", 2, counter.getValue (). intValue ());

Za razliku od ostalih brojača, StepCounter bilježi stopu u sekundi prethodnog biračkog intervala:

System.setProperty ("servo.pollers", "1000"); Brojač brojača = novi StepCounter (MonitorConfig.builder ("test"). Build ()); assertEquals ("brojač treba započeti s stopom 0,0", 0,0, counter.getValue ()); counter.increment (); SEKUNDE.spavanje (1); assertEquals ("brojač brojača trebao se povećati na 1,0", 1,0, counter.getValue ());

Primijetite da smo postavili servo.poleri do 1000 u gornjem kodu. To je trebalo postaviti interval ispitivanja na 1 sekundu, umjesto na intervale od 60 sekundi i 10 sekundi prema zadanim postavkama. O tome ćemo više govoriti kasnije.

3.2. Vrste metrika - Mjerač

Mjerač je jednostavan monitor koji vraća trenutnu vrijednost. BasicGauge, MinGauge, MaxGauge, i Brojilice su osigurani.

BasicGauge priziva a Pozivno da se dobije trenutna vrijednost. Možemo dobiti veličinu zbirke, najnoviju vrijednost a BlockingQueue ili bilo koja vrijednost koja zahtijeva mala izračunavanja.

Mjerač = novi BasicGauge (MonitorConfig.builder ("test") .build (), () -> 2,32); assertEquals (2,32, gauge.getValue (), 0,01);

MaxGauge i MinGauge koriste se za praćenje maksimalne, odnosno minimalne vrijednosti:

MaxGauge gauge = novi 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) obavija predviđeni Broj (Dugo, Dvostruko). Da bismo prikupili mjerne podatke pomoću ovih mjerila, moramo osigurati Broj zaštićen je nitima.

3.3. Vrste metrika - Tajmer

Tajmeri pomoć pri mjerenju trajanja određenog događaja. Zadane su implementacije BasicTimer, StatsTimer, i BucketTimer.

BasicTimer bilježi ukupno vrijeme, brojanje i ostale jednostavne statistike:

BasicTimer timer = novi BasicTimer (MonitorConfig.builder ("test"). Build (), SECONDS); Štoperica štoperica = timer.start (); SEKUNDE.spavanje (1); timer.record (2, SEKUNDE); štoperica.stop (); assertEquals ("timer treba računati 1 sekundu", 1, timer.getValue (). intValue ()); assertEquals ("tajmer bi trebao računati ukupno 3 sekunde", 3.0, timer.getTotalTime (), 0,01); assertEquals ("timer treba zabilježiti 2 ažuriranja", 2, timer.getCount (). intValue ()); assertEquals ("timer treba imati najviše 2", 2, timer.getMax (), 0,01);

StatsTimer pruža mnogo bogatiju statistiku uzorkovanjem između intervala glasanja:

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); Štoperica štoperica = timer.start (); SEKUNDE.spavanje (1); timer.record (3, SEKUNDE); štoperica.stop (); štoperica = timer.start (); timer.record (6, SEKUNDE); SEKUNDE.spavanje (2); štoperica.stop (); assertEquals ("tajmer treba računati ukupno 12 sekundi", 12, timer.getTotalTime ()); assertEquals ("tajmer treba računati ukupno 12 sekundi", 12, timer.getTotalMeasurement ()); assertEquals ("timer treba zabilježiti 4 ažuriranja", 4, timer.getCount ()); assertEquals ("statistika vrijednost vremena, trošak / ažuriranje treba biti 2", 3, timer.getValue (). intValue ()); konačna karta metricMap = timer.getMonitors (). stream () .collect (toMap (monitor -> getMonitorTagValue (monitor, "statistika"), monitor -> (Number) monitor.getValue ())); assertThat (metricMap.keySet (), containsInAnyOrder ("count", "totalTime", "max", "min", "variance", "stdDev", "avg", "percentile_99", "percentile_95", "percentile_90")) );

BucketTimer pruža način za dobivanje distribucije uzoraka skupljanjem raspona vrijednosti:

BucketTimer timer = novi BucketTimer (MonitorConfig .builder ("test") .build (), novi BucketConfig.Builder () .withBuckets (novi dugi [] {2L, 5L}) .withTimeUnit (SECONDS) .build (), SECONDS) ; timer.record (3); timer.record (6); assertEquals ("timer bi trebao računati ukupno 9 sekundi", 9, timer.getTotalTime (). intValue ()); Mapa metricMap = timer.getMonitors (). Stream () .filter (monitor -> monitor.getConfig (). GetTags (). ContainsKey ("servo.bucket")) .collect (toMap (m -> getMonitorTagValue (m, " servo.bucket "), m -> (Long) m.getValue ())); assertThat (metricMap, allOf (hasEntry ("kanta = 2s", 0L), hasEntry ("kanta = 5s", 1L), hasEntry ("kanta = preljev, 1L)));

Da bismo pratili dugotrajne operacije koje bi mogle trajati satima, možemo koristiti kompozitni monitor TrajanjeTimera.

3.4. Vrste metrika - Informativni

Također, možemo iskoristiti Informativni monitor za bilježenje opisnih podataka koji pomažu u otklanjanju pogrešaka i dijagnostici. Jedina provedba je OsnovneInformacijske, a njegova upotreba ne može biti jednostavnija:

BasicInformational informational = novi BasicInformational (MonitorConfig.builder ("test"). Build ()); informational.setValue ("prikupljene informacije");

3.5. MonitorRegistry

Metrički su tipovi svih vrsta Monitor, što je sama baza Servo. Sada znamo da vrste alata prikupljaju sirove mjerne podatke, ali da bismo prijavili podatke, moramo registrirati te monitore.

Imajte na umu da bi svaki pojedinačno konfigurirani monitor trebao biti registriran jednom i samo jednom kako bi se osigurala ispravnost mjernih podataka. Tako možemo registrirati monitore koristeći Singleton uzorak.

Većinu vremena možemo koristiti DefaultMonitorRegistry za registraciju monitora:

Mjerač = novi BasicGauge (MonitorConfig.builder ("test") .build (), () -> 2,32); DefaultMonitorRegistry.getInstance (). Register (gauge);

Ako želimo dinamički registrirati monitor, DynamicTimer, i DynamicCounter može se koristiti:

DynamicCounter.increment ("ime-monitora", "ključ oznake", "vrijednost-oznake");

Imajte na umu da bi dinamička registracija uzrokovala skupe operacije pretraživanja svaki put kad se vrijednost ažurira.

Servo također nudi nekoliko pomoćnih metoda za registraciju monitora deklariranih u objektima:

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

Metoda registerObject upotrijebit će refleksiju za dodavanje svih primjera Monitori deklarirano anotacijom @Monitor i dodaj oznake koje je deklarirao @MonitorTags:

@Monitor (name = "integerCounter", type = DataSourceType.COUNTER, description = "Ukupan broj operacija ažuriranja.") Private AtomicInteger updateCount = new AtomicInteger (0); @MonitorTags private TagList tags = new BasicTagList (newArrayList (new BasicTag ("tag-key", "tag-value"))); @Test javna praznina givenAnnotatedMonitor_whenUpdated_thenDataCollected () baca izuzetak {System.setProperty ("servo.pollers", "1000"); Monitors.registerObject ("testObject", ovo); assertTrue (Monitors.isObjectRegistered ("testObject", ovo)); updateCount.incrementAndGet (); updateCount.incrementAndGet (); SEKUNDE.spavanje (1); Popis metrika = promatrač.getObservations (); assertThat (metrics, hasSize (largerThanOrEqualTo (1))); Iterator metricIterator = metrics.iterator (); metricIterator.next (); // preskočiti prvo prazno promatranje while (metricIterator.hasNext ()) {assertThat (metricIterator.next (), hasItem (hasProperty ("config", hasProperty ("name", is ("integerCounter")))))); }}

4. Objavi metriku

Sa prikupljenim mjernim podacima možemo ih objaviti u bilo kojem formatu, poput prikazivanja grafikona vremenskih serija na različitim platformama za vizualizaciju podataka. Da bismo objavili mjerne podatke, moramo povremeno anketirati podatke iz promatranja monitora.

4.1. MetricPoller

MetricPoller koristi se kao dohvatnik mjernih podataka. Možemo dohvatiti mjerne podatke MonitorRegistries, JVM, JMX. Uz pomoć proširenja možemo anketirati metrike poput statusa Apache poslužitelja i Tomcat metrike.

MemoryMetricObserver promatrač = novi MemoryMetricObserver (); PollRunnable pollRunnable = novi PollRunnable (novi JvmMetricPoller (), novi BasicMetricFilter (istina), promatrač); PollScheduler.getInstance (). Start (); PollScheduler.getInstance (). AddPoller (pollRunnable, 1, SECONDS); SEKUNDE.spavanje (1); PollScheduler.getInstance (). Stop (); Popis metrika = promatrač.getObservations (); assertThat (metrics, hasSize (largerThanOrEqualTo (1))); Ključevi popisa = extractKeys (mjerni podaci); assertThat (ključevi, hasItems ("loadedClassCount", "initUsage", "maxUsage", "threadCount"));

Ovdje smo stvorili JvmMetricPoller za ispitivanje metrike JVM-a. Kada dodajemo aparat za planiranje, dopuštamo da se zadatak ankete pokreće svake sekunde. Zadane konfiguracije sustava za ispitivanje definirane su u Polleri, ali možemo odrediti alate za uporabu sa svojstvom sustava servo.poleri.

4.2. MetricObserver

Prilikom ispitivanja mjernih podataka, zapažanja registriranih MetricObservers bit će ažuriran.

MetricObservers prema zadanim postavkama su MemoryMetricObserver, FileMetricObserver, i AsyncMetricObserver. Već smo pokazali kako se koristi MemoryMetricObserver u prethodnom uzorku koda.

Trenutno je dostupno nekoliko korisnih proširenja:

  • AtlasMetricObserver: objaviti metrike u Netflix Atlas za generiranje podataka o vremenskim serijama u memoriji za analitiku
  • CloudWatchMetricObserver: push metrike na Amazon CloudWatch za praćenje i praćenje mjerenja
  • GraphiteObserver: objaviti mjerne podatke u Graphiteu za pohranu i grafički prikaz

Možemo implementirati prilagođene MetricObserver objaviti mjerne podatke aplikacije tamo gdje mi smatramo potrebnim. Jedino što bi vas trebalo brinuti je rukovanje ažuriranim mjernim podacima:

javna klasa CustomObserver proširuje BaseMetricObserver {// ... @Override public void updateImpl (Popis mjernih podataka) {// TODO}}

4.3. Objavi na Netflix Atlas

Atlas je još jedan alat za mjerenje povezan s Netflixom. To je alat za upravljanje podacima dimenzijskih vremenskih serija, što je savršeno mjesto za objavljivanje mjernih podataka koje smo prikupili.

Sada ćemo pokazati kako objaviti naše mjerne podatke na Netflix Atlasu.

Prvo, dodamo servo-atlas ovisnost o pom.xml:

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

Ova ovisnost uključuje AtlasMetricObserver kako bi nam pomogao objaviti metriku na Atlas.

Zatim ćemo postaviti Atlasov poslužitelj:

$ 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

Da bismo uštedjeli vrijeme za test, postavimo veličinu koraka na 1 sekundu memorija.konf, tako da možemo generirati grafikon vremenskih serija s dovoljno detalja o mjernim podacima.

The AtlasMetricObserver zahtijeva jednostavnu konfiguraciju i popis oznaka. Metrike zadanih oznaka bit će prebačene u Atlas:

System.setProperty ("servo.pollers", "1000"); System.setProperty ("servo.atlas.batchSize", "1"); System.setProperty ("servo.atlas.uri", "// localhost: 7101 / api / v1 / objaviti"); AtlasMetricObserver promatrač = novi AtlasMetricObserver (novi BasicAtlasConfig (), BasicTagList.of ("servo", "brojač")); PollRunnable zadatak = novi PollRunnable (novi MonitorRegistryMetricPoller (), novi BasicMetricFilter (istina), promatrač);

Nakon pokretanja a Raspoređivač anketa s AnketaRunnable zadatak, možemo automatski objaviti mjerne podatke u Atlasu:

Brojač brojača = novi BasicCounter (MonitorConfig .builder ("test") .withTag ("servo", "counter") .build ()); DefaultMonitorRegistry .getInstance () .register (brojač); assertThat (atlasValuesOfTag ("servo"), ne (sadržiString ("brojač"))); za (int i = 0; i <3; i ++) {counter.increment (RandomUtils.nextInt (10)); SEKUNDE.spavanje (1); counter.increment (-1 * RandomUtils.nextInt (10)); SEKUNDE.spavanje (1); } assertThat (atlasValuesOfTag ("servo"), containsString ("brojač"));

Na temelju mjernih podataka možemo generirati linijski grafikon koristeći API grafikona Atlas:

5. Sažetak

U ovom smo članku predstavili kako koristiti Netflix Servo za prikupljanje i objavljivanje mjernih podataka aplikacije.

U slučaju da niste pročitali naš uvod u Dropwizard Metrics, pogledajte ovdje za brzu usporedbu sa Servoom.

Kao i uvijek, puni implementacijski kod ovog članka nalazi se na Githubu.