Wavefrontで学ぶ分散トレーシング Part-4
この文章は、Wavefrontで学ぶ分散トレーシング シリーズの第四回目です。
シリーズ
第一回 : 概要編
第二回 : Spring Bootで分散トレーシング
第三回 : REDメトリクスって何?
第四回 : サービスをつなげてみる**← いまここ**
第五回 : Pythonで分散トレーシング
第六回 : AMQPで分散トレーシング
第七回 ; サービスメッシュで分散トレーシング
始めに
今回は2つのサービスをつなげてその時の動作をみたいと思います。 以下を目指します。
準備編
第二回と同じ手順でアプリを作ってください。 正しく構成されていれば、以下のURLで"Hello World"もしくは"Good Bye World"が表示されるはずです。
1curl localhost:8082/hello
なお、混乱をさけるため、このアプリは記事ではREDアプリと呼称します。 今回はこのREDアプリに加え、もうひとつアプリをつくり、くっつけてみます。
新しく作る方をHUBアプリと呼びます。
ソースコード
ここに公開しています。
https://github.com/mhoshi-vm/wf-demanabu-dis-tracing/tree/master/4
HUBアプリの準備
ここからはHUBアプリの作り方です。
(もうほぼテンプレですが) 準備ができたら、以下のURLにアクセスしてください。
ログイン後、以下を実施します。
- Add Dependencies を選択
- Spring Webを検索して追加
- Sleuth も同様に追加
- Wavefront も同様に追加
最後にGenerateをクリックします。 zipファイルは現在のアプリと重複しない場所に展開してください。
お気に入りのエディターで以下のファイルを開いてください。
1mhoshino@mhoshino demo % vi src/main/java/com/example/demo/DemoApplication.java
これを以下の内容に差し替えてください。
1package com.example.demo;
2
3import java.util.Map;
4
5import org.slf4j.Logger;
6import org.slf4j.LoggerFactory;
7import org.springframework.beans.factory.annotation.Autowired;
8import org.springframework.beans.factory.annotation.Value;
9import org.springframework.boot.SpringApplication;
10import org.springframework.boot.autoconfigure.SpringBootApplication;
11import org.springframework.context.annotation.Bean;
12import org.springframework.core.ParameterizedTypeReference;
13import org.springframework.http.HttpMethod;
14import org.springframework.web.bind.annotation.GetMapping;
15import org.springframework.web.bind.annotation.RequestHeader;
16import org.springframework.web.bind.annotation.RestController;
17import org.springframework.web.client.RestTemplate;
18
19@SpringBootApplication
20public class DemoApplication {
21
22 public static void main(String[] args) {
23 SpringApplication.run(DemoApplication.class, args);
24 }
25
26}
27
28@RestController
29class HubController{
30
31 private static final Logger LOGGER = LoggerFactory.getLogger(HubController.class);
32
33 @Value("${hub.urls}")
34 private String urls;
35
36 @Autowired
37 RestTemplate restTemplate;
38
39 @Bean
40 public RestTemplate getRestTemplate() {
41 return new RestTemplate();
42 }
43
44 @GetMapping(value="/hub")
45 public String MultiRest(@RequestHeader Map<String, String> header) {
46 printAllHeaders(header);
47
48 for( String url : urls.split(",") )
49 {
50 LOGGER.info(String.format("URLS = %s", url));
51 restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<String>() {}).getBody();
52 }
53 return "REST Complete";
54 }
55
56 private void printAllHeaders(Map<String, String> headers) {
57 headers.forEach((key, value) -> {
58 LOGGER.info(String.format("Header '%s' = %s", key, value));
59 });
60 }
61}
さらに以下のファイルを開きます。
1mhoshino@mhoshino demo % vi src/main/resources/application.properties
そして以下の内容を追記します。
1management.endpoints.web.exposure.include=wavefront
2server.port=8083
3wavefront.application.name=demo3
4wavefront.application.service=Hub
5
6hub.urls=http://localhost:8082/hello
コード編集は以上です。
サービスをくっつけてみる
さて、アプリを起動します。以下のコマンドをREDアプリとHUBアプリ両方で実行します。(同じコマンドなのでディレクトリーを混乱しないように)
1./mvnw sprint-boot:run
そしてしばらく、以下のURLに対してコマンドを何回か実行します。
1curl localhost:8083/hub
しばらくしたら、WavefrontのURLにログインしてみましょう。
http://localhost:8083/actuator/wavefront
そして、Wavefrontにログイン後、[Applications] > [Application Map(Beta)]を選択します。
うまくいってれば、以下のように図がつながっているはずです。
[Applications] > [Traces]を開くと、Traceログがみれるはずです。
何が起きている?
さて、いつもどおり後回しの解説です。 今回作ったHUBアプリは非常に単純に、前回作ったREDアプリへREST APIを送るシンプルなアプリです。 コードでいうと以下の箇所
1 @GetMapping(value="/hub")
2 public String MultiRest(@RequestHeader Map<String, String> header) {
3 printAllHeaders(header);
4
5 for( String url : urls.split(",") )
6 {
7 LOGGER.info(String.format("URLS = %s", url));
8 restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<String>() {}).getBody();
9 }
10 return "REST Complete";
11 }
どのURLへ送るかはapplication.properties
のhub.urls
パラメーターで指定します。
1hub.urls=http://localhost:8082/hello
もうすこし詳細な挙動をみてみましょう。
HUBアプリのログを見てみます。 以下のようなログになっているかと思います。
12020-07-20 09:18:40.787 INFO [,5f14e2e08374d381d7534b5d89939527,d7534b5d89939527,true] 34562 --- [nio-8083-exec-2]
22020-07-20 09:18:40.787 INFO [,5f14e2e08374d381d7534b5d89939527,d7534b5d89939527,true] 34562 --- [nio-8083-exec-2]
32020-07-20 09:18:40.787 INFO [,5f14e2e08374d381d7534b5d89939527,d7534b5d89939527,true] 34562 --- [nio-8083-exec-2]
42020-07-20 09:18:40.787 INFO [,5f14e2e08374d381d7534b5d89939527,d7534b5d89939527,true] 34562 --- [nio-8083-exec-2]
注目するのが[,5f14e2e08374d381d7534b5d89939527,d7534b5d89939527,true]
の箇所で、第一回目で説明したよう、5f14e2e08374d381d7534b5d89939527
がTrace ID
でd7534b5d89939527
がスパンIDです。
REDアプリのログをみてみます。 以下のようなログになっているかと思います。
1[hellorest,5f14e2e08374d381d7534b5d89939527,7ce53e353e48c2aa,true] 34007 --- [nio-8082-exec-2]
2[hellorest,5f14e2e08374d381d7534b5d89939527,7ce53e353e48c2aa,true] 34007 --- [nio-8082-exec-2]
3[hellorest,5f14e2e08374d381d7534b5d89939527,7ce53e353e48c2aa,true] 34007 --- [nio-8082-exec-2]
4[hellorest,5f14e2e08374d381d7534b5d89939527,7ce53e353e48c2aa,true] 34007 --- [nio-8082-exec-2]
ここで着目すると
5f14e2e08374d381d7534b5d89939527
のTrace IDが一致している- Span ID がREDアプリとHUBアプリの間で異なる
さらに、このログを右の箇所注目するとこのようになっていると思います
12020-07-20 09:18:40.789 INFO Header 'accept' = text/plain, application/json, application/*+json, */*
22020-07-20 09:18:40.789 INFO Header 'x-b3-traceid' = 5f14e2e08374d381d7534b5d89939527
32020-07-20 09:18:40.789 INFO Header 'x-b3-spanid' = 067b8ed01abdb759
42020-07-20 09:18:40.789 INFO Header 'x-b3-parentspanid' = d7534b5d89939527
52020-07-20 09:18:40.789 INFO Header 'x-b3-sampled' = 1
62020-07-20 09:18:40.789 INFO Header 'user-agent' = Java/14.0.1
72020-07-20 09:18:40.789 INFO Header 'host' = localhost:8082
82020-07-20 09:18:40.789 INFO Header 'connection' = keep-alive
これは、HUBアプリからやってきた、HTTPのヘッダーを出力しています。 ここからわかることが
- x-b3-trace-id にTrace IDが含まれている
- x-b3-parentspanid にHUBアプリのSpan IDが含まれている
x-b3?
さて、x-b3 ってなんぞや?ですが、これはb3-propagationとよばれるZipkinで定義されているTrace情報を共有するためのHTTPヘッダーです。
詳しくは、ここを参照ください。
Spring Bootではこのx-b3のアップストームからの展開とダウンストリームへの挿入をSluethがほぼコードからは透過的に実施します。 以下の③の箇所で定義したときのものです。
まとめ
- サービス同士をくっつけるには、Spring Bootでは単純にREST APIを実行すればよい
- サービス同士はTrace ID、Span IDをHTTPの"x-b3-*“ヘッダーでやり取りしている
- “x-b3-*“ヘッダーは、Spring BootではSluethが勝手にやってくれるのでうれしい
さて、次回はこのx-b3-ヘッダーの取り扱いがどれだけややこしいか、pythonをつかって説明したいと思います。 次回は「Pythonで分散トレーシング」です。