ケーススタディ: マイクロサービスのエンドツーエンドの可観測性の実装
このシリーズの最後の記事では、次のことを分析します。 実際のケース 実装の マイクロサービス アーキテクチャにおける可観測性の向上。私たちはスタートアップの道を歩みます 慢性的な問題を解決するために OpenTelemetry を採用した 5 つのマイクロサービスを備えた電子商取引 デバッグ、平均解決時間 (MTTR) の短縮、可視性の向上 ビジネスフローを完了します。
初期状況(可観測性ゼロ)から実装の各フェーズを文書化します。 本番環境のフルスタックまで、 メトリクスの前後 数値化するもの 可観測性への投資の影響。
この記事で学べること
- 段階的な可観測性の実装を計画する方法
- 5 つのマイクロサービスのフルスタック構成
- 実際の電子商取引フローのインスツルメンテーション パターン
- 運用およびビジネス監視のための Grafana ダッシュボード
- 前後のメトリクス: MTTR、インシデント検出、SLO コンプライアンス
- 学んだ教訓と導入に関する推奨事項
コンテキスト: ShopFlow E コマース プラットフォーム
ショップの流れ そして、次のスタックを備えたマイクロサービスベースの電子商取引プラットフォームです。
ショップフローアーキテクチャ
| サービス | 言語 | データベース | 責任 |
|---|---|---|---|
| APIゲートウェイ | Node.js (高速) | Redis (キャッシュ) | ルーティング、認証、レート制限 |
| オーダーサービス | Java (スプリングブート) | PostgreSQL | 注文作成、ステータス管理 |
| 在庫サービス | Python (高速API) | PostgreSQL | 在庫管理、予約 |
| 決済サービス | Java (スプリングブート) | PostgreSQL | 支払い、返金 |
| 通知サービス | Python (高速API) | モンゴDB | メール、SMS、プッシュ通知 |
サービスは、非同期イベントの場合、同期 HTTP および Kafka を介して通信します。導入 Kubernetes (EKS) 上で行われ、ピーク時の注文量は 1 時間あたり約 500 件になります。
可観測性以前の状況
OpenTelemetry を採用する前は、ShopFlow のシステムへの可視性は限られていました。
- 非構造化ログ: 各サービスは、trace_id なしで、異なる形式でログに記録されます。リクエストのログを検索するには、5 つのサービスで手動の grep が必要でした
- 基本的な指標: CloudWatch からのインフラストラクチャ メトリクス (CPU、メモリ、ディスク) のみ。アプリケーション メトリクスは含まれません。
- ゼロトレース: サービスを通じてリクエストに従うことができません。サービス間の問題のデバッグには数日かかりました
- 事後対応アラート: CPU > 80% および一般的な 5xx エラーのみをアラートします。エラーの種類やビジネスへの影響に関するコンテキストはありません。
可観測性以前のメトリクス (ベースライン)
| メトリック | 価値 |
|---|---|
| MTTR (平均解決時間) | 4.5時間 |
| MTTD (平均検出時間) | 45分 |
| インシデント P1/月 | 8 |
| SLO 準拠 (99.5%) | 94% 月の |
| サービス間のデバッグ時間 | 2~4時間 |
| インシデント/月のコスト (推定) | 12,000ドル |
フェーズ 1: 自動インストルメンテーションとコレクター (第 1 ~ 2 週目)
最初のフェーズでは、可観測性インフラストラクチャの展開に焦点を当てます。 アプリケーションコードを変更することなく、サービスの自己計測を実現します。
# Fase 1: Deploy OTel Collector come DaemonSet
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: otel-collector-agent
namespace: observability
spec:
selector:
matchLabels:
app: otel-agent
template:
spec:
containers:
- name: collector
image: otel/opentelemetry-collector-contrib:0.96.0
args: ["--config=/etc/otel/config.yaml"]
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
resources:
requests:
cpu: 200m
memory: 256Mi
ports:
- containerPort: 4317
hostPort: 4317
---
# Auto-instrumentation per i servizi Java
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: shopflow-instrumentation
namespace: shopflow
spec:
exporter:
endpoint: http://otel-collector-agent.observability:4317
propagators:
- tracecontext
- baggage
sampler:
type: parentbased_traceidratio
argument: "1.0" # 100% in fase iniziale
java:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:latest
python:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-python:latest
nodejs:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-nodejs:latest
---
# Annotare i deployment per l'auto-instrumentation
# Order Service (Java)
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: shopflow
spec:
template:
metadata:
annotations:
instrumentation.opentelemetry.io/inject-java: "shopflow-instrumentation"
フェーズ 2: 手動インストルメンテーションとログ相関 (第 3 ~ 6 週)
第 2 フェーズでは、チームはビジネス フロー用の手動計測を追加します。 クリティカルであり、ログを分散トレースにリンクするようにログとトレースの相関を構成します。
// Order Service: instrumentazione manuale del flusso checkout
@Service
public class CheckoutService {
private final Tracer tracer;
private final LongCounter ordersCreated;
private final DoubleHistogram orderValue;
public CheckoutService(OpenTelemetry otel) {
this.tracer = otel.getTracer("order-service");
Meter meter = otel.getMeter("order-service");
this.ordersCreated = meter.counterBuilder("shopflow.orders.created")
.setDescription("Orders created").build();
this.orderValue = meter.histogramBuilder("shopflow.orders.value")
.setDescription("Order value in EUR").setUnit("EUR").build();
}
public Order processCheckout(CheckoutRequest req) {
Span span = tracer.spanBuilder("checkout.process")
.setAttribute("customer.id", req.getCustomerId())
.setAttribute("customer.tier", req.getCustomerTier())
.setAttribute("cart.items_count", req.getItems().size())
.setAttribute("cart.total", req.getTotal())
.startSpan();
try (Scope scope = span.makeCurrent()) {
// Validazione
Span valSpan = tracer.spanBuilder("checkout.validate").startSpan();
try (Scope s = valSpan.makeCurrent()) {
validateCheckout(req);
valSpan.setStatus(StatusCode.OK);
} finally { valSpan.end(); }
// Riserva inventario
Span invSpan = tracer.spanBuilder("checkout.reserve-inventory")
.setAttribute("inventory.items", req.getItems().size())
.startSpan();
try (Scope s = invSpan.makeCurrent()) {
reserveInventory(req.getItems());
} finally { invSpan.end(); }
// Pagamento
Span paySpan = tracer.spanBuilder("checkout.payment")
.setAttribute("payment.method", req.getPaymentMethod())
.setAttribute("payment.amount", req.getTotal())
.startSpan();
try (Scope s = paySpan.makeCurrent()) {
processPayment(req);
} finally { paySpan.end(); }
// Creazione ordine
Order order = createOrder(req);
span.setAttribute("order.id", order.getId());
span.setAttribute("order.status", "created");
// Metriche di business
ordersCreated.add(1, Attributes.of(
AttributeKey.stringKey("customer.tier"), req.getCustomerTier(),
AttributeKey.stringKey("payment.method"), req.getPaymentMethod()
));
orderValue.record(req.getTotal(), Attributes.of(
AttributeKey.stringKey("customer.tier"), req.getCustomerTier()
));
span.setStatus(StatusCode.OK);
return order;
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR, e.getMessage());
throw e;
} finally {
span.end();
}
}
}
フェーズ 3: ダッシュボード、アラート、SLO (月 2 ~ 3)
3 番目のフェーズでは、チームは運用およびビジネスの監視のための Grafana ダッシュボードを作成します。 SLO ベースのアラートを構成し、サンプリングを最適化してコストを削減します。
# Alert basati su SLO per ShopFlow
groups:
- name: shopflow-slo-alerts
rules:
# SLO: 99.5% delle richieste checkout con successo
- alert: CheckoutSLOBreach
expr: |
1 - (
sum(rate(http_server_request_duration_seconds_count{
service="order-service",
http_route="/api/checkout",
http_status_code=~"2.."
}[1h]))
/
sum(rate(http_server_request_duration_seconds_count{
service="order-service",
http_route="/api/checkout"
}[1h]))
) > 0.005
for: 5m
labels:
severity: critical
slo: checkout-success-rate
annotations:
summary: "Checkout success rate below 99.5% SLO"
# SLO: P99 latenza checkout sotto 3 secondi
- alert: CheckoutLatencySLO
expr: |
histogram_quantile(0.99,
sum(rate(http_server_request_duration_seconds_bucket{
service="order-service",
http_route="/api/checkout"
}[5m])) by (le)
) > 3
for: 5m
labels:
severity: warning
slo: checkout-latency
annotations:
summary: "Checkout P99 latency above 3s SLO"
# SLO: pagamenti con successo sopra 98%
- alert: PaymentSuccessRateSLO
expr: |
sum(rate(shopflow_payments_total{status="success"}[1h]))
/
sum(rate(shopflow_payments_total[1h])) < 0.98
for: 5m
labels:
severity: critical
annotations:
summary: "Payment success rate below 98%"
結果: 前後のメトリクス
完全実装から 3 か月後、ShopFlow では次の改善が測定されました。
ShopFlow に対する可観測性の影響
| メトリック | 前に | Dopo | 改善 |
|---|---|---|---|
| MTTR | 4.5時間 | 1.2時間 | -73% |
| MTTD | 45分 | 3分 | -93% |
| インシデント P1/月 | 8 | 3 | -62% |
| SLO準拠 | 94% | 99.2% | +5.2pp |
| サービス間のデバッグ | 2~4時間 | 10~30分 | -87% |
| インシデント/月のコスト | 12,000ドル | 3,200ドル | -73% |
学んだ教訓
ShopFlow での可観測性の実装により、いくつかの有益な教訓が生まれました。 同じ道を歩むあらゆる組織:
主な推奨事項
- 自己計測から始める: コードを変更することなく、自動インストルメンテーションとコレクタにより、最初の月に価値の 70% が得られます。
- 相関関係に投資する: ログとトレースの相関関係と、ROI が最も高い単一の改善。デバッグ時間を 90% 短縮
- ダッシュボードの前に SLO を定義する: SLO は、収集するメトリックと構成するアラートの選択をガイドします。
- すぐにすべてを計測しないでください: 3 ~ 5 つの最も重要なビジネス フローから開始し、徐々に拡張します。
- コレクターを監視する: コレクターは重要なコンポーネントです。失敗すると視界がすべて失われます
- エラー時のテールサンプリング: 初期フェーズ (100% サンプリング) の後、100% の誤差を維持しながらテール サンプリングを実装します。
- チームを構築する: 可観測性は、チームがツールの使用方法を知っている場合にのみ価値があります。 Grafana、PromQL、トレース読み取りに関するトレーニングに投資する
導入コスト
ROI を計算するには、可観測性への投資コストを文書化することが重要です。 ShopFlow の場合、オープンソース スタックのコストは主にエンジニアリング時間にかかります およびインフラストラクチャ リソース:
導入の総コスト
| Voce | 推定コスト |
|---|---|
| エンジニアリング時間 (セットアップ + 計測) | 約 120 時間 (エンジニア 3 人 x 2 週間フル + パートタイム) |
| インフラストラクチャ コレクター (DaemonSet + ゲートウェイ) | ~$200/月 (EKS 上の CPU + メモリ) |
| バックエンド ストレージ (Jaeger、Prometheus、Loki) | ~$350/月 (EBS ボリューム + コンピューティング) |
| Grafana Cloud (セルフホスト型の代替) | $0 (セルフホスト型) または ~$500/月 (クラウド) |
| 月々の合計 | ~$550/月 (自己ホスト型) |
| 事故を防ぐ | ~$8,800/月 |
| ROI | 16倍 (節約/コスト) |
実装スケジュール
アイデアから製品化までの完全なプロセスには約 3 か月かかりました。 各段階で増分:
概要タイムライン
1週目: 5 つのサービスにコレクター、バックエンド (Jaeger、Prometheus、Grafana)、自動インスツルメンテーションをデプロイします。
最初の値:Jaeger で表示される分散トレース。
2週目: コレクターのパイプライン構成 (フィルター処理、バッチ処理)。各サービスの RED メトリクスを含む Grafana ダッシュボード。
3~4週目: チェックアウトおよび支払いフローの手動計測。 Loki とのログトレース相関。
最初のサービス間のデバッグは 15 分で完了しました (以前は 3 時間かかりました)。
5~6週目: カスタム ビジネス指標 (注文/時間、収益、コンバージョン率)。製品チーム用のダッシュボード。
2ヶ月目: SLO 定義、SLO ベースのアラート、テール サンプリング。 100% のエラーを維持しながら、トレース量を 80% 削減しました。
3ヶ月目: 最適化、チームトレーニング、ランブックのドキュメント。結果の安定化と測定。
シリーズの結論
この 12 記事シリーズでは、現代の可観測性の全範囲をカバーしました。 OpenTelemetry、理論的基礎 (3 つの柱、監視と可観測性) から このケーススタディまでの高度な実装 (eBPF、AI 可観測性、テール サンプリング) 実際のメトリクスを使用すると実用的です。
このシリーズの重要なメッセージは次のとおりです。
- 可観測性はシステムの特性です、買うべき商品ではありません。これは、正確な計測と信号相関を通じて構築されています。
- OpenTelemetry と標準: 一度インストゥルメントすれば、どこにでもエクスポートできます。コードを変更せずにバックエンドを自由に変更できることは、戦略的な利点です。
- シンプルに始めて徐々に進化させる: 1 か月目に自動計測、2 か月目に手動計測、3 か月目に最適化。
- 相関と値の乗数: トレース、ログ、メトリクスを接続すると、デバッグ時間が 90% 短縮されます。
- 可観測性には測定可能な ROI がある: MTTR と事故の削減は、経済的な節約とユーザー エクスペリエンスの向上に直接つながります。
可観測性はコストではなく、 投資 それはすぐに元が取れます 分散システムでは。 OpenTelemetry では、標準ツールと成熟したツールが利用可能です そして、採用プロセスは十分に文書化されています。始めるのに最適な時期は今です。







