技术架构

オブザーバビリティの3本柱:Traces、Metrics、Logs

マイクロサービスとクラウドネイティブアーキテクチャにおいて、オブザーバビリティはシステムの振る舞いを理解するために不可欠です。

オブザーバビリティ ≠ モニタリング。モニタリングは既知の問題の検出、オブザーバビリティは未知の問題の探索。

目的 典型的なシナリオ
Traces リクエストの完全なライフサイクル クロスサービスコールチェーン追跡
Metrics 定量化されたシステム指標 パフォーマンス監視、キャパシティプランニング
Logs 離散的なイベント記録 エラー調査、監査

OpenTelemetryは、CNCFのインキュベーティングプロジェクトで、3つのシグナルを統一的に収集するベンダーニュートラルなAPI、SDK、ツールを提供します。


OpenTelemetryアーキテクチャ:SDK、Collector、Exporter

3層アーキテクチャにより、収集とエクスポートの分離を実現:

アプリケーション層 SDK (Java/Go/Node)
    ↓ OTLP(gRPC/HTTP)
OTel Collector (受信→処理→エクスポート)
    ↓
バックエンド (Jaeger/Prometheus/Elasticsearch)
レイヤー コンポーネント 責務 デプロイ
SDK OpenTelemetry SDK 自動/手動インストルメンテーション プロセス内
Collector OTel Collector テレメトリデータの受信、処理、ルーティング スタンドアロン
Exporter OTLP Exporter バックエンドへのデータエクスポート Collector内

Java Agent自動インストルメンテーション:ゼロコード侵入

JVM引数を1つ追加するだけで、Spring Boot、HTTPクライアント、JDBC、Redisなどを自動追跡:

java -javaagent:opentelemetry-javaagent.jar \
     -Dotel.service.name=order-service \
     -Dotel.traces.exporter=otlp \
     -Dotel.metrics.exporter=otlp \
     -Dotel.exporter.otlp.endpoint=http://collector:4317 \
     -jar my-app.jar

主要設定

設定 デフォルト 説明
otel.service.name unknown サービス名
otel.traces.exporter otlp Traceエクスポーター
otel.traces.sampler parentBased_alwaysOn サンプリング戦略

自動インストルメンテーション対応範囲

コンポーネント 自動Trace 自動Metrics
Spring Web MVC/WebFlux
RestTemplate/WebClient
JDBC / R2DBC
Redis (Lettuce/Jedis)
Kafka

分散トレーシング実践

コールチェーン例

[OrderService] POST /api/orders
  ├── [InventoryService] POST /api/inventory/deduct
  ├── [PaymentService] POST /api/payments/charge
  └── [NotificationService] CONSUME payment-success

W3C Trace Context伝播

traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067bf0bc902b7-01

カスタムSpanとAttributes

@Service
public class OrderService {

    private final Tracer tracer;

    public OrderResult createOrder(CreateOrderRequest request) {
        Span span = tracer.spanBuilder("order.create")
            .setAttribute("order.userId", request.getUserId())
            .setAttribute("order.productCount", request.getItems().size())
            .startSpan();

        try (Scope scope = span.makeCurrent()) {
            OrderResult result = doCreateOrder(request);
            span.setAttribute("order.id", result.getOrderId());
            return result;
        } catch (Exception e) {
            span.recordException(e);
            span.setStatus(StatusCode.ERROR, e.getMessage());
            throw e;
        } finally {
            span.end();
        }
    }
}

Metrics収集:Counter、Histogram、Gauge

タイプ セマンティクス 集約方式 ユースケース
Counter 増加のみのカウント Sum リクエスト総数、エラー総数
Histogram 値の分布統計 Histogram リクエストレイテンシ
Gauge 現在の瞬時値 Last Value アクティブ接続数
Meter meter = meterProvider.meterBuilder("payment-service").build();

LongCounter requestCounter = meter.counterBuilder("payment.requests.total")
    .setDescription("Total payment requests")
    .build();

LongHistogram latencyHistogram = meter.histogramBuilder("payment.request.duration")
    .setUnit("ms")
    .ofLongs()
    .build();

Collectorデプロイメントモード

モード メリット デメリット ユースケース
Sidecar 隔離性が良い リソースコスト大 大規模K8s
DaemonSet リソース効率が良い 単一障害点リスク 一般推奨
Gateway 集中管理 ネットワークホップ増 マルチクラスター

Collector設定

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    send_batch_size: 1024
    timeout: 5s

exporters:
  otlp/jaeger:
    endpoint: jaeger:4317
  prometheusremotewrite:
    endpoint: http://prometheus:9090/api/v1/write

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/jaeger]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheusremotewrite]

サンプリング戦略:ヘッドベース vs テールベース

ヘッドベースサンプリング

otel.traces.sampler=parentbased_traceidratio
otel.traces.sampler.arg=0.1

シンプルで効率的だが、エラーリクエストを見逃す可能性あり。

テールベースサンプリング

processors:
  tail_sampling:
    decision_wait: 10s
    sampling_policies:
      - name: errors-policy
        type: status_code
        status_code:
          status_codes: [ERROR]
      - name: slow-policy
        type: latency
        latency:
          threshold_ms: 1000
      - name: fallback-policy
        type: probabilistic
        probabilistic:
          sampling_percentage: 10

推奨:本番環境ではテールベースサンプリングを使用し、エラーと遅いリクエストの100%可視性を確保。


フロントエンドRUM統合

import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';

const exporter = new OTLPTraceExporter({
  url: 'https://collector.example.com/v1/traces',
});

const provider = new WebTracerProvider();
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();

フロントエンドのHTTPリクエストが自動的にtraceparentヘッダーを運び、ブラウザからバックエンドまでのエンドツーエンドのトレーシングを実現。


Prometheus + Grafanaのクラシックスタック

OpenTelemetry SDK → OTel Collector → Prometheus → Grafana
                                     → Jaeger/Tempo → Grafana

主要メトリクス

パネル PromQL アラート閾値
リクエストレート rate(http_server_request_total[5m]) >10000
P99レイテンシ histogram_quantile(0.99, rate(http_server_duration_bucket[5m])) >500ms
エラーレート rate(http_server_request_total{status=~"5.."}[5m]) / rate(http_server_request_total[5m]) >1%

RED原則:Rate、Errors、Duration — サービスモニタリングの3つのゴールデンシグナル。


まとめ

オブザーバビリティは贅沢品ではなく、マイクロサービスアーキテクチャの必需品である。 オブザーバビリティがなければマイクロサービスはブラックボックス、OpenTelemetryがあればシステムの振る舞いを完全に把握できる。

ブラウザローカルツールを無料で試す →

#OpenTelemetry#可观测性#分布式追踪#Metrics#日志