OpenTelemetry デモアプリケーションを使って Mackerel のメトリックエクスプローラーを体験しよう

OpenTelemetry デモアプリケーションとは、現実世界に近い環境での OpenTelemetry の実装を示すことを目的としたマイクロサービスベースの分散システムです。様々な言語での SDK による計装があらかじめ実装されており、すぐに OpenTelemetry のトレースとメトリックを試すことができます。

github.com

この記事では OpenTelemetry デモアプリケーションによるメトリックを Mackerel に送信し、メトリックエクスプローラーを用いた障害が発生した際のシナリオを体験してみます。

注:この記事は、2024年6月5日に開催した「オブザーバビリティ再入門 - 大切さと高め方を知ろう!」の id:azukiazusa のトーク内容となります。記事中で紹介しているMackerelのメトリックエクスプローラー機能および画面は開発中のものであり、ユーザーの皆さまにご利用いただけるようになるまで、いましばらくお待ちください。

トークの動画もございますので、ぜひ下記記事や動画のアーカイブもご覧ください。当該トークは55分57秒からとなっています。

mackerel.io

OpenTelemetry デモアプリケーションのセットアップ

まずは OpenTelemetry デモアプリケーションのセットアップを行います。OpenTelemetry は Docker または Kubernetes でのセットアップが可能です。今回は Docker を使用します。

なお、アプリケーション用におよそ 6GB のメモリが必要であることに注意してください。

はじめにデモレポジトリをクローンします。

git clone https://github.com/open-telemetry/opentelemetry-demo.git

make コマンドを実行すると、Docker イメージがビルドされ、デモアプリケーションが起動します。

make start

ビルドが完了したら、http://localhost:8080 にアクセスするとデモアプリケーションの画面が表示されます。

Mackerel へのメトリック送信

次に、OpenTelemetry デモアプリケーションから Mackerel へメトリックを送信する設定を行います。デモアプリケーションは OpenTelemetry Collector を使用してメトリックを送信する構成となっています。そのためアプリケーションのコードに変更を加えることなく、OpenTelemetry Collector の設定ファイルの exporters に Mackerel 向けの設定を追加するだけで簡単にメトリックを送信できます。

src/otelcollector/otelcol-config.yml ファイルを編集し以下の設定を追加します。

  receivers:
    otlp:
      protocols:
        grpc:
        http:
          cors:
            allowed_origins:
              - "http://*"
              - "https://*"
    httpcheck/frontendproxy:
      targets:
        - endpoint: http://frontendproxy:${env:ENVOY_PORT}

  exporters:
    otlp:
      endpoint: "jaeger:4317"
      tls:
        insecure: true
    otlphttp/prometheus:
      endpoint: "http://prometheus:9090/api/v1/otlp"
      tls:
        insecure: true
    opensearch:
      logs_index: otel
      http:
        endpoint: "http://opensearch:9200"
        tls:
          insecure: true
+   otlp/mackerel:
+     endpoint: otlp.mackerelio.com:4317
+     compression: gzip
+     headers:
+       Mackerel-Api-Key: ${env:MACKEREL_API_KEY}

  processors:
    batch:

  connectors:
    spanmetrics:

  service:
    pipelines:
      traces:
        receivers: [otlp]
        processors: [batch]
        exporters: [otlp, debug, spanmetrics]
      metrics:
        receivers: [httpcheck/frontendproxy, otlp, spanmetrics]
        processors: [batch]
-       exporters: [otlphttp/prometheus, debug]        
+       exporters: [otlp/mackerel, otlphttp/prometheus, debug]
      logs:
        receivers: [otlp]
        processors: [batch]
        exporters: [opensearch, debug]

メトリックが Mackerel に投稿されるまでのデータフローの概要を見てみましょう。OpenTelemetry デモアプリケーションは Java, Node.js, Python などの様々な言語で書かれた複数のサービスから構成されています。それぞれのサービスは OpenTelemetry SDK を使用してメトリック・トレースを計装し、OpenTelemetry Collector に送信します。OpenTelemetry Collector は受信したメトリックを Mackerel に送信するためのエクスポーターを使用して Mackerel に送信します。

https://opentelemetry.io/docs/demo/collector-data-flow-dashboard/ より引用

トレースとして OpenTelemetry Collector に送信されたデータは Span Metrics Connector によってメトリックに変換され、Mackerel に送信されます。Connector はエクスポーターとレシーバー両方の役割を持ち、異なるテレメトリーパイプラインを接続するために使用されます。

MACKEREL_API_KEY には Mackerel の API キーを設定します。Mackerel の API キーは https://mackerel.io/my?tab=apikeys から取得できます。API キーには Read & Write 権限が必要です。

.env ファイルに Mackerel のダッシュボードから取得した API キーを設定します。

MACKEREL_API_KEY=<YOUR_API_KEY>

docker-compose.yml ファイルの otel-col サービスを編集し、MACKEREL_API_KEY を環境変数として設定します。

  # OpenTelemetry Collector
  otelcol:
    image: ${COLLECTOR_CONTRIB_IMAGE}
    container_name: otel-col
    deploy:
      resources:
        limits:
          memory: 200M
    restart: unless-stopped
    command: [ "--config=/etc/otelcol-config.yml", "--config=/etc/otelcol-config-extras.yml" ]
    volumes:
      - ./src/otelcollector/otelcol-config.yml:/etc/otelcol-config.yml
      - ./src/otelcollector/otelcol-config-extras.yml:/etc/otelcol-config-extras.yml
    ports:
      - "${OTEL_COLLECTOR_PORT_GRPC}"
      - "${OTEL_COLLECTOR_PORT_HTTP}"
    depends_on:
      - jaeger
    logging: *logging
    environment:
      - ENVOY_PORT
+     - MACKEREL_API_KEY

設定が完了したら、デモアプリケーションを再起動しておきましょう。

docker compose down
make start

Mackerel でメトリックを確認する

デモアプリケーションでショッピングカートに商品を追加したり、購入したりといった操作を行ってみましょう。しばらくすると Mackerel にメトリックが送信されているはずです。送信されたメトリックはメトリックエクスプローラー画面で確認できます。ただしくメトリックが送信されていれば、それぞれのマイクロサービスに対応するサービス名の一覧が表示されます。

メトリックエクスプローラー画面は現在開発中の機能であり、今後変更される可能性があります。

もしメトリックが送信されていない場合には、OpenTelemetry Collector のログを確認してみましょう。docker-compose logs otelcol でログを確認できます。

例えば Mackerel の API キーが正しく設定されていない場合には、以下のようなエラーメッセージが表示されます。

otel-col  | YYYY-MM-DDT00:00:00.000Z error   exporterhelper/queue_sender.go:101      Exporting failed. Dropping data.    {"kind": "exporter", "data_type": "metrics", "name": "otlp/mackerel", "error": "not retryable error: Permanent error: rpc error: code = PermissionDenied desc = authenticate error, please check mackerel-api-key", "dropped_items": 27}

メトリックエクスプローラー画面に戻ります。frontend サービスを選択していくつかのメトリックを眺めてみましょう。frontend サービスで計装されているメトリックはチェックボックスのリストで表示されます。チェックボックスを選択すると、そのメトリック対応するグラフの表示非表示を切り替えることができます。

画面を下にスクロールすると、duration.p95, duration.p99, duration.p50 といったグラフが表示されています。これらはそれぞれ、リクエストの 95 パーセンタイル、99 パーセンタイル、50 パーセンタイルのレイテンシを示しています。Mackerel では histogram データ形式のメトリックが投稿された場合、以下の代表値に変換され保存されます。

  • p99
  • p95
  • p90
  • count
  • sum
  • max
  • min

ラベルによるフィルタリング

さらに絞り込まれた情報を確認するために、ラベルによるフィルタリングを行うこともできます。例えばエラーが発生しているかどうかを確認するためには、ラベルのキーとして status を、値として 500 を指定します。

app.frontend.requests メトリックのグラフを見ると、500 エラーを返しているリクエストのグラフが表示されます。

app.frontend.requests メトリックは累積値であるため、時刻とともに増加していくグラフが表示されています。どのタイミングでエラーが発生したのか差分値で確認したいことでしょう。グラフの右上に表示されている 差分値で表示するボタンを ON にすることでグラフを差分値に変更できます。

監視ルールの設定

続いてこのグラフを元に監視ルールを設定してみましょう。三点リーダーからメニューを開いて「監視ルールを作成する」をクリックすると、監視ルールの設定画面が表示されます。監視ルールのクエリが自動的に設定されているため、すぐに監視ルールを作成できます。

追加の設定としてしきい値と監視ルール名を入力します。監視ルール名にはラベルのテンプレート構文を利用できます。テンプレート構文は {{}} で囲まれた部分にメトリックのラベルのキーを指定することで、アラートが発生した際のラベルの値を監視ルール名に埋め込むことができます。

例えば、監視ルール名を以下のように設定します。

app.frontend.requests [{{method}}] {{target}}

このとき、http.request.method=GET、http.route=/api/v1/users のラベルを持つメトリックに対してアラートが発生した場合、監視ルール名は以下のようになり、アラート通知に表示されます。

app.frontend.requests [GET] /api/recommendations

この機能を利用することで、どのメトリックでアラートが発生したのか瞬時に把握できます。

障害が発生した際のシナリオを再現する

最後に、障害が発生した際のシナリオを再現してみましょう。OpenTelemetry デモアプリケーションでは、フィーチャーフラグによって意図的に特定のコンポーネントの障害を発生させることができます。フィーチャーフラグの一覧は以下の URL から確認できます。

opentelemetry.io

フラグを有効にするためには src/flagd/demo.flagd.json ファイルを編集し、有効にしたいフラグ名の defaultVarianton に設定します。

  {
    "$schema": "https://flagd.dev/schema/v0/flags.json",
    "flags": {
        "recommendationServiceCacheFailure": {
        "description": "Fail recommendation service cache",
        "state": "ENABLED",
        "variants": {
          "on": true,
          "off": false
        },
-        "defaultVariant": "off"
+        "defaultVariant": "on"
      },
    }
  }

ここでは recommendationServiceCacheFailure フラグを有効にしています。これにより商品のレコメンド機能のメモリリークが発生し、一定の確率でリクエストがタイムアウトするようになります。デモアプリケーションをしばらく操作すると、Mackerel のアラートが発生するはずです。

監視ルール名より、api/recommendations への GET リクエストで 500 エラーが発生していることがわかります。

この結果からどうやら商品のレコメンド機能機能を提供している recommendations サービスに障害でよくないことが発生していることが予測できます。メトリックエクスプローラー画面を使って、recommendations サービスのメトリックを確認してみましょう。

メトリックエクスプローラー画面のサービスの一覧から recommendationservice 選択します。

グラフを確認すると、system.cpu.utilization{service.name="recommendationservice"}process.runtime.cpython.memory{service.name="recommendationservice"} のメトリックが途切れていることが確認できます。

これらの現象が障害の原因であることが予測されます。フロントエンドのリクエストで 500 エラーが発生し始めた時間と照らし合わせて確認してみましょう。system.cpu.utilization{service.name="recommendationservice"}process.runtime.cpython.memory{service.name="recommendationservice"} のグラフの左上にある「グラフを保持」アイコンを ON にすることで、メトリックの検索条件が変更されてもグラフが表示され続けられるようになります。グラフを保持した状態で、サービスを frontend に戻して app.frontend.requests メトリックを確認します。

app.frontend.requests メトリックのグラフを見ると、500 エラーが発生し始めた時間と recommendationservice のメトリックが途切れている時間が一致していることがわかります。これにより、recommendationservice に何かしらの問題が発生しているところまで絞り込むことができました。

まとめ

  • OpenTelemetry デモアプリケーションとは、現実世界に近い環境での OpenTelemetry の実装を示すことを目的としたマイクロサービスベースの分散システム
  • OpenTelemetry Collector の設定に Mackerel のエクスポーターを追加することで、メトリックを Mackerel に送信できる
  • Mackerel のメトリックエクスプローラー画面ではサービス一覧が表示され、サービスを選択することでメトリックを確認できる
  • メトリックのラベルによるフィルタリングやグラフの差分値表示を使って、メトリックの詳細を確認できる
  • OpenTelemetry デモアプリケーションのフィーチャーフラグを有効にすることで、障害が発生した際のシナリオを再現できる
  • グラフ保持機能を使って、複数のメトリックのグラフを比較することで障害の原因を特定できる