こんにちは、QualiArtsでサーバー側を担当している曹(ジョ)と申します。
最近、リリースした課金基盤のプロキシにStackdriver Traceというものを導入してみましたので、紹介してみたいと思います。
皆さんは受け取ったリクエストが中でどういう動きをしてどれぐらいの時間がかかっているのか気になったことはありませんか?予想はできるものの実際の動きはlogを一つ一つ入れない限り見えないと思います。
特にマイクロサービスが多く導入されていて、レスポンスが遅い場合、マイクロサービスの個々の動きを把握するのが難しいのでボトルネックを探すのも面倒だと思います。
それで導入を検討したのがStackdriver Traceです。
Stackdriver Traceについて
Stackdriver Traceですが、Google Cloud Platform(以下GCP)上で利用できるサービスで、簡単に使用できる分散トレースシステムです。
特徴としては
- パフォーマンスボトルネックの検出
- 分析レポートによる問題の迅速かつ自動的な検出
- 幅広い言語のサポート
になります。
このように便利なStackdriver Traceですが、このプロダクトはOpenCensusというオープンソースプロジェクトを基盤にしているので、まずそれについて説明したいと思います。
OpenCensusについて
OpenCensusはGoogleが開発した分散トレース収集ツールです。オープンソースで、今もGoogleが主導して開発しています。手軽にリクエストの軌跡を把握できる凄く便利なものです。
OpenCensusの概要
下記はOpenCensusの紹介ページから抜粋した内容です。
OpenCensus makes getting critical telemetry out of your services easy and seamless. OpenCensus currently provides libraries for a number of languages that allow you to capture, manipulate, and export metrics and distributed traces to the backend(s) of your choice. OpenCensus works great with all software systems, from client applications, large monoliths, or highly-distributed microservices. OpenCensus started at Google but is now developed by a broad community of service developers, cloud vendors, and community contributors. OpenCensus isn’t tied to any particular vendor’s backend or analysis system.
OpenCensusはサービスの重要な遠隔測定を途切れなく簡単にすることが可能です。OpenCensusは選択したバックエンドに対する分散トレースとメトリックのエクスポート、キャプチャーを処理する多数の言語ライブラリーを提供しています。OpenCensusはクライアントアプリケーション、大きいモノリスまたは高度な分散マイクロシステムなどの素晴らしい全てのソフトウェアシステムに動作します。OpenCensusはGoogleで始まりましたが、現在はコミュニティ コンストリビューター、クラウドベンダとサービス開発者の幅広いコミュニティによって開発されています。OpenCensusは特定のベンダーまたは分析システムに縛られることはありません。
OpenCensusの特徴
そのOpenCensusの特徴を簡単に並べますと
- Context Propagation
- 分散トレース収集
- 時系列でのメトリクス収集
- 低コスト
- 多数の種類の言語のサポート
などがあります。他、OpenCensusの特徴の詳細についてはこちらでご確認することが可能です。
主な機能は下記のものがあります。
今回はTracingをメインとして導入しました。
Tracing
Trace
ここまで提供している機能について把握できたと思うので、サポートしている言語とExporterについて調べてみましょう。
サポートしている言語とExporter
OpenCensusは多様な言語とExporterをサポートしています。
サポート言語
Go | Beta | https://godoc.org/go.opencensus.io |
Java | Beta | https://www.javadoc.io/doc/io.opencensus/opencensus-api/ |
C# | Alpha | https://github.com/census-instrumentation/opencensus-csharp/ |
C++ | Beta | https://github.com/census-instrumentation/opencensus-cpp |
Node.js | Alpha | https://github.com/census-instrumentation/opencensus-node |
Ruby | Pre-Alpha | https://www.rubydoc.info/gems/opencensus |
Erlang/Elixir | Beta | https://hexdocs.pm/opencensus/ |
Python | Beta | https://census-instrumentation.github.io/opencensus-python/trace/api/index.html |
PHP | Pre-Alpha | https://packagist.org/packages/opencensus/opencensus |
サポートExporter
Node.js
- Stackdriver (Stats)
- Stackdriver (Tracing)
- Instana (Tracing)
- Jaeger (Tracing)
- Prometheus (Stats)
- Zipkin (Tracing)
Python
GoLang
- OpenCensus Agent
- Azure Monitor
- Honeycomb.io (Tracing)
- AWS X-Ray (Tracing)
- Datadog (Stats and Tracing)
- Jaeger (Tracing)
- Prometheus (Stats)
- Stackdriver (Stats and Tracing)
- Zipkin (Tracing)
Java
このように多様な言語とプラットフォームをサポートしているので、GCP以外のプラットフォームでも十分利用できると思います。OpenCensusの紹介はここまでで、次に実際Stackdriver Trace導入と活用について移ります。
導入実績と活用方法の紹介
では、実際にQualiArtsの課金基盤のプロキシで導入した実績とその活用方法について紹介致します。
なぜ、導入したのか?
Google Cloud Next 2018で製品の紹介を見た瞬間、これは導入すべきだと直感で思いました。
その理由は二つとなります。
- UIが直観的で非常に見やすい
- 複数のサービスを利用する場合ボトルネックがわかる
特に後者の理由ですが、課金基盤は内部の別のサービスに依存しているので、その通信内容を可視化したかったです。
導入開始!
導入を決めたので、早速導入するために準備を始めましたが、何も情報がないのでとりあえず、本家のOpenCensusサイトを参照しました。
そして、上記で述べたように重点的に導入した機能はTracingになります。
システム構成について
まず、導入について説明する前に課金基盤がどういう構成なのか確認してみましょう。
課金基盤は下記の構成になっております。
- ゲームサービス(Game Service): 課金基盤のプロキシにリクエストをを送り、必要な情報を受け取ります。
- プロキシAPI(Proxy API):外部APIの実行を代行するプロキシAPIになります。GoLangで作成しました。ゲームサービスが必要な作業を纏めて代行してくれれます。
- 行動ログAPI(Action Log API):課金API実行のとき、分析で必要な行動ログを記録する内部APIになります。
- 外部API (External API):実際の課金処理を行うAPIになります。
- 基本HTTPS通信ですが、GKE内部だけGRPC通信を行います。
ここでTracingしたい部分を整理してみました。
ゲームサービスから実行されるのが親で外部APIと内部APIの実行は子供になります。
Spanで表すとこんな感じですね。
どころでガイドラインを参照しながら実際導入したところ、下記のように表示されました。
SpanがParentのみ表示されましたが、自分が望んでたのはこれではなく、親と子供のSpanが表示されるものなので、色々と調べると子供のSpanを作るためにはParentからのChild Spanを作る必要があったということでした。
_, span := trace.StartSpanWithRemoteParent(request.Context(), request.URL.String(), spanCtx) defer span.End()
これで下記のようにParent Spanの下にChild Spanが表示するようになりました!
ここまでできて、全体のレスポンスとサービス間のレイテンシを測定するのはよかったのですが、
これをもっと活用できないかと悩み、活用方法を探しました。
それでいくつか探した活用方法あったので紹介したいと思います。
活用方法1:Attributeの活用(Requestの情報を豊かに!)
このOpenCensusの特徴は一つのRequestに対してAttributeをセットすることで、色んな情報を出力することができます。
例えば、headerの情報とか、requestのbodyの情報とかあと調査で必要情報などなど
実際導入するコードはこんな感じです。
uuID, _ := uuid.NewRandom() c.SetRequest(c.Request().WithContext(context.WithValue(c.Request().Context(), CtxKeyRequestID{}, uuID.String()))) requestURL := c.Request().Host + c.Request().URL.String() ctx, span := trace.StartSpan(c.Request().Context(), requestURL) span.AddAttributes(trace.StringAttribute("path", c.Request().URL.Path), trace.StringAttribute("host", c.Request().Host), trace.StringAttribute("user_id", c.Request().Header.Get("userId")), trace.StringAttribute("platform", c.Request().Header.Get("platform")), trace.Int64Attribute("res_status", int64(c.Response().Status)), trace.Int64Attribute("res_size", int64(c.Response().Size)), trace.StringAttribute("req_body", string(reqBody)), trace.StringAttribute("res_body", string(resBody)), trace.StringAttribute("env", c.Request().Header.Get("Env")), trace.StringAttribute("request_id", c.Request().Context().Value(CtxKeyRequestID{}).(string)), )
親のAttribute情報
子供のAttribute情報
こういう風に情報を入れることであとで何が起きたか一目で把握することができます。
今までだと何が問題が起きた時にStackDriver Loggingを確認して調査するのが非常に辛かったのですが、
これを導入することで調査が凄く楽になりました。
ここからはGCPを導入していることを限定としての話になりますが、
MetricsとFilteringの機能がよかったです。
活用方法2:Metricsの活用(一目でわかるリクエスト分布)
このMetricsを見ると平均レイテンシーと平均から外れてるレイテンシーの分布を一目でわかることができます。そして、そのリクエストを選択して詳細の内容も確認することができます。
活用方法3:Filterの活用
最後Filter機能ですが、特定条件を入れることで検索したいrequestをすぐ見つかることができます。
この機能を使うことで調査する時間が導入前に比べ100倍早くなりました。
これで活用方法の説明は以上になりますが、もっと使いたい&便利な機能がたくさんあるので、見つけたら別の記事として紹介したいと思います。
まとめ
Stackdriver Trace(OpenCensus)はクラスターとマイクロサービス時代で必須と言えるぐらい分析と調査で便利な機能を持っています。この場で紹介できなかった機能もいっぱいあるので、ぜひ導入を検討して見てくださいー。
参考サイト
- OpenCensus 本家サイト:https://opencensus.io/
- GCP Stackdriver Trace : https://cloud.google.com/trace/?hl=ja