{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": { "slideshow": { "slide_type": "notes" } }, "outputs": [], "source": [ "from IPython.display import HTML # slide内で埋め込みが出来るように" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Akkaを分散トレーシングで見てみよう\n", "\n", "[@grimrose](https://twitter.com/grimrose) \n", "\n", "@[Scala関西 Summit2018](https://2018.scala-kansai.org/session/#grimrose)\n", "\n", "2018-11-10" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 今日話すこと\n", "\n", "マイクロサービス化されたアプリケーションでは、パフォーマンス測定の一つとして分散トレーシングが挙げられます。 \n", "\n", "Akka HTTPをAPIサーバの一つとして構築した際に、他のサービスとのやり取りを含め全体のパフォーマンスを可視化するには、分散トレーシングの仕組みに載せる必要が出てきます。 \n", "\n", "そこで、数ある分散トレーシングの実装の中から、MetricsとTracingの実装の一つである[OpenCensus](https://opencensus.io)と、 OpenCensusが利用できる分散トレーシングのバックエンドの一つである[Jaeger](https://www.jaegertracing.io/)を用いて、 Akka HTTPのAPIサーバでの分散トレーシングの可視化を紹介します。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## お前、誰よ" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### お前、誰よ\n", "\n", "よしだ\n", "\n", "* twitter: [@grimrose](https://twitter.com/grimrose)\n", "* github: [grimrose](https://github.com/grimrose)\n", "* とある人材紹介会社\n", " * マーケティング部門のデータエンジニア(自称)\n", "* 好きなIDE: IntelliJ IDEA\n", "* Scala歴: 3年(2015~)\n", "* [ScalaMatsuri](scalamatsuri.org) 2016, 2017, 2018, 2019 スタッフ" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 普段の仕事\n", "\n", "#### 設計から運用\n", "\n", "* 事業KPIの可視化を行うためのWebアプリケーション\n", "* Scalaを使った日次や月次の集計バッチを実行するアプリケーション\n", "* 帳票と呼ばれるExcelや外部APIなどからデータベースへデータを投入するツール\n", "* 部門の日常業務を改善するためのちょっとしたツール\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 普段の仕事\n", "\n", "#### その他\n", "\n", "* 先述のアプリケーションをAWSで運用する基盤の構築" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 今回のテーマ\n", "\n", "**Akkaで作られたアプリケーションの監視の必要に迫られた人**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 背景\n", "\n", "**どの処理にどれくらい時間がかかっているかを知りたい。**\n", "\n", "* 本番環境はコンテナで動かしているので、SSHで入ってログファイルをtailしてなんてのは無理。\n", "* ログには出力しているが、整理しながら見るにはシェル芸や超絶技巧検索スキルを駆使する必要がある。\n", "* 時系列で可視化しておいて、後で見たい。また、自分以外が見られるようにしたい。\n", "* 他のHTTPサービスとやり取りしてると、どこがボトルネックなのか分かりづらい。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## そこで\n", "\n", "分散トレーシングで可視化しよう" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 分散トレーシングについて" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "scrolled": false, "slideshow": { "slide_type": "slide" } }, "outputs": [ { "data": { "text/html": [ "
分散トレーシング技術について(Open tracingやjaeger) from NTT Communications Technology Development
" ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('
分散トレーシング技術について(Open tracingやjaeger) from NTT Communications Technology Development
')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 分散トレーシングについて\n", "\n", "> * Tracing\n", "> * Span全体のStartからFinishまでを含むSpanの集合体\n", "> * 各Spanの間には関係性があり、有効巡回グラフ(DAG)で表すことができる。\n", "> * Span\n", "> * 一つのサービス(境界)内の処理\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### JVMで使う場合\n", "\n", "他にもあるが一例として、以下のプロダクトが挙げられる。\n", "\n", "* [Datadog](https://www.datadoghq.com)\n", "* [Elastic](https://www.elastic.co/solutions/apm)\n", "* [AWS X-Ray](https://aws.amazon.com/jp/xray/)\n", "* [Kamon](https://kamon.io)\n", "* [Zipkin](https://zipkin.io)\n", "* [Jaeger](https://www.jaegertracing.io)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Zipkinについて\n", "\n", "https://zipkin.io/\n", "\n", "Twitterが[Google Dapper](http://research.google.com/pubs/pub36356.html)を参考に開発した分散トレーシングシステム" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Zipkinについて\n", "\n", "https://speakerdeck.com/shakuzen/zipkin-meetup-number-1-zipkintofen-san-toresingufalseshao-jie\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## OpenTracingについて" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### OpenTracingとは\n", "\n", "https://opentracing.io\n", "\n", "> Vendor-neutral APIs and instrumentation for distributed tracing\n", "\n", "[仕様](https://github.com/opentracing/specification)を統一し、実装は各プロダクトのものを採用できるように。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### OpenTracingとは\n", "\n", "CNCF(Cloud Native Computing Foundation)の管理下にあるプロジェクトのひとつ。\n", "\n", "https://landscape.cncf.io\n", "\n", "Category: Observability and Analysis - Tracing\n", "\n", "同じカテゴリに[Jaeger](https://www.jaegertracing.io/)が存在。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### OpenTracingとは\n", "\n", "CNCFの他のプロジェクトとの関わりは、TrailMapを参照。\n", "\n", "https://github.com/cncf/landscape#trail-map\n", "\n", "TrailMapについては、[Japan Container Days、CNCFのCTOが語るクラウドネイティブへの道](https://thinkit.co.jp/article/14089)を参照。 " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### OpenTracingに対応したTracerライブラリ\n", "\n", "https://opentracing.io/docs/supported-tracers/\n", "\n", "ここのリストに挙げられているもの以外にも、プロダクトでサポートしているものは、以下のが挙げられる。\n", "\n", "* [Zipkin](https://github.com/openzipkin-contrib/brave-opentracing)\n", "* [Elastic](https://www.elastic.co/guide/en/apm/agent/java/current/index.html)\n", "\n", "その他にもContributeされているものが、こちらのレポジトリ\n", "* https://github.com/opentracing-contrib\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Jaegerについて" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Jaegerについて\n", "\n", "数ある実装からJaegerを選んだ理由\n", "\n", "* CNCFのプロジェクトである。\n", "* ロゴがかわいい。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "![logo](https://www.jaegertracing.io/img/jaeger-logo.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Jaegerについて\n", "\n", "現在の最新versionは **1.7**\n", "\n", "https://www.jaegertracing.io/docs/1.7/features/\n", "\n", "* High Scalability\n", "* Native support for OpenTracing\n", "* Multiple storage backends\n", "* Modern Web UI\n", "* Cloud Native Deployment\n", "* Observability\n", "* Backwards compatibility with Zipkin\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Jaegerについて\n", "\n", "アーキテクチャは、主に以下のコンポーネントで構成されている。\n", "\n", "* jaeger-agent\n", "* jaeger-collector\n", "* jaeger-query\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "> from https://www.jaegertracing.io/docs/1.7/architecture/\n", "\n", "![img](https://www.jaegertracing.io/img/architecture.png)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Jaegerについて\n", "\n", "開発や検証だけなら、all-in-oneなdocker imageが利用可能。\n", "\n", "```sh\n", "$ docker run -d --name jaeger \\\n", " -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \\\n", " -p 5775:5775/udp \\\n", " -p 6831:6831/udp \\\n", " -p 6832:6832/udp \\\n", " -p 5778:5778 \\\n", " -p 16686:16686 \\\n", " -p 14268:14268 \\\n", " -p 9411:9411 \\\n", " jaegertracing/all-in-one:1.7\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Jaegerについて\n", "\n", "本番向けとして、k8sのmanifestが公開されている。\n", "\n", "[jaegertracing/jaeger-kubernetes](https://github.com/jaegertracing/jaeger-kubernetes)\n", "\n", "更に[Helm](https://helm.sh)のChartも[公開](https://github.com/helm/charts/tree/master/incubator/jaeger)されているので、デプロイもHelmから可能。\n", "\n", "更にKubernetes Operatorも[用意](https://github.com/jaegertracing/jaeger-operator)されたので、更にデプロイが省力化されている。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 分散トレーシングについて\n", "\n", "ここまでのまとめ\n", "\n", "* 分散トレーシングは、TraceとSpanで構成されている。\n", "* OpenTracingという統一された仕様が存在する。\n", "* JaegerをTracerとして使うことでOpenTracingを利用できる。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## ここでの疑問" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "あれ? OpenTracing? OpenCensusじゃないの?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## OpenCensusについて" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### OpenCensusについて\n", "\n", "https://opencensus.io\n", "\n", "> OpenCensus is a vendor-agnostic single distribution of libraries to provide metrics collection and tracing for your services.\n", "\n", "ベンダー非依存なMetricsとTracing用のライブラリ" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### OpenCensusについて\n", "\n", "[仕様](https://github.com/census-instrumentation/opencensus-specs)\n", "\n", "* OpenTracingとは別物。\n", "* Observabilityの為のライブラリ。\n", " * つまり、metricsとtracesまとめて面倒を見るために。\n", "* Googleが作っている部分が多いが、OSSである。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### なぜ、OpenCensusか\n", "\n", "* 仕様と実装の分離\n", " * 各サービスのライブラリを使って書くのもいいが、統一した仕様のもとに書ける。\n", " * ロックインされることなく、切り替えまたは同時に利用出来る。\n", "* MetricsとTracingどちらも欲しい\n", " * Tracingだけでは、RuntimeやOSといった情報までは持っていない。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### なぜ、OpenCensusか\n", "\n", "Scalaの実装があったから -> [opencensus-scala](https://github.com/census-ecosystem/opencensus-scala)\n", "\n", "* [opencensus-java](https://github.com/census-instrumentation/opencensus-java)のScala wrapper\n", "* [Scalaの主要なHTTPライブラリをサポート](https://github.com/census-ecosystem/opencensus-scala#instrumentations)\n", " * Playは計画中…\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### OpenCensus-Scalaについて\n", "\n", "ちょっとした注意点\n", "\n", "* jaegerのtrace-exporterはjavaにあるものの、scalaではconfigが無い。\n", " * 出力属性がzipkinのB3フォーマットより少ない。\n", "* zipkinのexporterを使うことで、jaegerの[Zipkin compatibility API](https://www.jaegertracing.io/docs/1.7/getting-started/#migrating-from-zipkin)を利用可能。\n", " * 若干Scalaの`toString`そのままなのが気になる。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### OpenCensus-Scalaについて\n", "\n", "JaegerのZipkin compatibility APIとは。\n", "\n", "* [B3 propagation](https://github.com/openzipkin/b3-propagation)を要求されているので、jaegerのフォーマットではエラーとして扱われてしまう。\n", "* そこで、HTTP headerに以下のものを付与することで、トレーシングが可能に。\n", " * X-B3-TraceId\n", " * X-B3-ParentSpanId\n", " * X-B3-SpanId\n", " * X-B3-Sampled\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### OpenCensus-Scalaについて\n", "\n", "* `io.opencensus.scala.akka.http.TracingDirective` が用意されているので、Akka-HTTPで`io.opencensus.trace.Span` を使うのが簡単に。\n", "* `io.opencensus.scala.Tracing` が用意されているので、対応していないframeworkでも実装が可能。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### TracingIDについて\n", "\n", "Zipkin以外にも以下のようなHTTP headerがTracingに用いられている。\n", "\n", "* AWS ALB\n", " * X-Amzn-Trace-Id\n", "* GCP\n", " * X-Cloud-Trace-Context\n", "* Jaeger\n", " * uber-trace-id\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### TracingIDについて\n", "\n", "Q. 誰がこのIDを付与するのか?\n", "\n", "A. ロードバランサーやプロキシーが行う。\n", "\n", "特に以下のプロダクトが例として挙げられる。\n", "\n", "* [envoy](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/front_proxy)\n", "* [istio](https://istio.io/docs/tasks/telemetry/distributed-tracing/)\n", "* [nginx](https://github.com/opentracing-contrib/nginx-opentracing)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## では、実際にどんな感じなのか見てみましょう" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## デモ" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### デモアプリケーションについて\n", "\n", "メッセージを登録するAPIアプリケーション\n", "\n", "* メッセージのIDはID生成サービスから取得" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### デモアプリケーションについて\n", "\n", "![containers](img/containers.svg)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### メッセージ用のID生成について\n", "\n", "* [kayac/go-katsubushi](https://github.com/kayac/go-katsubushi)で順序のあるIDを生成。\n", " * [分散環境でユニークなidを発番するGo製プロダクト「katsubushi」のご紹介](https://techblog.kayac.com/katsubushi-introduction.html)\n", "\n", "* memcached プロトコルをAkka Streamで利用出来るように。\n", " * [j5ik2o/reactive-memcached](https://github.com/j5ik2o/reactive-memcached)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### ログについて\n", "\n", "dockerのlogging driverとしてfluentdを利用。\n", "\n", "* コンテナのログもdocker logging driverで取得。\n", "* fluentdから[fluent-plugin-elasticsearch](https://github.com/uken/fluent-plugin-elasticsearch)でelasticsearchへ。\n", "* ログの加工を楽にするひと手間として、json形式へ加工。\n", " * [logstash/logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder)を利用し、そのまま標準出力へ。\n", " * コンテナ以外は見やすい形式にするために、sbt-native-packager側で切り替え。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Metricsについて\n", "\n", "[Prometheus](https://prometheus.io/)をバックエンドにすることで、opencensusからMetricsを転送することが可能。\n", "\n", "(但し、opencensus-scalaではまだ計画中の段階)\n", "\n", "今回は、[opencensus-integrations/ocjdbc](https://github.com/opencensus-integrations/ocjdbc) を利用して、JDBCのMetricsを可視化。\n", "\n", "また、他のexporterと組み合わせることで、より詳細な監視が可能に。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 実演\n", "\n", "https://github.com/grimrose/scala-kansai-summit-2018" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## 今後" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 今後について\n", "\n", "* OpenCensusがサポートする言語、バックエンドがまだ少ないが徐々に増えていくと思われる。\n", "* opencensus-scalaのようにブリッジとなるライブラリが出来ていくことで、今のプロダクトへ導入することが進むと思われる。\n", " * 出来ればフレームワークが公式にサポートするとありがたい。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 今後について\n", "\n", "* 既にDatadogやZipkinを単体で使っているような場合でも、OpenCensusに切り替えることで、複数のバックエンドに転送が可能に。\n", " * 例えば、デプロイするときには、Stackdriver + Datadog、ローカルで開発するときは、Zipkinのコンテナみたいなのも可能。\n", " " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 今後について\n", "\n", "[Module for tagless-final & cats-effect](https://github.com/census-ecosystem/opencensus-scala/issues/31)\n", "\n", "* 関数の合成が出来るようになると、さらにいろいろと便利に。" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### 今後について\n", "\n", "OpenTracingとは別に、[OpenMetrics](https://openmetrics.io/) といったプロジェクトがCNCFで立ち上がっているので、こちらも同様に注視しておくと良いかも。\n", "\n", "* promertheusのようなテキスト形式のフォーマットや、Protocol Buffersのフォーマットを選択出来るようになっていくそう。\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## まとめ" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### まとめ\n", "\n", "* 分散トレーシングを織り込んで作ることで、ログだけでは分かりにくいことが見えるように。\n", "* OpenTracingやOpenCensusを利用することで、ロックインされることなく、複数のバックエンドを有効活用出来る。\n", "* Scalaだと言語のチカラで、より簡単に導入することが出来るように。" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0" } }, "nbformat": 4, "nbformat_minor": 2 }