Micrometer

Posted by KimJongMin on 2019-12-03

Micrometer란?

micrometer.io에서는 Micrometer에 대해서 다음과 같이 소개하고 있다.

Micrometer provides a simple facade over the instrumentation clients for the most popular monitoring systems, allowing you to instrument your JVM-based application code without vendor lock-in. Think SLF4J, but for metrics

Micrometer는 JVM 기반의 애플리케이션에서 다양한 모니터링 도구가 제공하는 클라이언트 라이브러리에 대한 facade를 제공한다. 로깅 관련된 시스템에서는 SLF4J가 있다면 모니터링(metric) 시스템에서는 Micrometer가 있는 것이다.

즉, 모니터링 시스템을 만드는 vendor들은 Micrometer 인터페이스를 따르기 때문에 Micrometer를 사용하면 애플리케이션 내의 코드 상에서는 모니터링 시스템 클라이언트로 어떤 것을 사용할지에 대한 고민에서 벗어나 Micrometer를 이용해 애플리케이션 metric을 수집하기만 하면 된다.
(모니터링 시스템을 선택하는 것은 런타임 시점에 정해진다고 생각하면 된다.)

예를 들어, 모니터링 시스템으로 Prometheus를 사용한다고 하면 아래와 같이 표현할 수 있다.
micrometer

Micrometer는 다음과 같은 모니터링 시스템을 지원한다.

  • AppOptics, Azure Monitor, Netflix Atlas, CloudWatch, Datadog, Dynatrace, Elastic, Ganglia, Graphite, Humio, Influx/Telegraf, JMX, KairosDB, New Relic, Prometheus, SignalFx, Google Stackdriver, StatsD, Wavefront

Micrometer에 의해서 기록된 애플리케이션의 metric 정보는 시스템의 이상 유뮤룰 판단하기 위한 모니터링(알람) 용도로 사용된다.

Supported monitoring systems

Micrometer는 코어 모듈과 측정 SPI(Service Provider Interface)를 포함하고 있다. (각각 Registry라고 부르는 다양한 모니터링 시스템에 대한 구현을 포함하고 있다.)
모니터링 시스템에는 중요한 3가지 특징이 있다.

Dimensionality

Dimensionality는 수집하는 metric 이름에 tag(key-value)를 붙일 수 있도록 지원하는 것을 말한다. 반면 일부 모니터링 시스템의 경우에는 tag 형태가 아닌, flat한 metric name만 사용이 가능하다. 이를 hierarchical system이라고 한다.
Micrometer는 hierarchical system에 metric을 보낼 때는 tag를 metric name에 추가한다.

  • Dimensional: AppOptics, Atlas, Azure Monitor, Cloudwatch, Datadog, Datadog StatsD, Dynatrace, Elastic, Humio, Influx, KairosDB, New Relic, Prometheus, SignalFx, Sysdig StatsD, Telegraf StatsD, Wavefront
  • Hierarchical: Graphite, Ganglia, JMX, Etsy StatsD

Rate aggregation

모니터링 시스템 사용자들은 일정 시간 간격 동안의 특정 지표에 대한 평균값을 필요로 하는 경우가 많다. 어떤 모니터링 시스템은 애플리케이션에서 평균값을 직접 구해서 보내주기를 기대한다. 반면에 어떤 모니터링 시스템은 애플리케이션이 누적된 값을 보내주기를 기대하며, 모니터링 시스템이 직접 평균값을 구하는 경우도 있다.

  • Client-side: AppOptics, Atlas, Azure Monitor, Datadog, Elastic, Graphite, Ganglia, Humio, Influx, JMX, Kairos, New Relic, all StatsD flavors, SignalFx
  • Server-side: Prometheus, Wavefront

Publishing

일부 모니터링 시스템은 metric 정보를 애플리케이션으로부터 polling한다. 반면 일부 모니터링 시스템은 애플리케이션이 일정한 간격으로 metric 정보를 push하는 방식으로 사용된다.

  • Client pushes: AppOptics, Atlas, Azure Monitor, Datadog, Elastic, Graphite, Ganglia, Humio, Influx, JMX, Kairos, New Relic, SignalFx, Wavefront
  • Server polls: Prometheus, all StatsD flavors

Micrometer 어떤 Registry를 사용하는지에 따라, 위와 같은 요구사항을 충족하도록 metric 정보를 커스터마이징한다.

Registry

Meter는 애플리케이션의 metric을 수집하기 위한 인터페이스이다. Meter는 MeterRegistry에 의해 생성되어 등록된다. 지원되는 각 모니터링 시스템은 MeterRegistry 구현체를 갖고 있다.

SimpleMeterRegistry는 각 meter의 최신 값을 메모리에 저장한다. 그리고 metric 정보를 다른 시스템으로 내보내지 않는다. 따라서 만약 어떤 모니터링 시스템을 사용할지 결정하지 못했다면 SimpleMegerRegistry를 사용하면 된다.

1
MeterRegistry registry = new SimpleMeterRegistry();

Composite registries

Micrometer는 여러 Registry를 추가할 수 있는 CompositeMeterRegistry를 제공한다. 따라서 CompositeMeterRegistry를 사용하면 둘 이상의 모니터링 시스템에서 동시에 metric을 사용할 수 있다.

1
2
3
4
5
6
CompositeMeterRegistry compositeRegistry = new CompositeMeterRegistry();
SimpleMeterRegistry oneSimpleMeter = new SimpleMeterRegistry();
AtlasMeterRegistry atlasMeterRegistry = new AtlasMeterRegistry(atlasConfig, Clock.SYSTEM);

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

Global registry

Micrometer는 static 변수로 Global MeterRegistry를 제공한다. Metrics.globalRegistry를 통해 static 변수에 접근할 수 있으며 Metrics 클래스에는 글로벌 MeterRegistry를 기반으로 Meter를 생성하는 정적 빌더 메소드가 있다.
Global MeterRegistry는 CompositeMeterRegistry 객체이다.

Meters

Micrometer는 Meter의 구현체로 다음의 것들을 지원한다. Meter의 type 별로 수집되는 metric 수가 다르다.

  • Timer, Counter, Gauge, DistributionSummary, LongTaskTimer, FunctionCounter, FunctionTimer, TimeGauge

Meter는 이름(name)태그(tag)로 고유하게 식별된다.

Naming

Micrometer는 소문자 단어를 ‘.’으로 구분하는 naming 규칙을 사용한다. 각각의 모니터링 시스템은 naming 규칙과 관련해 권장 사항을 갖고 있으며 일부 모니터링 시스템은 서로의 naming 규칙이 달라 호환되지 않을 수도 있다.

따라서 모니터링 시스템의 각 Micrometer 구현체는 소문자 단어와 ‘.’으로 구분된 이름을 각자의 모니터링 시스템 naming 규칙으로 변환하는 기능을 제공한다.

예를 들면 아래의 timer meter는 각각의 모니터링에서 다음과 같이 변경된다.

1
registry.timer("http.server.requests");

  • Prometheus: http_server_requests_duration_seconds
  • Atlas: httpServerRequests
  • Graphite: http.server.requests
  • InfluxDB: http_server_requests

그러므로 Micrometer의 소문자 단어를 ‘.’으로 구분하는 naming 규칙을 사용하면 모니터링 시스템 종류에 상관없이 metric name에 대해 이식성을 보장할 수 있다.

Counter

Counter는 애플리케이션에서 특정 속성에 대한 카운트를 기록한다. Build method 혹은 MetricRegistry의 helper method를 통해 custom counter를 생성할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
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);

Timers

시스템의 latency(지연 시간) 혹은 이벤트 빈도를 측정하기 위해서 Timers를 사용할 수 있다. Timer는 이벤트가 발생한 수와 총 시간을 기록한다.

1
2
3
4
5
6
7
8
9
10
11
12
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));

Gauge

Gauge는 Meter의 현재 값을 보여준다. 다른 Meter와 다르게 Guage는 데이터의 변경이 관찰 된 경우에만 데이터를 기록한다. 캐시 등의 통계를 모니터링 할 때 유용하다.

1
2
3
4
5
6
7
8
9
10
11
12
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);

Binders

Micrometer에는 JVM, 캐시, ExecutorService 및 로깅 서비스를 모니터링하기 위한 여러 내장 Binder가 있다.

  • JVM 및 시스템 모니터링: ClassLoaderMetrics
  • JVM memory pool: JvmMemoryMetrics
  • GC metrics: JvmGcMetrics
  • Thread 및 CPU 사용률: JvmThreadMetrics, ProcessorMetrics