本文へ移動
cccskills
無料GitHub で公開

distributed-tracing

JaegerとTempoによる分散トレーシングを実装して、マイクロサービス間のリクエストを追跡し、パフォーマンスボトルネックを特定します。マイクロサービスのデバッグ、リクエストフローの分析、分散システムの可観測性実装時に使用します。

インストール方法を見る

含まれるファイル(1)

  • SKILL.md11.0 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

English | 日本語

分散トレーシング

マイクロサービス間のリクエストフローの可視性のためにJaegerとTempoによる分散トレーシングを実装します。

目的

分散システム間でリクエストを追跡し、レイテンシ、依存関係、障害ポイントを理解します。

使用タイミング

  • レイテンシ問題のデバッグ
  • サービス依存関係の理解
  • ボトルネックの特定
  • エラー伝播のトレース
  • リクエストパスの分析

分散トレーシングの概念

トレース構造

トレース(リクエストID: abc123)
  ↓
スパン(frontend)[100ms]
  ↓
スパン(api-gateway)[80ms]
  ├→ スパン(auth-service)[10ms]
  └→ スパン(user-service)[60ms]
      └→ スパン(database)[40ms]

主要コンポーネント

  • トレース - エンドツーエンドのリクエストジャーニー
  • スパン - トレース内の単一操作
  • コンテキスト - サービス間で伝播されるメタデータ
  • タグ - フィルタリング用のキーバリューペア
  • ログ - スパン内のタイムスタンプ付きイベント

Jaegerのセットアップ

Kubernetesデプロイ

# Jaeger Operatorのデプロイ
kubectl create namespace observability
kubectl create -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.51.0/jaeger-operator.yaml -n observability

# Jaegerインスタンスのデプロイ
kubectl apply -f - <<EOF
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
  name: jaeger
  namespace: observability
spec:
  strategy: production
  storage:
    type: elasticsearch
    options:
      es:
        server-urls: http://elasticsearch:9200
  ingress:
    enabled: true
EOF

Docker Compose

version: '3.8'
services:
  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "5775:5775/udp"
      - "6831:6831/udp"
      - "6832:6832/udp"
      - "5778:5778"
      - "16686:16686"  # UI
      - "14268:14268"  # Collector
      - "14250:14250"  # gRPC
      - "9411:9411"    # Zipkin
    environment:
      - COLLECTOR_ZIPKIN_HOST_PORT=:9411

参照: references/jaeger-setup.mdを参照

アプリケーション計装

OpenTelemetry(推奨)

Python(Flask)

from opentelemetry import trace
from opentelemetry.exporter.jaeger.thrift import JaegerExporter
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from flask import Flask

# トレーサーの初期化
resource = Resource(attributes={SERVICE_NAME: "my-service"})
provider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(JaegerExporter(
    agent_host_name="jaeger",
    agent_port=6831,
))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# Flaskの計装
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)

@app.route('/api/users')
def get_users():
    tracer = trace.get_tracer(__name__)

    with tracer.start_as_current_span("get_users") as span:
        span.set_attribute("user.count", 100)
        # ビジネスロジック
        users = fetch_users_from_db()
        return {"users": users}

def fetch_users_from_db():
    tracer = trace.get_tracer(__name__)

    with tracer.start_as_current_span("database_query") as span:
        span.set_attribute("db.system", "postgresql")
        span.set_attribute("db.statement", "SELECT * FROM users")
        # データベースクエリ
        return query_database()

Node.js(Express)

const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base');
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express');

// トレーサーの初期化
const provider = new NodeTracerProvider({
  resource: { attributes: { 'service.name': 'my-service' } }
});

const exporter = new JaegerExporter({
  endpoint: 'http://jaeger:14268/api/traces'
});

provider.addSpanProcessor(new BatchSpanProcessor(exporter));
provider.register();

// ライブラリの計装
registerInstrumentations({
  instrumentations: [
    new HttpInstrumentation(),
    new ExpressInstrumentation(),
  ],
});

const express = require('express');
const app = express();

app.get('/api/users', async (req, res) => {
  const tracer = trace.getTracer('my-service');
  const span = tracer.startSpan('get_users');

  try {
    const users = await fetchUsers();
    span.setAttributes({ 'user.count': users.length });
    res.json({ users });
  } finally {
    span.end();
  }
});

Go

package main

import (
    "context"
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/jaeger"
    "go.opentelemetry.io/otel/sdk/resource"
    sdktrace "go.opentelemetry.io/otel/sdk/trace"
    semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)

func initTracer() (*sdktrace.TracerProvider, error) {
    exporter, err := jaeger.New(jaeger.WithCollectorEndpoint(
        jaeger.WithEndpoint("http://jaeger:14268/api/traces"),
    ))
    if err != nil {
        return nil, err
    }

    tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(exporter),
        sdktrace.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("my-service"),
        )),
    )

    otel.SetTracerProvider(tp)
    return tp, nil
}

func getUsers(ctx context.Context) ([]User, error) {
    tracer := otel.Tracer("my-service")
    ctx, span := tracer.Start(ctx, "get_users")
    defer span.End()

    span.SetAttributes(attribute.String("user.filter", "active"))

    users, err := fetchUsersFromDB(ctx)
    if err != nil {
        span.RecordError(err)
        return nil, err
    }

    span.SetAttributes(attribute.Int("user.count", len(users)))
    return users, nil
}

参照: references/instrumentation.mdを参照

コンテキスト伝播

HTTPヘッダー

traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
tracestate: congo=t61rcWkgMzE

HTTPリクエストでの伝播

Python

from opentelemetry.propagate import inject

headers = {}
inject(headers)  # トレースコンテキストを注入

response = requests.get('http://downstream-service/api', headers=headers)

Node.js

const { propagation } = require('@opentelemetry/api');

const headers = {};
propagation.inject(context.active(), headers);

axios.get('http://downstream-service/api', { headers });

Tempoのセットアップ(Grafana)

Kubernetesデプロイ

apiVersion: v1
kind: ConfigMap
metadata:
  name: tempo-config
data:
  tempo.yaml: |
    server:
      http_listen_port: 3200

    distributor:
      receivers:
        jaeger:
          protocols:
            thrift_http:
            grpc:
        otlp:
          protocols:
            http:
            grpc:

    storage:
      trace:
        backend: s3
        s3:
          bucket: tempo-traces
          endpoint: s3.amazonaws.com

    querier:
      frontend_worker:
        frontend_address: tempo-query-frontend:9095
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tempo
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: tempo
        image: grafana/tempo:latest
        args:
          - -config.file=/etc/tempo/tempo.yaml
        volumeMounts:
        - name: config
          mountPath: /etc/tempo
      volumes:
      - name: config
        configMap:
          name: tempo-config

参照: assets/jaeger-config.yaml.templateを参照

サンプリング戦略

確率的サンプリング

# トレースの1%をサンプリング
sampler:
  type: probabilistic
  param: 0.01

レート制限サンプリング

# 最大100トレース/秒をサンプリング
sampler:
  type: ratelimiting
  param: 100

適応的サンプリング

from opentelemetry.sdk.trace.sampling import ParentBased, TraceIdRatioBased

# トレースIDに基づくサンプリング(決定論的)
sampler = ParentBased(root=TraceIdRatioBased(0.01))

トレース分析

遅いリクエストの検索

Jaegerクエリ:

service=my-service
duration > 1s

エラーの検索

Jaegerクエリ:

service=my-service
error=true
tags.http.status_code >= 500

サービス依存関係グラフ

Jaegerは以下を示すサービス依存関係グラフを自動生成します:

  • サービス関係
  • リクエスト率
  • エラー率
  • 平均レイテンシ

ベストプラクティス

  1. 適切にサンプリング(本番環境で1-10%)
  2. 意味のあるタグを追加(user_id、request_id)
  3. すべてのサービス境界でコンテキストを伝播
  4. スパンで例外をログ
  5. 操作に一貫した命名を使用
  6. トレーシングのオーバーヘッドを監視(CPU影響<1%)
  7. トレースエラーのアラートを設定
  8. 分散コンテキストを実装(バゲージ)
  9. 重要なマイルストーンにスパンイベントを使用
  10. 計装標準を文書化

ロギングとの統合

相関ログ

import logging
from opentelemetry import trace

logger = logging.getLogger(__name__)

def process_request():
    span = trace.get_current_span()
    trace_id = span.get_span_context().trace_id

    logger.info(
        "Processing request",
        extra={"trace_id": format(trace_id, '032x')}
    )

トラブルシューティング

トレースが表示されない:

  • コレクターエンドポイントを確認
  • ネットワーク接続を検証
  • サンプリング設定を確認
  • アプリケーションログをレビュー

高レイテンシオーバーヘッド:

  • サンプリングレートを削減
  • バッチスパンプロセッサーを使用
  • エクスポーター設定を確認

リファレンスファイル

  • references/jaeger-setup.md - Jaegerインストール
  • references/instrumentation.md - 計装パターン
  • assets/jaeger-config.yaml.template - Jaeger設定

関連スキル

  • prometheus-configuration - メトリクスのため
  • grafana-dashboards - 可視化のため
  • slo-implementation - レイテンシSLOのため

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Migrate from AngularJS to Angular using hybrid mode, incremental component rewriting, and dependency injection updates. Use when upgrading AngularJS applications, planning framework migrations, or modernizing legacy Angular code.

日本語の概要は準備中です。原文の説明を表示しています。

amurata/cc-tools62025年11月28日 更新

angular-migration

無料日本語概要

ハイブリッドモード、段階的コンポーネント書き換え、依存性注入更新を使用してAngularJSからAngularへ移行します。AngularJSアプリケーションのアップグレード、フレームワーク移行の計画、またはレガシーAngularコードのモダナイゼーション時に使用します。

amurata/cc-tools62025年11月28日 更新

Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.

日本語の概要は準備中です。原文の説明を表示しています。

amurata/cc-tools62025年11月28日 更新

api-design-principles

無料日本語概要

開発者を喜ばせる直感的でスケーラブルで保守可能なAPIを構築するために、RESTとGraphQL APIの設計原則をマスターします。新しいAPIの設計、API仕様のレビュー、またはAPI設計標準の確立時に使用してください。

amurata/cc-tools62025年11月28日 更新

Implement proven backend architecture patterns including Clean Architecture, Hexagonal Architecture, and Domain-Driven Design. Use when architecting complex backend systems or refactoring existing applications for better maintainability.

日本語の概要は準備中です。原文の説明を表示しています。

amurata/cc-tools62025年11月28日 更新

architecture-patterns

無料日本語概要

クリーンアーキテクチャ、ヘキサゴナルアーキテクチャ、ドメイン駆動設計を含む実証済みのバックエンドアーキテクチャパターンを実装します。複雑なバックエンドシステムの設計や、保守性向上のための既存アプリケーションのリファクタリング時に使用します。

amurata/cc-tools62025年11月28日 更新

amurata のスキルをすべて見る

このスキルの問題を報告する