🦌

OpenTelemetryでプロダクトのオブザーバビリティを向上させている話

に公開

この記事は2025 ZAICO アドベントカレンダーの14日目の記事です。

はじめに

ZAICOは在庫管理システムを提供し、お客様の日々の業務を支えています。安心して使い続けていただくためには、私たちがシステム内部の状態を外部から把握できるようにするオブザーバビリティを高めることは重要です。

今回、OpenTelemetryをプロダクトに導入し、トレースをMackerel APMを用いて可視化するところまで実施したので、その過程を共有したいと思います。

社内LTでも発表しており、noteに軽くまとめられているので、こちらもご参考ください。
https://note.com/zaico_support/n/nbd6eb33bb338

OpenTelemetry導入背景

弊社では過去にいくつかAPM(Application Performance Monitoring)を試されてきましたが、本格導入まで至らず、トレースの取得やAPMは未導入の状態でした。そのため、0→1でテレメトリ(特にトレース)を実装するにあたり、OSSであるOpenTelemetryは有力な選択肢となりました。

OpenTelemetryを採用することで、テレメトリ実装の知見を蓄積しながらオブザーバビリティの標準化を進められる点や目的や要件に応じてオブザーバビリティバックエンドを柔軟に切り替えられる点は大きなメリットでした。

APMの導入を検討していたタイミングで、OpenTelemetryを標準的にサポートするMackerel APMがリリースされ、コスト面・サポート面ともに要件に合致したため、オブザーバビリティバックエンドとして、Mackerel APMを採用することにしました。

導入にあたり、MackerelのCREの方にサポートいただきました。Mackerel APMだけでなく、OpenTelemetryについて相談に乗っていただけて大変心強かったです。以下はMackerel APMの正式リリース時の記事になります。
https://mackerel.io/ja/blog/entry/announcement/20250501

システム構成

弊社ではAmazon ECS Fargate上にRuby on Railsアプリケーションをデプロイしており、ECSサービスは複数のFargateタスクで構成されています。各タスクはオートスケーリングにより自動的に増減します。

アプリケーションはRuby on Railsで実装されているため、Ruby用のOpenTelemetry SDKで、トレースを実装しました。

ここからは、このRailsアプリケーションで収集したトレースをどのようにオブザーバビリティバックエンドへ送るかについて検討した内容を紹介します。

トレースの送信方法

トレースなどのテレメトリデータをオブザーバビリティバックエンドに送信する方法として、以下のパターンが考えられると思います。

  1. アプリケーションから直接送る方法(OpenTelemetry SDK -> オブザーバビリティバックエンド)
  2. アプリケーションからCollectorに集約して送信する方法(OpenTelemetry SDK -> OpenTelemetry Collector -> オブザーバビリティバックエンド)

1は追加コンポーネントが不要でシンプルに始められますが、OpenTelemetryの設定がアプリケーション側に閉じてしまい、設定変更のたびにアプリケーションを更新する必要があります。また後述しますが、柔軟なサンプリングには向いていません。

今回は、アプリケーションからOpenTelemetryの設定を切り離し、Collector側で柔軟に運用管理したかったため、2の「アプリケーションからCollectorに集約して送信する方法」を採用しています。

OpenTelemetry Collector構成

ECS Fargate上で、OpenTelemetry Collectorを配置するにあたり、以下のパターンが考えられると思います。

  1. OpenTelemetry Collectorをサイドカーとして配置する方式(アプリケーションと同じECSタスク内にCollectorを置く)
  2. OpenTelemetry Collectorをゲートウェイとして独立したサービスで配置する方式
    (Collectorを単独のECSサービスとして動かす)

1のサイドカー方式は構成がシンプルでタスク内で完結しますが、Collectorがタスクごとに分散するためトレースをサービス全体で集約できず、横断的なサンプリング制御が行えません。

また、タスク数に応じたCollectorのリソース確保が必要になる点や、設定変更のたびに全タスクの再デプロイが必要になる点も運用負荷となります。

これらのデメリットを踏まえ、トレース設定やサンプリング条件の調整を、メインアプリケーションのデプロイフローから切り離すため、2の「OpenTelemetry Collectorをゲートウェイとして独立したサービスで配置する方式」を採用しました。
これにより、アプリケーションのリリースとは独立してトレース設定の変更を反映できる構成としています。

サンプリング方式

トレースをすべて送信できるのが理想ですが、コストの観点からサンプリングが必要となりました。OpenTelemetryには、主にヘッドサンプリングとテイルサンプリングの2つがあります。

ヘッドサンプリングは、トレースの開始時点でアプリケーションが送信可否を判断する方式です。構成は簡単ですが、トレース全体を見て判断できないため、後半で発生する重要な情報を考慮できないという制約があります。

テイルサンプリングは、Collectorがトレース全体を受け取ってから判断する方式で、ヘッドサンプリングでは難しい複雑な条件での選別が可能です。エラーを含むものや遅いトレースを確実に残せるほか、カスタム属性を使った柔軟なサンプリングルールにも対応できます。

例えば、ユーザーのプランなどのサービス固有の情報をカスタム属性としてトレースに付与することで、ビジネス要件に基づいた優先度の高いリクエストを重点的にサンプリングすることも可能です。

今回の構成では、サンプリング条件を柔軟に変更でき、重要なトレースを確実に残せるように、テイルサンプリングを採用しました。

最終的な構成

最終的に、Railsアプリケーションから収集したトレースをOpenTelemetry Collector(ゲートウェイ方式)に集約し、Mackerel APMへ送信する構成となりました。

全体のデータフローは以下の通りです。

  1. メインのECSサービス上で起動するRailsアプリケーションは、Ruby用のOpenTelemetry SDKで各処理のトレースを収集
  2. 収集したトレースデータは、複数のECSタスクからService Discoveryを利用してOpenTelemetry Collector用のECSサービスへ送信される
  3. OpenTelemetry Collectorでは、受信したトレースを集約した上でサンプリングなどの処理を行い、最終的にMackerel APMへエクスポートする

2ではECSのService Discoveryを使って、ALBなどを介さないシンプルな通信を行なっています。
この構成では、例えばタスク側から以下のようにotel-collector.localという任意の名前でCollector用のECSサービスを名前解決できます。

Railsアプリ側のECSタスク定義のエンドポイント指定例

{
  "environment": [
    {
      "name": "OTEL_EXPORTER_OTLP_ENDPOINT",
      "value": "http://otel-collector.local:4318"
    }
  ]
}

アプリケーション側のエクスポート設定では、OTEL_EXPORTER_OTLP_ENDPOINT環境変数を指定しています。実装時(2025年7月時点)ではRuby用のSDKでは、gRPC(4317)をサポートしていないためか、gRPCエンドポイントを指定しても動作しませんでした。

そのためOTEL_EXPORTER_OTLP_ENDPOINTは、HTTP/Protobuf(通常 4318)を使用することにしました。

この構成により、アプリケーションとオブザーバビリティ基盤を明確に分離し、柔軟で運用しやすい環境を実現しています。

Mackerel APMで可視化

OpenTelemetryでトレースをMackerel APMへ送信するには、Collectorを使っている場合、Configで、exportersで以下のようにendpointを向けると送信可能です。

exporters:
  otlphttp/mackerel:
    endpoint: "https://otlp-vaxila.mackerelio.com"
    headers:
      Accept: "*/*"
      "Mackerel-Api-Key": ${env:MACKEREL_APIKEY}

参考
https://mackerel.io/ja/docs/entry/tracing/installations/opentelemetry-collector

Mackerel APM上で、以下のようにトレースを可視化できました。

UIがシンプルで見やすく、直感的に操作できる点がとても良いと感じています。正式リリース後も、画面、機能の改善やMCPをはじめとした新機能の追加が継続的に行われている点も好印象です。

トレースが可視化されたことで、大きなリリース時の確認手順にAPMのチェックを組み込めるようになり、アプリケーションレベルでお客様影響の有無を定量的に判断しやすくなりました。

一方で、トレースの計装については、Ruby用ライブラリの自動計装によってある程度は取得できているものの、自動計装ではカバーできていない部分も多いため、手動での計装も追加しています。

また、今回はトレースの話が中心でしたが、OpenTelemetryを用いたメトリクス実装の検証も並行して行いました。ただし、現時点では本導入はしておりません。トレース以外のテレメトリデータについては、今後の必要性に応じて標準化を検討していくのが良さそうだと考えています。

まとめ

今回は、OpenTelemetryの導入背景から導入までの経緯を説明してきました。
OpenTelemetryを導入することで、プロダクトのオブザーバビリティを向上できていると感じています。ただ、改善やAPMを活用した施策については、今後まだまだ取り組んでいく必要があるため、また機会があれば、情報共有させていただければと思います。


次回の担当はiOSエンジニアのfuku0223さんのリリースを自動化した話です。ぜひお楽しみに。

ZAICO Developers Blog

Discussion