1概要


Netflix Servo

は、Javaアプリケーション用のメトリックツールです。サーボはhttp://metrics.dropwizard.io/[Dropwizard Metrics]に似ていますが、それでもはるかに単純です。 JMXを利用するのは、アプリケーションメトリックを公開および公開するための単純なインタフェースを提供するためだけです。

この記事では、Servoが提供するものと、それを使用してアプリケーションメトリックを収集および公開する方法を紹介します。


2 Mavenの依存関係

実際の実装に入る前に、https://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22servo-core%22[Servo]依存関係を

pom.xml

ファイルに追加しましょう。

<dependency>
    <groupId>com.netflix.servo</groupId>
    <artifactId>servo-core</artifactId>
    <version>0.12.16</version>
</dependency>

その他にも、https://search.maven.org/classic/#search%7Cga%7C1%7Cservo-apache[Servo-Apache]、https://search.maven.org/classic/など、多数の拡張機能があります。 #search%7Cga%7C1%7Cervo-aws[Servo-AWS]など。後で必要になるかもしれません。これらの拡張機能の最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22com.netflix.servo%22[Maven Central]にもあります。


3メトリックスを収集する

まず、アプリケーションからメトリックを集める方法を見てみましょう。

サーボは4つの主要なメトリックタイプを提供します。



Counter


、http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/Gauge.html[

Gauge

]、http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/サーボ/モニタ/Timer.html[

Timer、

]および


情報



3.1. メトリクスの種類 –



カウンター




Counters


は、増分を記録するために使用されます。一般的に使用される実装は


BasicCounter





http://netflix.githubです。

io/サーボ/電流/サーボコア/docs/javadoc/com/netflix/serv/monitor/StepCounter.html[StepCounter]

、および


PeakRateCounter



BasicCounter

は、カウンターがすべきことを、わかりやすく簡単に実行します。

Counter counter = new BasicCounter(MonitorConfig.builder("test").build());
assertEquals("counter should start with 0", 0, counter.getValue().intValue());

counter.increment();

assertEquals("counter should have increased by 1", 1, counter.getValue().intValue());

counter.increment(-1);

assertEquals("counter should have decreased by 1", 0, counter.getValue().intValue());


PeakRateCounter

は、ポーリング間隔中の特定の1秒間の最大カウントを返します。

Counter counter = new PeakRateCounter(MonitorConfig.builder("test").build());
assertEquals(
  "counter should start with 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());

他のカウンタと異なり、

StepCounter

は前回のポーリング間隔の1秒あたりのレートを記録します。

System.setProperty("servo.pollers", "1000");
Counter counter = new StepCounter(MonitorConfig.builder("test").build());

assertEquals("counter should start with rate 0.0", 0.0, counter.getValue());

counter.increment();
SECONDS.sleep(1);

assertEquals(
  "counter rate should have increased to 1.0",
  1.0, counter.getValue());

上記のコードで

servo.pollers



1000

に設定したことに注意してください。これは、ポーリング間隔をデフォルトで60秒と10秒の間隔ではなく1秒に設定することでした。これについては後で詳しく説明します。


3.2. メトリクスタイプ –



Gauge




Gauge


は、現在の値を返す単純なモニタです。



BasicGauge


、http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/MinGauge.html[

MinGauge

]、http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/サーボ/モニタ/MaxGauge.html[

MaxGauge

]、およびhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/NumberGauge.html[

NumberGauges

]が提供されます。


BasicGauge



Callable

を呼び出して現在の値を取得します。コレクションのサイズ、

BlockingQueue

の最新値、または小さな計算を必要とする任意の値を取得できます。

Gauge<Double> gauge = new BasicGauge<>(MonitorConfig.builder("test")
  .build(), () -> 2.32);

assertEquals(2.32, gauge.getValue(), 0.01);


MaxGauge



MinGauge

は、それぞれ最大値と最小値を追跡するために使用されます。

MaxGauge gauge = new 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

(http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/LongGauge.html[

LongGauge

]、http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/DoubleGauge.html[

DoubleGauge

])は、提供された

Number



Long



Double

)をラップします。これらのゲージを使用してメトリックを収集するには、

Number

がスレッドセーフであることを確認する必要があります。


3.3. メトリクスタイプ –



Timer




Timers


は、特定のイベントの期間を測定するのに役立ちます。デフォルトの実装はhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/BasicTimer.html[

BasicTimer

]、http://netflix.github.io/です。サーボ/電流/サーボコア/docs/javadoc/com/netflix/サーボ/モニター/StatsTimer.html[

StatsTimer

]、およびhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/serv/monitor/BucketTimer.html[

BucketTimer

]。


BasicTimer

は合計時間、カウント、その他の単純な統計を記録します。

BasicTimer timer = new BasicTimer(MonitorConfig.builder("test").build(), SECONDS);
Stopwatch stopwatch = timer.start();

SECONDS.sleep(1);
timer.record(2, SECONDS);
stopwatch.stop();

assertEquals("timer should count 1 second", 1, timer.getValue().intValue());
assertEquals("timer should count 3 seconds in total",
  3.0, timer.getTotalTime(), 0.01);
assertEquals("timer should record 2 updates", 2, timer.getCount().intValue());
assertEquals("timer should have max 2", 2, timer.getMax(), 0.01);


StatsTimer

は、ポーリング間隔をサンプリングすることによって、より豊富な統計を提供します。

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);
Stopwatch stopwatch = timer.start();

SECONDS.sleep(1);
timer.record(3, SECONDS);
stopwatch.stop();

stopwatch = timer.start();
timer.record(6, SECONDS);
SECONDS.sleep(2);
stopwatch.stop();

assertEquals("timer should count 12 seconds in total",
  12, timer.getTotalTime());
assertEquals("timer should count 12 seconds in total",
  12, timer.getTotalMeasurement());
assertEquals("timer should record 4 updates", 4, timer.getCount());
assertEquals("stats timer value time-cost/update should be 2",
  3, timer.getValue().intValue());

final Map<String, Number> metricMap = timer.getMonitors().stream()
  .collect(toMap(monitor -> getMonitorTagValue(monitor, "statistic"),
    monitor -> (Number) monitor.getValue()));

assertThat(metricMap.keySet(), containsInAnyOrder(
  "count", "totalTime", "max", "min", "variance", "stdDev", "avg",
  "percentile__99", "percentile__95", "percentile__90"));


BucketTimer

は、値の範囲をまとめてサンプルの分布を取得する方法を提供します。

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(
  "timer should count 9 seconds in total",
  9, timer.getTotalTime().intValue());

Map<String, Long> 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("bucket=2s", 0L), hasEntry("bucket=5s", 1L),
  hasEntry("bucket=overflow", 1L)));

何時間も続く可能性がある長時間の操作を追跡するには、複合モニターhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/DurationTimerを使用できます。 html[

DurationTimer

]。


3.4. メトリクスの種類 –



情報


また、http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/Informational.html[

Informational

]モニターを使用して説明情報を記録することもできます。デバッグと診断に役立ちます。唯一の実装はhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/BasicInformational.html[

BasicInformational

]であり、その使い方は単純ではあり得ません:

BasicInformational informational = new BasicInformational(
  MonitorConfig.builder("test").build());
informational.setValue("information collected");


3.5.

MonitorRegistry


メトリックタイプはすべてhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/service/monitor/Monitor.html[

Monitor

]タイプのすべてです。

サーボ

。生のメトリクスを収集するツールの種類はわかっていますが、データを報告するには、これらのモニタを登録する必要があります。

メトリックの正確性を保証するために、設定された各モニタは1回だけ登録する必要があります。そのため、シングルトンパターンを使用してモニターを登録できます。

ほとんどの場合、http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/DefaultMonitorRegistry.html[

DefaultMonitorRegistry

]を使用してモニターを登録できます。

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

動的にモニターを登録したい場合は、http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/DynamicTimer.html[

DynamicTimer

]、およびhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/DynamicCounter.html[

DynamicCounter

]を使用できます。

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

動的登録では、値が更新されるたびに高価な検索操作が発生します。

サーボは、オブジェクトで宣言されたモニタを登録するためのいくつかのヘルパーメソッドも提供します。

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

メソッドhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/monitor/Monitors.html#registerObject(java.lang.String,%20java.lang.Object)[

registerObject

]は、アノテーションhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/annotations/Monitor.html[

によって宣言された

Monitors

のすべてのインスタンスを追加するためにリフレクションを使用します。 @Monitor

]とhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/annotations/MonitorTags.html[

@MonitorTags

]で宣言されたタグを追加します。

@Monitor(
  name = "integerCounter",
  type = DataSourceType.COUNTER,
  description = "Total number of update operations.")
private AtomicInteger updateCount = new AtomicInteger(0);

@MonitorTags
private TagList tags = new BasicTagList(
  newArrayList(new BasicTag("tag-key", "tag-value")));

@Test
public void givenAnnotatedMonitor__whenUpdated__thenDataCollected() throws Exception {
    System.setProperty("servo.pollers", "1000");
    Monitors.registerObject("testObject", this);
    assertTrue(Monitors.isObjectRegistered("testObject", this));

    updateCount.incrementAndGet();
    updateCount.incrementAndGet();
    SECONDS.sleep(1);

    List<List<Metric>> metrics = observer.getObservations();

    assertThat(metrics, hasSize(greaterThanOrEqualTo(1)));

    Iterator<List<Metric>> metricIterator = metrics.iterator();
    metricIterator.next();//skip first empty observation

    while (metricIterator.hasNext()) {
        assertThat(metricIterator.next(), hasItem(
          hasProperty("config",
          hasProperty("name", is("integerCounter")))));
    }
}


4メトリクスを公開する

収集されたメトリックを使用して、さまざまなデータ視覚化プラットフォームで時系列グラフをレンダリングするなど、任意の形式で公開できます。メトリクスを公開するには、監視観測からデータを定期的にポーリングする必要があります。


4.1.

MetricPoller


メトリクスフェッチャーとしては、http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/publish/MetricPoller.html[

MetricPoller

]が使用されます。


MonitorRegistries


、http://netflix.githubのメトリックスを取得できます。 IO/サーボ/電流/サーボコア/docs/javadoc/com/netflix/serv/publish/JvmMetricPoller.html[JVM]、http://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/publish/JmxMetricPoller.html[JMX]

拡張機能の助けを借りて、私たちはhttps://github.com/Netflix/servo/tree/master/servo-apache[Apacheサーバーのステータス]やhttps://github.com/Netflix/servo/tree/のようなメトリックスをポーリングすることができますmaster/serv-tomcat[Tomcatメトリック]。

MemoryMetricObserver observer = new 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().stop();
List<List<Metric>> metrics = observer.getObservations();

assertThat(metrics, hasSize(greaterThanOrEqualTo(1)));
List<String> keys = extractKeys(metrics);

assertThat(keys, hasItems("loadedClassCount", "initUsage", "maxUsage", "threadCount"));

ここで、JVMのメトリックをポーリングするために


JvmMetricPoller


を作成しました。スケジューラにポーラーを追加すると、ポーリングタスクは毎秒実行されます。システムのデフォルトのポーラー設定は


Pollers


で定義されていますが、ポーラーを指定することもできますシステムプロパティ

servo.pollers

と共に使用します。


4.2.

MetricObserver


メトリックスをポーリングすると、登録されているhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/publish/MetricObserver.html[

MetricObservers

]の観測値が更新されます。

デフォルトで提供される

MetricObservers

はhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/servo/publish/MemoryMetricObserver.html[

MemoryMetricObserver

]、http://netflix.githubです。 IO/サーボ/電流/サーボコア/docs/javadoc/com/netflix/serv/publish/FileMetricObserver.html[

FileMetricObserver

]、およびhttp://netflix.github.io/servo/current/servo-core/docs/javadoc/com/netflix/serv/publish/AsyncMetricObserver.html[

AsyncMetricObserver

]。

前のコードサンプルで

MemoryMetricObserver

の使い方をすでに説明しました。

現在、いくつかの便利な拡張機能が利用可能です。

メトリクスをhttps://github.com/Netflix/atlas[Netflix Atlas]に公開します。
分析用のデータをメモリ内で時系列に生成する
**


CloudWatchMetricObserver


:

メトリクスをhttps://aws.amazon.com/cloudwatch/[Amazon CloudWatch]にプッシュする
メトリックの監視と追跡
**


GraphiteObserver


:

保存してグラフ化するためにhttp://graphiteapp.org/[Graphite]にメトリクスを公開する

カスタマイズした

MetricObserver

を実装して、適切な場所にアプリケーションメトリックを公開できます。気にするべき唯一の事は更新された測定基準を扱うことです:

public class CustomObserver extends BaseMetricObserver {

   //...

    @Override
    public void updateImpl(List<Metric> metrics) {
       //TODO
    }
}


4.3. Netflix Atlasに公開する



Atlas


は、Netflixのもう1つの指標関連のツールです。これはディメンション時系列データを管理するためのツールです。これは、収集した指標を公開するのに最適な場所です。

これで、メトリクスをNetflix Atlasに公開する方法について説明します。

まず、https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22com.netflix.servo%22%20AND%20a%3A%22servo-atlas%22[

servo-を追加しましょう。

pom.xml__への依存関係:

<dependency>
      <groupId>com.netflix.servo</groupId>
      <artifactId>servo-atlas</artifactId>
      <version>${netflix.servo.ver}</version>
</dependency>

<properties>
    <netflix.servo.ver>0.12.17</netflix.servo.ver>
</properties>

この依存関係には、メトリックを

Atlas

に公開するのに役立つ

AtlasMetricObserver

が含まれています。

その後、Atlasサーバーをセットアップします。

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

テストの時間を節約するために、

memory.conf

でステップサイズを1秒に設定して、メトリックの詳細を含む時系列グラフを生成できるようにします。


AtlasMetricObserver

には、簡単な設定とタグのリストが必要です。与えられたタグのメトリクスはAtlasにプッシュされます。

System.setProperty("servo.pollers", "1000");
System.setProperty("servo.atlas.batchSize", "1");
System.setProperty("servo.atlas.uri", "http://localhost:7101/api/v1/publish");
AtlasMetricObserver observer = new AtlasMetricObserver(
  new BasicAtlasConfig(), BasicTagList.of("servo", "counter"));

PollRunnable task = new PollRunnable(
  new MonitorRegistryMetricPoller(), new BasicMetricFilter(true), observer);


PollRunnable

タスクで

PollScheduler

を起動した後、メトリクスをAtlasに自動的に公開できます。

Counter counter = new BasicCounter(MonitorConfig
  .builder("test")
  .withTag("servo", "counter")
  .build());
DefaultMonitorRegistry
  .getInstance()
  .register(counter);
assertThat(atlasValuesOfTag("servo"), not(containsString("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"), containsString("counter"));

メトリクスに基づいて、Atlasのhttps://github.com/Netflix/atlas/wiki/Graph[graph API]を使用して折れ線グラフを生成できます。

リンク:/uploads/graph.png%20780w[]


5概要

この記事では、Netflix Servoを使用してアプリケーションメトリックを収集して公開する方法を紹介しました。

Dropwizard Metricsの紹介をまだ読んでいない場合は、Servoとの簡単な比較のために/dropwizard-metrics[ここ]をチェックしてください。

いつものように、この記事の完全な実装コードはhttps://github.com/eugenp/tutorials/tree/master/metrics[over on Github]にあります。