Slide 1

Slide 1 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 2020/06/04 コネヒトマルシェ オンライン Yoichiro Shimizu @budougumi0617 ゆるふわ分散トレースはじめました

Slide 2

Slide 2 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 自己紹介 2 ● 清水 陽一郎 @budougumi0617 ● BASE BANK, Inc. Dev Division ○ Go/PHP/Python/AWS etc... ● コミュニティ: golang.tokyo / Go Conference etc... ● 趣味: ボルダリング/毎週ブログを書くこと ○ https://budougumi0617.github.io/ Go Conferenece

Slide 3

Slide 3 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. はじめに 3

Slide 4

Slide 4 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 4 ● なぜ分散トレースが必要なのか ○ 舞台となる事業のアーキテクチャ構成 ● 分散トレースとは何なのか ○ 分散トレースの概要 ○ ”ゆるふわ”とは ● どうやって実現したのか ○ Context patternを使ったGoとPythonの実装 ● 導入してどうだったか アジェンダ

Slide 5

Slide 5 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 5 ● 複数サービスでシステムを構成したときに生じる悩みを共有する ● 分散トレースについてざっくり知ってもらう ● インフラ構成の変更、追加予算なしで始める方法の紹介 ● リクエストIDを付けるだけでも解析が便利になることを共有する 今日のゴール

Slide 6

Slide 6 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. なぜ分散トレースが 必要なのか 6

Slide 7

Slide 7 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 売れたタイミングで自動支払い 即時で資金調達できるという体験 100万店舗のデータから BASE独自の売上予測を開発 リスクなく、即時で資金調達できる金融サービス https://thebase.in/yellbank 7 YELL BANK

Slide 8

Slide 8 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. BASE本体 分析データ データ分析基盤 API データ処理系 API ログ分析 エラーレポート 8 YELL BANKのアーキテクチャ構成 CWL Kibana Raygun

Slide 9

Slide 9 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● どのログ同士(エラーレポート)が関連しているのかわからない 9 エラーが発生したとき エラー発生  エラーに対応している  ログはどれ? どれ? どれ?

Slide 10

Slide 10 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 時刻で絞って探すのを止めたかった 分散トレースしたい! 10

Slide 11

Slide 11 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 分散トレースとは 11

Slide 12

Slide 12 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● MicroservicesのObservabilityに関するパターンのひとつ ● 個々の外部リクエストに一意なIDを与え、そのリクエストがサービス間をどのよう にやり取りされたのか可視化、解析する 12 分散トレース(Distributed tracing pattern) Image from https://www.jaegertracing.io/docs/1.17/architecture/

Slide 13

Slide 13 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● Pattern: Distributed tracing ○ https://microservices.io/patterns/observability/distribute d-tracing.html ● W3C Trace context ○ https://www.w3.org/TR/trace-context/ 13 分散トレース(Distributed tracing pattern)

Slide 14

Slide 14 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● SaaSを使う ○ New Relic, Datadog etc ● OSSを組み合わせる ○ OpenTelemetry/OpenCensus, Jeager, Istio etc ● クラウドベンダーの仕組みに乗っかる ○ AWS X-Ray, GCP Cloud trace etc ● それなりに仰々しい追加・変更が必要になる 14 分散トレースの実現方法

Slide 15

Slide 15 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ゆるくふわっと始めてみる 15

Slide 16

Slide 16 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● (現時点では)そこまで困っていなかった ○ 1ヶ月に1回あると楽だなと思うくらい ○ パフォーマンス面でとくに問題ない ● 他のOKRタスクの片手間でやれるくらいでやりたかった ○ 追加コストを払ってまではやりたくない ○ インフラ構成の追加・変更してまでやりたくない ○ 正式に導入するときに容易に廃棄可能であってほしい 16 そんなにガッツリやりたくなかった

Slide 17

Slide 17 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● ログ分析やエラーレポートは既存の基盤をそのまま使う ○ 各サービスごとにKibanaやCWLを確認する現状は維持 ● リクエストIDを付与することでログとエラーの関連性を可視化 ● ドリルダウンみたいなリッチな可視化は今回は諦める 17 ゆるくふわっと始める分散トレース

Slide 18

Slide 18 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ゆるふわ分散トレースの方針 1 2 3 リクエストからIDを取り出す IDをサービス全体に伝播させる IDをログやエラーに埋め込む 18

Slide 19

Slide 19 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. サービス間で リクエストIDをやりとりする 19

Slide 20

Slide 20 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 20 リクエストIDでログ同士、エラーの関連性を可視化 リクエストID生成 with ID with ID with ID with ID with ID ● リクエストごとに各ログ出力、エラーレポートが一意なIDを内包 with ID

Slide 21

Slide 21 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 21 ログやエラーにリクエストIDを伝播させる ● 操作の起点でリクエストIDを生成する ○ PHPからGoに送信するリクエストにリクエストIDを付与 ● GoはPHPからもらったリクエストIDをPythonに送信する ● Go/Pythonサービス内でリクエストIDを伝播するようにする ● ログやエラーレポートにリクエストIDをいれる

Slide 22

Slide 22 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ここでちょっと問題 レイヤードアーキテクチャでは リクエストヘッダーにアクセスできる箇所は限られる 22

Slide 23

Slide 23 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● BANKのサービスはレイヤードアーキテクチャ構成になっている ○ GoでのAPI開発現場のアーキテクチャ実装事例(Pythonもほぼ同じ) ■ https://speakerdeck.com/hgsgtk/go-api-architecture-practical-example 23 レイヤードアーキテクチャ内でリクエストIDを使う

Slide 24

Slide 24 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● コントローラ層以外でHTTPリクエストは参照できない ● ドメイン層やサービス層でもリクエストIDを参照したい ○ すべての関数や引数にリクエストIDを直接含めるのは嫌 24 レイヤードアーキテクチャ内でリクエストIDを使う

Slide 25

Slide 25 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. Context pattern 25

Slide 26

Slide 26 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 26 Context pattern ● 特定の条件下に閉じた情報を透過的にやりとりするパターン ○ Go(1.7~)やPython(3.7~)で標準で提供されている ■ https://golang.org/pkg/context/ ■ https://docs.python.org/ja/3/library/contextvars.html ○ J2EE、AndroidやWPF(C#)でもあるパターン ■ https://docs.oracle.com/javase/jp/8/docs/api/org/omg/CORBA/Context.html ■ https://developer.android.com/reference/android/content/Context.html ■ https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.frameworkelement.datacontext ○ Stateパターンと似ているが、「状態」だけではない

Slide 27

Slide 27 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. GoでContextを使う 27

Slide 28

Slide 28 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● 透過的に値をやり取りするときにつかう ○ キャンセルやタイムアウトを伝播させるときにも使われる ● 関数やメソッドの第一引数にcontext.Contextを含める ○ [Go] context.TODO()を使って漸進的にcontext対応を始める ■ https://budougumi0617.github.io/2020/02/21/use-context/ 28 GoでContextを使う

Slide 29

Slide 29 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● MiddlewareでcontextにリクエストIDを注入しておく ○ Middlewareはハンドラーに対する共通の前処理 29 GoでContextを使う

Slide 30

Slide 30 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● ロギングやエラーレポート送信時にcontextからリクエストIDを 取り出す ● 他サービス呼び出し時にはcontextから取り出してHTTPヘッダー にリクエストIDを付与する ● アクセスログにもリクエストIDを付与する 30 GoでContextを使う

Slide 31

Slide 31 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● ロギングやエラーレポート送信時にcontextからリクエストIDを 取り出す 31 GoでContextを使う

Slide 32

Slide 32 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. Python(aiohttp)で Contextを使う 32

Slide 33

Slide 33 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● Middleware(ハンドラーに対する共通の前処理)でcontextにリ クエストIDを注入しておく ○ [Python] aiohttpでリクエストスコープのコンテキスト情報を扱う ■ https://budougumi0617.github.io/2020/04/08/python-use-context-var-in-aiohttp/ 33 Python(aiohttp)でContextを使う

Slide 34

Slide 34 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● Middleware(ハンドラーに対する共通の前処理)でcontextにリ クエストIDを注入しておく 34 Python(aiohttp)でContextを使う

Slide 35

Slide 35 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● ロギングやエラーレポート送信時にcontextからリクエストIDを 取り出す 35 Python(aiohttp)でContextを使う

Slide 36

Slide 36 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● アクセスログにもリクエストIDを付与する ○ [Python] aiohttpで独自形式のアクセスログを出力する ■ https://budougumi0617.github.io/2020/04/11/python-access-log-in-aiohttp/ 36 Python(aiohttp)でContextを使う

Slide 37

Slide 37 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 37 リクエストIDでログ同士、エラーの関連性を可視化 リクエストID生成 with ID with ID with ID with ID with ID ● アプリケーションコードの変更のみでIDを付与するようにした with ID

Slide 38

Slide 38 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● 通知されたエラーレポートのリクエストIDを確認する 38 ゆるふわ分散トレース実装後

Slide 39

Slide 39 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ● KibanaやCloud Watch LogsでリクエストIDを検索する 39 ゆるふわ分散トレース実装後

Slide 40

Slide 40 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 40 ゆるふわ分散トレース実装後 ● IDを検索するだけで関連ログが探せるようになった! Before After

Slide 41

Slide 41 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. ログやエラーの関連性を 可視化できた kibanaやCWLでIDを検索するだけで 関連ログが探せるようになった! 41

Slide 42

Slide 42 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 42 ● 複数サービスでシステムを構成したときに生じる悩みを共有する ● 分散トレースについてざっくり知ってもらう ● インフラ構成の変更、追加予算なしで始める方法の紹介 ● リクエストIDを付けるだけでも解析が便利になることを共有する 今日のゴール

Slide 43

Slide 43 text

© 2012-2019 BASE, Inc. © 2012-2020 BASE, Inc. 43 ● 分散トレースをしたくなるときを説明 ● 分散トレースの概要を説明 ● GoやPythonでどうやってリクエストIDを引き回すか解説 ● インフラ構成やランニングコストを変えずにログやエラーを追跡 できるようになった ● 複数言語で類似処理を実装すると言語差異を感じられて楽しい まとめ