EXERCISE 60分

ストーリー

佐藤CTO
オブザーバビリティの理論を学んだ。次は実際にオブザーバビリティ基盤を設計し構築してみよう
佐藤CTO
マイクロサービス4つで構成される注文システムに対して、メトリクス・トレース・ログの3本柱を統合した基盤を設計してほしい

ミッション概要

ミッションテーマ目安時間
Mission 1OpenTelemetry計装設計15分
Mission 2メトリクス設計とPromQLクエリ15分
Mission 3分散トレーシングの設計15分
Mission 4統合ダッシュボードの設計15分

前提条件

system: "OrderFlow - 注文処理システム"
services:
  - name: "order-api"
    tech: "Node.js + Express"
    role: "注文の受付・管理"
  - name: "inventory-service"
    tech: "Node.js + Fastify"
    role: "在庫管理・引当"
  - name: "payment-service"
    tech: "Node.js + Express"
    role: "決済処理"
  - name: "notification-service"
    tech: "Node.js + Express"
    role: "メール・SMS通知"

infrastructure:
  - PostgreSQL (orders DB)
  - PostgreSQL (inventory DB)
  - Redis (caching)
  - RabbitMQ (messaging)

request_flow:
  "order-api → inventory-service → payment-service → notification-service"

Mission 1: OpenTelemetry計装設計(15分)

要件

OrderFlowシステムの各サービスに対するOpenTelemetry計装を設計してください。 以下を含めること:

  1. 共通の計装設定(全サービス共通)
  2. サービス固有のカスタムSpan設計(各サービス最低2つ)
  3. Span属性(Attributes)の設計
  4. Context Propagation戦略(同期呼び出しとメッセージキュー)
解答例

1. 共通計装設定:

// shared/telemetry.ts
const sdk = new NodeSDK({
  resource: new Resource({
    'service.name': process.env.SERVICE_NAME,
    'service.version': process.env.APP_VERSION,
    'deployment.environment': process.env.NODE_ENV,
  }),
  traceExporter: new OTLPTraceExporter({ url: 'http://otel-collector:4318/v1/traces' }),
  instrumentations: [
    getNodeAutoInstrumentations(), // HTTP, Express, pg, amqplib自動計装
  ],
});

2. サービス固有のカスタムSpan:

サービスSpan名種類主要属性
order-apicreateOrderINTERNALorder.id, order.total, order.items_count
order-apivalidateOrderINTERNALorder.id, validation.result
inventory-servicereserveStockINTERNALitem.id, quantity, warehouse.id
inventory-servicecheckAvailabilityCLIENTitem.id, available_quantity
payment-serviceprocessPaymentINTERNALpayment.amount, payment.provider
payment-servicecallStripeAPICLIENTstripe.charge_id
notification-servicesendEmailCLIENTemail.to, email.template
notification-servicesendSMSCLIENTsms.phone, sms.provider

3. Context Propagation:

同期呼び出し: W3C Trace Context ヘッダーで自動伝搬
メッセージキュー(RabbitMQ): メッセージヘッダーにTrace Contextを注入

// RabbitMQ Producer
const headers: Record<string, string> = {};
propagation.inject(context.active(), headers);
channel.publish(exchange, routingKey, content, { headers });

// RabbitMQ Consumer
const parentContext = propagation.extract(ROOT_CONTEXT, message.properties.headers);
context.with(parentContext, () => { /* 処理 */ });

Mission 2: メトリクス設計とPromQLクエリ(15分)

要件

OrderFlowシステムのSLI/SLOに必要なPrometheusメトリクスを設計し、PromQLクエリを記述してください。

  1. 各サービスに必要なカスタムメトリクス(最低3つ/サービス)
  2. SLI計算用のRecording Rules
  3. 障害検知用のPromQLクエリ
解答例

1. カスタムメトリクス:

サービスメトリクス名タイプ説明
order-apiorder_created_totalCounter注文作成数
order-apiorder_processing_duration_secondsHistogram注文処理時間
order-apiorder_statusGaugeステータス別の注文数
inventory-servicestock_reserved_totalCounter在庫引当数
inventory-servicestock_availableGauge利用可能在庫数
payment-servicepayment_processed_totalCounter決済処理数(status別)
payment-servicepayment_amount_totalCounter決済金額合計

2. Recording Rules:

groups:
  - name: orderflow_sli
    rules:
      - record: sli:order_success_rate:5m
        expr: |
          sum(rate(order_created_total{status="success"}[5m]))
          /
          sum(rate(order_created_total[5m]))
      - record: sli:order_latency_p99:5m
        expr: |
          histogram_quantile(0.99,
            sum(rate(order_processing_duration_seconds_bucket[5m])) by (le)
          )
      - record: sli:payment_success_rate:5m
        expr: |
          sum(rate(payment_processed_total{status="success"}[5m]))
          /
          sum(rate(payment_processed_total[5m]))

3. 障害検知クエリ:

# 在庫引当の失敗率が5%を超えた
sum(rate(stock_reserved_total{result="failed"}[5m]))
/
sum(rate(stock_reserved_total[5m])) > 0.05

# RabbitMQキューの滞留
rabbitmq_queue_messages{queue="orders"} > 1000

# DB接続プール枯渇
pg_stat_activity_count / pg_settings_max_connections > 0.8

Mission 3: 分散トレーシングの設計(15分)

要件

注文処理フロー全体のトレーシング設計を行ってください。

  1. 典型的な注文フローのTrace構造(Span階層図)
  2. サンプリング戦略の設計
  3. 障害時のトレース活用シナリオ
解答例

1. Trace構造:

Trace: createOrder (order-api)
├── validateOrder (order-api) [50ms]
├── reserveStock (inventory-service) [120ms]
│   ├── checkAvailability (inventory-service) [30ms]
│   │   └── pg.query SELECT (inventory-db) [15ms]
│   └── pg.query UPDATE (inventory-db) [20ms]
├── processPayment (payment-service) [800ms]
│   ├── pg.query INSERT (orders-db) [10ms]
│   └── callStripeAPI (external) [700ms]
├── publishOrderEvent (order-api → RabbitMQ) [5ms]
└── sendNotification (notification-service) [200ms]  ※非同期
    ├── sendEmail (external SMTP) [150ms]
    └── sendSMS (external API) [100ms]

2. サンプリング戦略:

tail_based_sampling:
  policies:
    - name: errors
      type: status_code
      status_codes: [ERROR]
      sample_rate: 100%
    - name: slow_orders
      type: latency
      threshold_ms: 3000
      sample_rate: 100%
    - name: payment_traces
      type: string_attribute
      key: service.name
      values: [payment-service]
      sample_rate: 50%
    - name: default
      type: probabilistic
      sample_rate: 10%

3. 障害シナリオ:

シナリオ: 決済の遅延が発生
1. アラート: payment_latency_p99 > 3s
2. Grafanaダッシュボードで確認
3. Tempoで遅いトレースを検索: duration > 3s
4. Trace詳細: callStripeAPI Spanが2.5s(通常300ms)
5. Span属性: stripe.response_code=429 (Rate Limited)
6. 根本原因: Stripe APIのレート制限に到達
7. 対策: リトライバックオフ + レート制限の緩和申請

Mission 4: 統合ダッシュボードの設計(15分)

要件

メトリクス、トレース、ログを統合した障害対応ダッシュボードを設計してください。

  1. ダッシュボードのパネル構成
  2. メトリクスからトレースへのドリルダウン方法
  3. トレースからログへの相関検索方法
解答例

1. パネル構成:

graph TD
    subgraph Dashboard["OrderFlow 統合ダッシュボード"]
        subgraph Row1["Row 1: SLO概要"]
            R1A["注文成功率"]
            R1B["決済成功率"]
            R1C["バジェット残"]
            R1D["MTTR"]
        end
        subgraph Row2["Row 2: リクエストフロー"]
            R2A["サービス別レイテンシ<br/>(Time Series)"]
            R2B["エラー率 by サービス<br/>(Time Series)"]
        end
        subgraph Row3["Row 3: トレース & ログ"]
            R3A["遅いトレース一覧<br/>(Tempo Exemplar)"]
            R3B["最新エラーログ<br/>(Loki Stream)"]
        end
        subgraph Row4["Row 4: インフラ"]
            R4A["DB接続数"]
            R4B["RabbitMQキュー"]
            R4C["Redis Hit Rate"]
        end
    end

    classDef slo fill:#198754,stroke:#146c43,color:#fff
    classDef flow fill:#0d6efd,stroke:#0a58ca,color:#fff
    classDef trace fill:#f5a623,stroke:#c47d10,color:#fff
    classDef infra fill:#6c757d,stroke:#495057,color:#fff

    class R1A,R1B,R1C,R1D slo
    class R2A,R2B flow
    class R3A,R3B trace
    class R4A,R4B,R4C infra

2. ドリルダウンフロー:

メトリクス(エラー率上昇を検知)

  ├─ Exemplar機能: メトリクスのグラフ上にTrace IDがプロット
  │  └─ クリックでTempoのトレース詳細に遷移

  └─ 時間範囲で絞り込み → Tempoで検索
     conditions: {service="payment-service", status=error}

3. トレース→ログ相関:

トレース詳細画面で Trace ID をコピー

  └─ GrafanaのExplore画面 → Lokiデータソース
     クエリ: {service=~".*"} | json | traceId = "<copied_trace_id>"
     → 全サービスの関連ログを時系列で表示

達成度チェック

ミッションテーマ完了
Mission 1OpenTelemetry計装設計
Mission 2メトリクス設計とPromQL
Mission 3分散トレーシング設計
Mission 4統合ダッシュボード設計

まとめ

ポイント内容
計装設計共通設定 + サービス固有のカスタムSpan
メトリクスSLI計算用のRecording Rules + 障害検知クエリ
トレーシングTail-basedサンプリングでエラー・遅延を確実に記録
統合ダッシュボードExemplarでメトリクス→トレース→ログのドリルダウン

チェックリスト

  • マイクロサービスのOpenTelemetry計装を設計できた
  • SLI用のRecording RulesとPromQLクエリを記述できた
  • サンプリング戦略を設計できた
  • 3本柱を統合したダッシュボードを設計できた

次のステップへ

次は理解度チェッククイズです。Step 3で学んだオブザーバビリティ基盤の理解度を確認しましょう。


推定読了時間: 60分