Краткое руководство по микрометру

[[1-introduction]]

1. Вступление

https://github.com/micrometer-metrics/micrometer-docs предоставляет простой интерфейс над инструментальными средствами клиентов для ряда популярных систем мониторинга. ** В настоящее время он поддерживает следующие системы мониторинга: Atlas, Datadog , Графит, ганглии, инфлюкс, JMX и прометей.

В этой статье мы расскажем об основах использования Micrometer и его интеграции с Spring.

Для простоты мы возьмем Micrometer Atlas в качестве примера, чтобы продемонстрировать большинство наших вариантов использования.

[[2-maven-dependency]]

2. Maven Dependency

Для начала давайте добавим следующую зависимость в pom.xml :

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

Самую последнюю версию можно найти Вот .

[[3-registry]]

3. MeterRegistry

В микрометре MeterRegistry является основной компонент, используемый для регистрации счетчиков. Мы можем перебирать реестр и далее метрики каждого счетчика, чтобы генерировать временные ряды в бэкэнде с комбинациями метрик и их значений измерений.

Простейшая форма реестра: SimpleMeterRegistry .

Но в большинстве случаев мы должны использовать MeterRegistry явно разработан для нашей системы мониторинга; для Атласа это AtlasMeterRegistry ,

CompositeMeterRegistry позволяет нескольким регистрам быть добавленным Он предоставляет решение для публикации метрик приложений в различных поддерживаемых системах мониторинга одновременно.

Мы можем добавить любую MeterRegistry , необходимую для загрузки данных на несколько платформ:

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

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

В Micrometer есть поддержка статического глобального реестра:

Кроме того, набор статических компоновщиков на основе этого глобального реестра предоставляется для генерации счетчиков в https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/ядро/инструмент/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 и Meters

4.1. Tags

Идентификатор Meter состоит из имя и метки. Предполагается, что мы должны следовать соглашению об именах, которое разделяет слова точкой, чтобы гарантировать переносимость имен метрик в нескольких системах мониторинга.

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

Для нарезки Метрика для рассуждений о значениях. В приведенном выше коде page.visitors - это имя счетчика с тегом age = 20s . В этом случае счетчик предназначен для подсчета посетителей на странице в возрасте от 20 до 30 лет.

Для большой системы мы можем добавить общие теги в реестр, скажем, метрики из определенного региона:

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

4.2. Counter

Https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/core/instrument/Counter.java#L25[ Counter ]сообщает только о подсчете указанное свойство приложения. Мы можем создать пользовательский счетчик с помощью беглого компоновщика или вспомогательного метода любого MetricRegistry :

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

Как видно из приведенного выше фрагмента, мы пытались уменьшить счетчик на единицу, но мы можем монотонно увеличивать счетчик только на фиксированную положительную величину.

4.3. Timers

Для измерения задержек или частоты событий в нашей системе мы можем использовать https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/core/instrument/Timer.java # L34[Таймеры] .

Timer сообщит, по крайней мере, общее время и количество событий определенного временного ряда.

Например, мы можем записать событие приложения, которое может длиться несколько секунд:

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

Для записи длительных событий мы используем https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/core/instrument/LongTaskTimer.java# L26[ LongTaskTimer ]:

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. Gauge

  • Датчик показывает текущее значение метра. **

В отличие от других счетчиков, Gauges следует только сообщать данные, когда наблюдается. Gauges может быть полезен при мониторинге статистики кеша, коллекций и т. Д .:

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

Распределение событий и простая сводка предоставлены 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());

Кроме того, DistributionSummary и Timers могут быть обогащены квантилями:

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

В приведенном выше фрагменте три регистра с тэгами quantile = 0.3 , quantile = 0.5 и quantile = 0.95 будут доступны в реестре, указывая значения, ниже которых выпадают 95%, 50% и 30% наблюдений соответственно.

Чтобы увидеть эти квантили в действии, давайте добавим следующие записи:

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

Затем мы можем проверить, извлекая значения из этих трех квантилей Gauges :

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

Кроме того, Микрометр также поддерживает гистограммы:

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

Подобно квантилям, после добавления нескольких записей мы можем видеть, что гистограмма довольно хорошо справляется с вычислениями:

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

Как правило, гистограммы могут помочь проиллюстрировать прямое сравнение в отдельных сегментах. Гистограммы также можно масштабировать по времени, что весьма полезно для анализа времени отклика бэкэнд-сервиса:

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. Связующие

Микрометр имеет несколько встроенных связывателей для мониторинга JVM, кэшей, ExecutorService и служб ведения журналов.

Когда речь идет о JVM и системном мониторинге, мы можем отслеживать показатели загрузчика классов ( https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jvm/ClassLoaderMetrics.java # L27[ ClassLoaderMetrics ]), пул памяти JVM ( https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/микрометр/ядро ​​/прибор/связующее/jvm/JvmMemoryMetrics.java # L38[ JvmMemoryMetrics ]) и метрики ГХ ( JvmGcMetrics ), использование потоков и ЦП ( https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/микрометр/ядро ​​/инструмент/связующее/jvm/JvmThreadMetrics.java # L27[ JvmThreadMetrics ], https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/Основной/Java/IO/микрометра/ядро ​​/инструмент/связующий/система/Процессор Metrics.java # L30[ ProcessorMetrics ]).

Мониторинг кэша (в настоящее время поддерживаются только Guava, EhCache, Hazelcast и Caffeine) поддерживается с помощью инструментов с помощью https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/IO/микрометр/ядро ​​/инструмент/связующее вещество/кэш/GuavaCacheMetrics.java # L31[ GuavaCacheMetrics ], EhCache2Metrics , https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/микрометр/ядро ​​/прибор/связующее вещество/кэш/HazelcastCacheMetrics.java # L27[ HazelcastCacheMetrics https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/микрометр/ядро ​​/инструмент/связующий/кэш/CaffeineCacheMetrics.java # L42[ CaffeineCacheMetrics ].

А для отслеживания службы обратного входа мы можем связать https://github.com/micrometer-metrics/micrometer/blob/master/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/logging/LogbackMetrics.java # L36[ LogbackMetrics ]в любой действительный реестр:

new LogbackMetrics().bind(registry);

Использование вышеупомянутых связывателей очень похоже на LogbackMetrics и все довольно просто, поэтому мы не будем вдаваться в подробности здесь.

[[6-spring-integration]]

6. Весенняя интеграция

  • Spring Boot Actuator обеспечивает управление зависимостями и автоматическую настройку для Micrometer. ** Теперь он поддерживается в Spring Boot 2.0/1.x и Spring Framework 5.0/4.x.

Нам понадобится следующая зависимость (последнюю версию можно найти https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22io.micrometer%22%20AND%20a%3A%22micrometer жёсткости-наследие% 22[здесь]):

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

Без каких-либо дальнейших изменений в существующем коде мы включили поддержку Spring с помощью микрометра. Метрики памяти JVM нашего приложения Spring будут автоматически зарегистрированы в глобальном реестре и опубликованы в конечной точке атласа по умолчанию:

http://локальный : 7101/API/v1/publish .

Существует несколько настраиваемых свойств, доступных для управления режимами экспорта метрик, начиная с spring.metrics.atlas. ** . Проверьте AtlasConfig , чтобы увидеть полный список свойств конфигурации для публикации Atlas ,

Если нам нужно связать больше метрик, добавьте их только как @ Bean в контекст приложения.

Скажем, нам нужен JvmThreadMetrics :

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

Что касается веб-мониторинга, он автоматически настраивается для каждой конечной точки в нашем приложении, но управляется через свойство конфигурации:

spring.metrics.web.autoTimeServerRequests .

  • Реализация по умолчанию предоставляет четыре измерения показателей для конечных точек: метод HTTP-запроса, код ответа HTTP, URI конечной точки и информация об исключениях. **

При ответе на запросы метрики, относящиеся к методу запроса ( GET , POST и т. Д.), Будут опубликованы в Atlas.

Используя Atlas Graph API , мы можем сгенерировать график для сравнения времени отклика для разных методов:

ссылка:/uploads/methods-768x466.png%20768w[]

По умолчанию также сообщаются коды ответов 20x , 30x , 40x , 50x

ссылка:/uploads/status-768x576.png%20768w[]

Мы также можем сравнить различные URI:

ссылка:/uploads/uri-768x521.png%20768w[]

или проверьте метрики исключений:

ссылка:/uploads/exception-768x466.png%20768w[]

Обратите внимание, что мы также можем использовать @ Timed для класса контроллера или определенных методов конечной точки для настройки тегов, длинных задач, квантилей и процентилей метрик:

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

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

}

На основе приведенного выше кода мы можем увидеть следующие теги, проверив конечную точку Atlas http://localhost : 7101/api/v1/tags/name :

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

Микрометр также работает в веб-среде функций, представленной в Spring Boot 2.0. Метрики могут быть включены путем фильтрации функции RouterFunction :

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

Метрики из источника данных и запланированных задач также могут быть собраны.

Обратитесь к official документов для более подробной информации.

[[7-summary]]

7. Заключение

В этой статье мы представили метрику фасада Микрометр. Благодаря абстракции и поддержке нескольких систем мониторинга в соответствии с общей семантикой, инструмент делает переключение между различными платформами мониторинга довольно простым.

Как всегда, полный код реализации этой статьи можно найти over на Github .