Wavefrontで学ぶ分散トレーシング Part-3

この文章は、Wavefrontで学ぶ分散トレーシング シリーズの第三回目です。

シリーズ

第一回 : 概要編
第二回 : Spring Bootで分散トレーシング
第三回 : REDメトリクスって何? ← いまここ
第四回 : サービスをつなげてみる
第五回 : Pythonで分散トレーシング
第六回 : AMQPで分散トレーシング
第七回 ; サービスメッシュで分散トレーシング

始めに

前回Wavefrontで簡単なアプリで分散トレーシングをしましたが、以下の画面がでてきたと思えます。

画面最初のペインは3行で構成されていますが、これはREDメトリクスをベースに作成されています。

REDメトリクスとは Rate, Error, Durationの頭文字で、元々はWeaveworksのTom Wilkie氏が提唱した考え方です

Wavefrontでは、各サービスの分散トレーシングのREDメトリクスを表示し、それぞれを測れるようにしています。 なお、Durationが見慣れないP95という表示になっていますが、これはパーセンタイル95%を表しています。あえて、ざっくりとした説明をしますが、これはやってきた全てのリクエストの95%目の遅いリクエストを表示しています。

さて、前回のデモでは特にErrorやDurationで面白い結果が表示されていないと思います。 今回はもうすこしこのREDについて理解を深めようというものです。

ここからの手順はほとんど前回と一緒ですが、微妙に違う箇所もあります。

準備編

Spring BootはJavaのフレームワークです。そのため、最低限以下が必要です。

  • Java JDK 8+

Oracle JDKに従いJDKをインストールしてください。

ソースコード

ここに公開しています。

https://github.com/mhoshi-vm/wf-demanabu-dis-tracing/tree/master/3

アプリの準備

準備ができたら、以下のURLにアクセスしてください。

start.spring.io

ログイン後、以下を実施します。

  • Add Dependencies を選択
  • Spring Webを検索して追加
  • Sleuth も同様に追加
  • Wavefront も同様に追加

最後にGenerateをクリックします。 すると、zipファイルのダウンロードされるので、どこでもいいので展開してくだい。

お気に入りのエディターで以下のファイルを開いてください。

1mhoshino@mhoshino demo % vi src/main/java/com/example/demo/DemoApplication.java

これを以下の内容に差し替えてください。

 1
 2package com.example.demo;
 3
 4import java.util.Map;
 5
 6import org.slf4j.Logger;
 7import org.slf4j.LoggerFactory;
 8import org.springframework.boot.SpringApplication;
 9import org.springframework.boot.autoconfigure.SpringBootApplication;
10import org.springframework.http.ResponseEntity;
11import org.springframework.web.bind.annotation.GetMapping;
12import org.springframework.web.bind.annotation.RequestHeader;
13import org.springframework.web.bind.annotation.RestController;
14
15@SpringBootApplication
16public class DemoApplication {
17
18	public static void main(String[] args) {
19		SpringApplication.run(DemoApplication.class, args);
20	}
21
22}
23
24@RestController
25class HelloRestController {
26
27	private static final Logger LOGGER = LoggerFactory.getLogger(HelloRestController.class);
28
29        @GetMapping("/hello")
30        public ResponseEntity<String> hello (@RequestHeader Map<String, String> header) throws InterruptedException{
31
32                printAllHeaders(header);
33
34                // Generate bad request 10%
35                if ((long)(Math.random()*10%10) == 1) {
36                    return ResponseEntity.badRequest().body("Good Bye World!");
37                }
38                int randomNumber = (int) (Math.random()*100);
39
40                if (randomNumber > 97) {
41                    // Wait for 5 seconds in 2%
42                    Thread.sleep(5000);
43                }else if (randomNumber > 90) {
44                    // Wait for 2 seconds in 10%
45                    Thread.sleep(2000);
46                }
47                return ResponseEntity.ok("Hello World!");
48        }
49
50	private void printAllHeaders(Map<String, String> headers) {
51		headers.forEach((key, value) -> {
52			LOGGER.info(String.format("Header '%s' = %s", key, value));
53		});
54	}
55}

さらに以下のファイルを開きます。

1mhoshino@mhoshino demo % vi src/main/resources/application.properties

そして以下の内容を追記します。

1management.endpoints.web.exposure.include=wavefront
2server.port=8082
3wavefront.application.name=demo2
4wavefront.application.service=HelloRED

コード編集は以上です。

試してみる

それではアプリケーションを稼働させます。 以下のコマンドを実行してください。

1mhoshino@mhoshino demo % ./mvnw spring-boot:run

うまくいけば、エラーなくアプリケーションが起動するはずです。 別プロンプトを開いて以下のコマンドをしばらく実行します。

1watch -n 0.1 curl localhost:8082/hello

さて5分ほどながしたら、サービスダッシュボードを見てみましょう。 これは、前回と同じく以下のURLでアクセスできるはず。

https://localhost:8082/actuator/wavefront

REDを分析する

しばらくすると、概ね以下のような図になるかと思います。

さて、この結果と実際のコードを照らし合わせてみましょう。 まず、Errorの以下の値をみてましょう。

これは以下のコードの結果です。 要は、10%の確率でエラーに陥らせた結果です。

1
2                // Generate bad request 10%
3                if ((long)(Math.random()*10%10) == 1) {
4                    return ResponseEntity.badRequest().body("Good Bye World!");
5                }

なのでこれは結果どおりかと思います。

さて面白いのが以下のDuration(P95)の結果です。

さて一番遅いのが2秒と結果が出ていますが、以下がコードの結果です。

1
2                if (randomNumber > 97) {
3                    // Wait for 5 seconds in 2%
4                    Thread.sleep(5000);
5                }else if (randomNumber > 90) {
6                    // Wait for 2 seconds in 10%
7                    Thread.sleep(2000);
8                }

注目がこのコードは本来2%の確率で5秒まつ10%の確率で2秒まつとしている点です。 実際すこしスクロールダウンすると、実際には5秒待ちを検知しているのがわかります。

しかし、結果からわかるとおり、5秒まつの結果が無視されます。これが「パーセンタイル 95%」の意味です。要は、高い値の95% 以上の確率で発生する遅延はエラー値として、無視するという考えです。

この値に関して、色々考え方があるとは思いますが、とりあえず現段階で知って欲しいことはWavefrontがこういった分析結果を表示できる点です。(しかもタダで)

まとめ

  • REDメトリクスは、Rate Error Durationの頭文字
  • WavefrontでもREDメトリクスを元に、分析できる
  • パーセンタイル95%など難しい結果表示もWavefrontでできる

次回は「サービスをつなげてみる」です。