Kurzanleitung zum Mikrometer

[[1-introduction]]

1. Einführung

https://github.com/micrometer-metrics/micrometer-docs bietet eine einfache Fassade gegenüber den Instrumentierungsclients für eine Reihe gängiger Überwachungssysteme. ** Derzeit werden folgende Überwachungssysteme unterstützt: Atlas, Datadog , Graphit, Ganglia, Influx, JMX und Prometheus.

In diesem Artikel werden die grundlegende Verwendung von Mikrometer und die Integration mit Spring vorgestellt.

Der Einfachheit halber nehmen wir den Mikrometer Atlas als Beispiel, um die meisten unserer Anwendungsfälle zu demonstrieren.

[[2-maven-dependency]]

2. Maven-Abhängigkeit

Fügen wir zunächst die folgende Abhängigkeit zu pom.xml hinzu:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-atlas</artifactId>
    <version>0.12.0.RELEASE</version>
</dependency>

Die neueste Version finden Sie unter Hier .

[[3-registry]]

3. MeterRegistry

Im Mikrometer-Bereich ist ein MeterRegistry der Kernkomponente für die Erfassung von Zählern. Wir können die Registrierung und weitere Metriken jedes Zählers iterieren, um im Backend eine Zeitreihe mit Kombinationen von Metriken und ihren Dimensionswerten zu generieren.

Die einfachste Form der Registrierung ist SimpleMeterRegistry .

CompositeMeterRegistry ermöglicht das mehrfache Registrieren hinzugefügt werden. Es bietet eine Lösung zur gleichzeitigen Veröffentlichung von Anwendungsmetriken auf verschiedenen unterstützten Überwachungssystemen.

Wir können jedes beliebige MeterRegistry hinzufügen, um die Daten auf mehrere Plattformen hochzuladen:

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

compositeRegistry.add(oneSimpleMeter);
compositeRegistry.add(atlasMeterRegistry);

In Micrometer gibt es eine statische globale Registrierungsunterstützung:

Außerdem wird ein Satz statischer Builder auf der Grundlage dieser globalen Registrierung bereitgestellt, um Zähler in https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/zu generieren. core/instrument/Metrics.java # L30[ Metrics ]:

@Test
public void givenGlobalRegistry__whenIncrementAnywhere__thenCounted() {
    class CountedObject {
        private CountedObject() {
            Metrics.counter("objects.instance").increment(1.0);
        }
    }
    Metrics.addRegistry(new SimpleMeterRegistry());

    Metrics.counter("objects.instance").increment();
    new CountedObject();

    Optional<Counter> counterOptional = Metrics.globalRegistry
      .find("objects.instance").counter();
    assertTrue(counterOptional.isPresent());
    assertTrue(counterOptional.get().count() == 2.0);
}

[[4-meters]]

4. Tags und Meters

4.1. Stichworte

Ein Bezeichner eines Meter besteht aus einen Namen und Tags. Es wird empfohlen, einer Namenskonvention zu folgen, bei der Wörter mit einem Punkt getrennt werden, um die Übertragbarkeit von Metriknamen über mehrere Überwachungssysteme hinweg zu gewährleisten. **

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

Tags kann zum Aufteilen der Daten verwendet werden Metrik für die Begründung der Werte. Im obigen Code ist page.visitors der Name des Messgeräts mit age = 20s als Tag. In diesem Fall soll der Zähler die Besucher der Seite im Alter zwischen 20 und 30 zählen.

Bei einem großen System können Sie häufig verwendete Tags an eine Registrierung anfügen, beispielsweise, die Metriken stammen aus einer bestimmten Region:

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

4.2. Zähler

Ein Counter meldet lediglich einen Zählerstand eine angegebene Eigenschaft einer Anwendung. Wir können einen benutzerdefinierten Zähler mit dem fluent Builder oder der Hilfemethode eines beliebigen MetricRegistry erstellen:

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

Wie aus dem obigen Ausschnitt ersichtlich, haben wir versucht, den Zähler um eins zu verringern, aber ** wir können den Zähler nur monoton um einen festen positiven Betrag erhöhen.

4.3. Timer

Um die Latenzen oder die Häufigkeit von Ereignissen in unserem System zu messen, können wir https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/core/instrument/Timer.java # L34[Timer] .

Ein Timer gibt mindestens die Gesamtzeit und Ereignisanzahl bestimmter Zeitreihen an.

Beispielsweise können wir ein Anwendungsereignis aufzeichnen, das mehrere Sekunden dauern kann:

SimpleMeterRegistry registry = new SimpleMeterRegistry();
Timer timer = registry.timer("app.event");
timer.record(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(1500);
    } catch (InterruptedException ignored) { }
});

timer.record(3000, MILLISECONDS);

assertTrue(2 == timer.count());
assertTrue(4510 > timer.totalTime(MILLISECONDS)
  && 4500 <= timer.totalTime(MILLISECONDS));
SimpleMeterRegistry registry = new SimpleMeterRegistry();
LongTaskTimer longTaskTimer = LongTaskTimer
  .builder("3rdPartyService")
  .register(registry);

long currentTaskId = longTaskTimer.start();
try {
    TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException ignored) { }
long timeElapsed = longTaskTimer.stop(currentTaskId);

assertTrue(timeElapsed/(int) 1e9 == 2);

4.4. Spur

  • Eine Anzeige zeigt den aktuellen Wert eines Zählers an. **

Anders als bei anderen Messgeräten sollte Gauges verwendet werden Nur Daten melden, wenn beobachtet. Gauges kann nützlich sein, wenn Sie Statistiken zu Cache, Sammlungen usw. überwachen:

SimpleMeterRegistry registry = new SimpleMeterRegistry();
List<String> list = new 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

Die Verteilung der Ereignisse und eine einfache Zusammenfassung finden Sie unter https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/core/instrument/DistributionSummary.java# L29[ DistributionSummary ]:

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

Außerdem können DistributionSummary und Timers um Quantile erweitert werden:

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

Im obigen Snippet sind drei Messgeräte mit den Tags quantile = 0,3 , quantile = 0,5 und quantile = 0,95 in der Registrierung verfügbar. Sie geben die Werte an, unter denen 95%, 50% bzw. 30% der Beobachtungen fallen.

Um diese Quantile in Aktion zu sehen, fügen Sie die folgenden Datensätze hinzu:

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

Dann können wir die Werte in diesen drei Quantilen Gauges ermitteln:

List<Gauge> quantileGauges = registry.getMeters().stream()
  .filter(m -> m.getType().name().equals("Gauge"))
  .map(meter -> (Gauge) meter)
  .collect(Collectors.toList());

assertTrue(3 == quantileGauges.size());

Map<String, Integer> quantileMap = extractTagValueMap(registry, Type.Gauge, 1e9);
assertThat(quantileMap, allOf(
  hasEntry("quantile=0.3",2),
  hasEntry("quantile=0.5", 3),
  hasEntry("quantile=0.95", 8)));

Micrometer unterstützt außerdem Histogramme:

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

Ähnlich wie bei Quantilen können wir nach dem Anhängen mehrerer Datensätze feststellen, dass das Histogramm die Berechnung ziemlich gut handhabt:

Map<String, Integer> histograms = extractTagValueMap(registry, Type.Counter, 1.0);
assertThat(histograms, 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)));

Im Allgemeinen können Histogramme helfen, einen direkten Vergleich in separaten Buckets darzustellen. Histogramme können auch zeitlich skaliert werden, was für die Analyse der Antwortzeit des Backend-Services sehr nützlich ist:

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

[[5-binders]]

5. Bindemittel

Das Mikrometer verfügt über mehrere integrierte Ordner zur Überwachung der JVM, der Caches, des ExecutorService und der Protokollierungsdienste.

Um den Protokollierungsdienst zu überwachen, können wir https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/logging/binden . LogbackMetrics.java # L36[ LogbackMetrics ]an eine gültige Registrierung:

new LogbackMetrics().bind(registry);

Die Verwendung der obigen Ordner ist LogbackMetrics ziemlich ähnlich und alle sind ziemlich einfach, sodass wir uns hier nicht mit weiteren Details befassen.

[[6-spring-integration]]

6. Spring Integration

  • Spring Boot Actuator bietet Abhängigkeitsverwaltung und automatische Konfiguration für Mikrometer. ** Jetzt wird es in Spring Boot 2.0/1.x und Spring Framework 5.0/4.x unterstützt.

Wir benötigen die folgende Abhängigkeit (die neueste Version finden Sie unter https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22io.micrometer%22%20A%3A%22micrometer -spring-legacy% 22[hier]):

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-spring-legacy</artifactId>
    <version>0.12.0.RELEASE</version>
</dependency>

Ohne weitere Änderung des vorhandenen Codes haben wir die Spring-Unterstützung mit dem Mikrometer aktiviert. JVM-Speichermetriken unserer Spring-Anwendung werden automatisch in der globalen Registrierung registriert und auf dem Standardatlasendpunkt veröffentlicht:

http://localhost : 7101/api/v1/publish .

Es stehen mehrere konfigurierbare Eigenschaften zur Verfügung, mit denen das Verhalten von Metriken beim Exportieren gesteuert werden kann, beginnend mit spring.metrics.atlas. ** . Unter AtlasConfig finden Sie eine vollständige Liste der Konfigurationseigenschaften für die Veröffentlichung von Atlas .

Wenn Sie mehr Metriken binden müssen, fügen Sie sie nur als @ Bean zum Anwendungskontext hinzu.

Sagen wir, wir brauchen die JvmThreadMetrics :

@Bean
JvmThreadMetrics threadMetrics(){
    return new JvmThreadMetrics();
}

Das Web-Monitoring wird für jeden Endpunkt in unserer Anwendung automatisch konfiguriert, kann jedoch über eine Konfigurationseigenschaft verwaltet werden:

spring.metrics.web.autoTimeServerRequests .

  • Die Standardimplementierung bietet vier Dimensionen von Metriken für Endpunkte: HTTP-Anforderungsmethode, HTTP-Antwortcode, Endpunkt-URI und Informationen zu Ausnahmen.

Wenn Anfragen beantwortet werden, werden Metriken in Bezug auf die Anforderungsmethode ( GET , POST usw.) in Atlas veröffentlicht.

Mit Atlas Graph API können wir eine Grafik erstellen, um die Antwortzeiten für verschiedene Methoden zu vergleichen:

Standardmäßig werden auch Antwortcodes von 20x , 30x , 40x , 50x gemeldet:

Wir können auch verschiedene URIs vergleichen:

oder überprüfen Sie Ausnahmemetriken:

Beachten Sie, dass wir auch https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/core/annotation/Timed.java#L24 Timed__]für die Controller-Klasse oder bestimmte Endpunktmethoden zum Anpassen von Tags, langen Aufgaben, Quantilen und Perzentilen der Metriken:

@RestController
@Timed("people")
public class PeopleController {

    @GetMapping("/people")
    @Timed(value = "people.all", longTask = true)
    public List<String> listPeople() {
       //...
    }

}

Basierend auf dem obigen Code können wir die folgenden Tags sehen, indem Sie den Atlas-Endpunkt http://localhost : 7101/api/v1/tags/name überprüfen:

----["people", "people.all", "jvmBufferCount", ...]----

Mikrometer funktioniert auch mit dem in Spring Boot 2.0 eingeführten Funktions-Web-Framework. Metriken können durch Filtern der RouterFunction aktiviert werden:

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

Metriken aus der Datenquelle und geplante Aufgaben können ebenfalls erfasst werden.

Weitere Informationen finden Sie unter http://micrometer.io/docs/atlas#__scheduling (Offizielle Dokumentation)].

[[7-summary]]

7. Fazit

In diesem Artikel haben wir die Metrikfassade Mikrometer vorgestellt. Durch das Abstrahieren und Unterstützen mehrerer Überwachungssysteme unter gängiger Semantik macht das Tool den Wechsel zwischen verschiedenen Überwachungsplattformen recht einfach.

Den vollständigen Implementierungscode dieses Artikels finden Sie wie immer unter über Github .