- 1 1. この記事について — 観測性本番運用シリーズ Vol3 完結巻
- 2 2. 前提・環境・準備
- 3 3. Application Signals vs CloudWatch Metrics 採用判断 + SLO 概念整理
- 4 4. ADOT + Application Signals 統合 Terraform 完全実装 — Lambda / ECS / EKS 3 形態
- 5 5. SLO 3 種 Terraform 実装 + Error Budget + Burn Rate 2-window アラート設計
- 6 6. Synthetic Canary + Real User Monitoring (RUM) + SLO 統合監視 — 外形監視と実ユーザー監視の連携
- 7 7. Burn Rate アラート → PagerDuty / OpsGenie 自動エスカレーション + コスト最適化
- 8 8. まとめ + 観測性 3 部作完結宣言 + 9 巻 AWS 本番運用シリーズ完結 + 落とし穴 10 選
1. この記事について — 観測性本番運用シリーズ Vol3 完結巻

1-1. 観測性 3 部作 + 9 巻シリーズの完結
本記事は「AWS 本番運用シリーズ」9 巻の完結巻です。Lambda 3 部作・EKS 3 部作を経て、観測性 3 部作の最終章として CloudWatch Application Signals + SLO を本番実装します。
観測性 3 部作の構成
| 巻 | テーマ | WP ID | ステータス |
|---|---|---|---|
| Vol1 | CloudWatch Logs Insights — ログ解析基盤 | 2252 | 公開済 |
| Vol2 | X-Ray + ADOT — 分散トレーシング基盤 | 2304 | 公開済 |
| Vol3 | Application Signals + SLO (本記事) | 2315 | 完結巻 |
9 巻シリーズ全体図
Lambda 3 部作がサービス層のデプロイ・パフォーマンス・コスト最適化を担い、EKS 3 部作がコンテナ基盤のスケーリング・IAM・GitOps を担い、観測性 3 部作がシステム全体の可視化と品質保証を担います。
- Lambda 本番運用 Vol1: コンテナイメージ + Blue/Green デプロイ
- Lambda 本番運用 Vol2: SnapStart + Provisioned Concurrency
- Lambda 本番運用 Vol3: Powertools + Lambda Layers + コスト最適化
- EKS 本番運用 Vol1: Karpenter + クラスターオートスケーリング
- EKS 本番運用 Vol2: IRSA + IAM 最小権限設計
- EKS 本番運用 Vol3: ALB + ArgoCD GitOps
- 観測性 Vol1: CloudWatch Logs Insights (ログ層)
- 観測性 Vol2: X-Ray + ADOT (トレース層)
- 観測性 Vol3: Application Signals + SLO (SLO 層) ← 本記事 (完結巻)
3 層完成の設計思想
Vol1 でログ層、Vol2 でトレース層を整備しました。本記事 Vol3 で SLO 層を追加することで、可観測性の 3 本柱「ログ・トレース・SLO」が完成します。SLO はシステムの信頼性を定量化し、「どこまで劣化を許容するか」という運用判断に根拠を与えます。Application Signals はこの SLO 管理を Lambda・ECS・EKS 横断で一元的に実現するマネージドサービスです。Vol2 で整備した ADOT Collector を再利用し、追加コストを最小化しながら SLO を本番導入します。
3 層が揃うことで「障害発生 → SLO/Burn Rate 検知 → アラート → ログ + トレースで根本原因分析」という一気通貫の観測性ループが完成します。
なぜ今 Application Signals なのか
従来の SLO 管理では独自実装のメトリクス収集・ダッシュボード・アラーム設定が必要で、設計コストの高さや属人化しやすい運用課題が長年残っていました。AWS が 2024 年に GA した Application Signals はこれらを一元化し、ADOT Collector と CloudWatch の既存インフラをそのまま活用して SLO・Error Budget・Burn Rate を自動計算します。
- ADOT 再利用: Vol2 で構築した Collector 設定に
awsapplicationsignalsexporter を追加するだけで移行完了 - Lambda/ECS/EKS 横断: 3 形態を同一の SLO コンソールで統合管理し、サービスマップで依存関係も可視化
- Terraform ネイティブ:
aws_applicationsignals_service_level_objectiveリソースが AWS Provider 5.x で追加され、IaC で完全管理可能 - Error Budget 自動算出: SLO 定義後、残 Error Budget と Burn Rate を CloudWatch が自動計算。手動集計は不要
このタイミングで導入することで、Vol1 ログ・Vol2 トレースと連携した「障害発生 → SLO 違反検知 → Burn Rate アラート → PagerDuty 通知 → ログ・トレースで根本原因分析」の全自動観測性パイプラインが完成します。
1-2. 本記事のゴール
本記事を完了すると、以下の成果物が手元に揃います。
- SLO 3 種の Terraform 定義と稼働確認: Availability SLO (99.9%) / Latency SLO (p99 < 500ms) / Error Rate SLO (< 0.1%) を
aws_applicationsignals_service_level_objectiveで定義 - Burn Rate 2-window アラート: Fast window (1 時間) + Slow window (6 時間) の二段階検知で誤報を抑制しながら早期検知を実現
- Synthetic Canary 外形監視: 5 分間隔の外形テストで SLO 計測の盲点 (内部メトリクスが正常でも外部から到達不可の状態) を補完
- Real User Monitoring (RUM): エンドユーザー体験を SLI として取り込み、SLO の完全性を向上
- PagerDuty / OpsGenie 自動エスカレーション: Burn Rate 超過を SNS → Lambda → Webhook で自動連携し、夜間の手動確認を不要化
これらはすべて Terraform IaC で管理されており、git 管理・CI/CD パイプラインへの統合が可能です。また Vol1 のログ・Vol2 のトレースと組み合わせることで、SLO 違反発生時に CloudWatch Logs Insights でエラーログを検索し、X-Ray トレースで障害箇所を特定する完全な調査フローが整います。
Vol1 / Vol2 との連携ポイント
本記事の成果物は観測性 3 部作の前 2 巻と直接連携します。
| 本記事の実装 | Vol1 (Logs) との連携 | Vol2 (Traces) との連携 |
|---|---|---|
| SLO 違反検知 | Logs Insights でエラーログを検索し根本原因を特定 | X-Ray トレースで障害サービスと遅延箇所を特定 |
| Burn Rate アラーム | Lambda escalator のログを Logs Insights で監視 | Canary の active_tracing で X-Ray に記録 |
| RUM エラー | JavaScript エラーを CloudWatch Logs に転送 | RUM enableXRay で API 呼び出しトレースと連携 |
3 部作を通じて「ログ → トレース → SLO」の完全な可観測性スタックが完成します。Vol1・Vol2 未読の場合は §1-5 のシリーズナビからご参照ください。
1-3. 読者像
パターン 1: Lambda SRE
Lambda で外部 API・DynamoDB を呼ぶサービスの可用性を SLO で管理したい。CloudWatch Alarms は設定済みだが、Error Budget の概念を本番運用に取り込めていない。SLO 違反が発生したとき、どこまでバジェットが残っているかを定量的に把握し、リリースペースの調整判断に使いたい。
本記事では Lambda に ADOT Layer を追加して Application Signals を有効化し、Availability SLO と Error Rate SLO を Terraform で定義する手順を解説します。Burn Rate 2-window アラートと PagerDuty 連携まで一気通貫で実装できます。
パターン 2: ECS マイクロサービス運用者
ECS 上の 5〜6 サービスで応答遅延が増加しているが、SLO がないため「どこまで劣化を許容するか」の基準がない。Burn Rate でアラート閾値を設計し、PagerDuty 連携を整備して夜間の呼び出し件数を最適化したい。
本記事では ECS サイドカー ADOT Collector の設定変更から Application Signals 有効化、Latency SLO 定義、Burn Rate アラームまでを Terraform で管理する方法を解説します。複数サービスを SLO コンソールで一元管理する方法も紹介します。
パターン 3: EKS Platform Engineer
Vol1 (Logs) + Vol2 (Traces) は整備済み。最後の層として SLO Dashboard と Error Budget Tracking を実装したい。既存の ADOT Collector を再利用し、追加インフラを最小化した Application Signals 統合を実現したい。
本記事では amazon-cloudwatch-observability EKS Add-on による ADOT + Application Signals の自動設定から Terraform IRSA 設定まで解説します。Namespace への自動計装注入により、アプリコードを変更せずに SLO 計測が開始されます。
1-4. 本記事の構成早見表
| 章 | テーマ | ポイント |
|---|---|---|
| §3 | Application Signals vs CloudWatch Metrics 採用判断 + SLO 概念整理 | brc-red: 採用判断基準を明示 |
| §4 | ADOT + Application Signals Terraform 統合 (Lambda/ECS/EKS) | brc-red: 横断実装パターン |
| §5 | SLO 3 種 + Error Budget + Burn Rate 2-window | Error Budget 自動計算ロジック |
| §6 | Synthetic Canary + RUM + SLO 統合監視 | 外形監視 × 実ユーザー体験 |
| §7 | Burn Rate → PagerDuty/OpsGenie 自動エスカレーション + コスト最適化 | 夜間アラート最適化 |
| §8 | まとめ + 観測性 3 部作完結 + 9 巻シリーズ完結告知 | 全体総括 |
§3・§4 は「何を選ぶか・なぜ選ぶか」の意思決定層で、既存システムに Application Signals を導入すべきか判断する読者に特に有用です。§5〜§7 は「どう実装するか」の実践層で、Terraform コードをそのまま活用できます。§8 は 9 巻シリーズ全体の総括として、次のステップを示します。
1-5. シリーズナビ
Vol2 未読の場合は、ADOT Collector の基礎設定と X-Ray トレーシングの概念を先に把握しておくと本記事の §4 をスムーズに読み進められます。
前提を読む: 観測性Vol2 X-Ray + ADOT 分散トレーシング基盤
2. 前提・環境・準備

2-0. SLI / SLO / Error Budget / Burn Rate の概念整理
本記事を読む前に、4 つの基本概念を押さえておきましょう。
| 用語 | 定義 | 例 |
|---|---|---|
| SLI (Service Level Indicator) | サービス品質を測定する指標 (計測値) | 成功リクエスト率 99.95% |
| SLO (Service Level Objective) | SLI の目標値 | 成功率 >= 99.9% (30日間) |
| Error Budget | SLO を下回ることが許容される量 (= 100% – SLO目標) | 0.1% = 月間 43.2 分のダウンタイム |
| Burn Rate | Error Budget が消費される速さ (1× = SLO期間ちょうどで使い切る速度) | 14× = 1h で Error Budget の 2% を消費 |
Burn Rate が重要なのは「今の障害が続くとあと何時間で Error Budget を使い切るか」を定量化できるためです。Burn Rate 1× 未満なら問題なし。Burn Rate 14× 以上は「今すぐ対処しないと SLO 違反」のシグナルです。
2-1. 前提環境
本記事では以下の環境が整備済みであることを前提とします。
- 観測性 Vol1 完了: CloudWatch Logs Insights によるログ解析基盤が稼働中
- 観測性 Vol2 完了: X-Ray + ADOT 分散トレーシング基盤が稼働中 (ADOT Collector 稼働中)
- AWS CLI v2.x:
aws --versionで v2.x 以上であることを確認 - Terraform >= 1.7:
terraform versionで 1.7 以上であることを確認 - 対応リージョン: Application Signals 対応リージョン (us-east-1 / ap-northeast-1 / eu-west-1 等)
- IAM 権限:
application-signals:*/cloudwatch:PutMetricAlarm/synthetics:*/rum:* - 稼働中ワークロード: Lambda / ECS / EKS のいずれか (Vol2 で ADOT 計装済み)
Application Signals は ADOT Collector が収集したメトリクスを入力として動作します。Vol2 で整備した Collector 設定をそのまま再利用するため、追加の計装コードは不要です。
前提環境の確認コマンド:
# AWS CLI バージョン確認
aws --version
# Terraform バージョン確認
terraform version
# Application Signals 対応リージョン確認 (ap-northeast-1 で例示)
aws application-signals list-services \
--start-time $(date -d '1 hour ago' +%s 2>/dev/null || date -v-1H +%s) \
--end-time $(date +%s) \
--region ap-northeast-1 2>&1 | head -5
# ADOT Collector 稼働確認 (ECS の場合)
aws ecs list-tasks --cluster my-cluster --region ap-northeast-1
2-2. 使用技術スタック
| サービス / ツール | バージョン | 用途 |
|---|---|---|
| CloudWatch Application Signals | GA (2024-) | SLO 定義 + Error Budget + Burn Rate 算出 |
| ADOT Collector (Vol2 成果) | v0.39+ | Application Signals メトリクス送出 |
aws_applicationsignals_service_level_objective | AWS Provider >= 5.x | SLO Terraform リソース |
aws_synthetics_canary | AWS Provider >= 3.x | Synthetic Canary (外形監視) |
aws_rum_app_monitor | AWS Provider >= 4.x | Real User Monitoring |
aws_cloudwatch_metric_alarm | AWS Provider >= 3.x | Burn Rate Fast/Slow アラーム |
aws_sns_topic / aws_lambda_function | AWS Provider >= 3.x | PagerDuty / OpsGenie 連携 |
| Terraform | >= 1.7 | IaC 管理 |
2-3. Terraform 主要リソース一覧
本記事で定義する Terraform リソースの全体像です。
| Terraform リソース | 役割 |
|---|---|
aws_applicationsignals_service_level_objective | SLO 3 種 (Availability / Latency / Error Rate) 定義 |
aws_cloudwatch_metric_alarm | Burn Rate Fast window (1h) + Slow window (6h) アラーム |
aws_synthetics_canary | 5 分間隔外形監視 Canary |
aws_rum_app_monitor | Real User Monitoring AppMonitor |
aws_sns_topic | Burn Rate アラーム通知先 SNS |
aws_lambda_function | PagerDuty / OpsGenie Webhook 中継 Lambda |
aws_iam_role | Canary / RUM / Lambda 実行ロール |
2-4. 今回のゴール状態定義
本記事の完了時点で、以下の状態が AWS マネジメントコンソールおよび terraform state で確認できることをゴールとします。
- SLO 3 種: Availability / Latency / Error Rate の SLO が Application Signals コンソールに表示され、Error Budget が緑 (残あり) であること
- Burn Rate アラーム: CloudWatch Alarms で Fast window / Slow window の 2 アラームが
OK状態で稼働していること - Synthetic Canary: Synthetics コンソールで 5 分間隔の Canary が
Passedを返していること - RUM AppMonitor: CloudWatch RUM コンソールで AppMonitor が稼働し、ページビューデータが収集されていること
確認コマンドチートシート:
# SLO 稼働確認
aws application-signals list-service-level-objectives --region ap-northeast-1
# Error Budget レポート
aws application-signals batch-get-service-level-objective-budget-report \
--timestamp $(date +%s) \
--slo-ids '["my-service-availability-slo"]' \
--region ap-northeast-1
# Canary ステータス確認
aws synthetics get-canary --name my-service-api-health --region ap-northeast-1
# RUM AppMonitor 確認
aws rum get-app-monitor --name my-app-rum --region ap-northeast-1
3. Application Signals vs CloudWatch Metrics 採用判断 + SLO 概念整理
3-1. CloudWatch Application Signals とは
CloudWatch Application Signals は 2024 年に GA となった AWS ネイティブの APM (Application Performance Monitoring) 機能だ。従来の CloudWatch でサービス品質を監視するには、カスタムメトリクスを手動定義し、X-Ray でトレースを収集し、SLO は自前スクリプトで計算するという分散した作業が必要だった。Application Signals はこれらを「サービス」単位で自動集約し、SLO / Error Budget / Burn Rate を AWS マネジメントコンソールと API で一元管理できる環境を提供する。
Application Signals の核心は OpenTelemetry (ADOT) との統合にある。ADOT Collector が送出するメトリクス・トレース・ログを受け取り、サービスマップとして可視化する。ユーザーは ADOT の設定に awsapplicationsignals エクスポーターを追加するだけで、追加のコード変更なしに Application Signals のすべての機能を利用できる。
対応プラットフォームと計装方式:
| プラットフォーム | 計装方式 | 備考 |
|---|---|---|
| AWS Lambda | ADOT Lambda Layer 追加のみ | Lambda Insights は不要になる場合あり |
| Amazon ECS | ADOT サイドカーコンテナ | タスク定義に ADOT コンテナを追加 |
| Amazon EKS | ADOT Operator + Auto-instrumentation | K8s アノテーションで自動計装 |
| Amazon EC2 | CloudWatch Agent + ADOT Collector | エージェントを EC2 にインストール |
Auto-instrumentation が特に強力なのは EKS だ。Pod に instrumentation.opentelemetry.io/inject-java: "true" などのアノテーションを付けるだけで、JVM エージェントが自動挿入される。コードの変更なしにトレース・メトリクスの収集が始まり、Java・Python・Node.js・.NET がサポートされている。
Vol2 で構築した ADOT Collector は Application Signals のデータソースとして そのまま流用できる。Vol2 の Collector 設定に awsapplicationsignals エクスポーターを追加し、パイプラインにバインドするだけで統合が完了する。具体的な Terraform コードと ADOT 設定は §4 で示す。
Application Signals が提供するダッシュボードでは、サービス間の依存関係を自動生成されたサービスマップで可視化できる。上流・下流のサービスにまたがる SLO 達成状況と Error Budget 消費量を一覧で確認でき、インシデント発生時の影響範囲特定が大幅に効率化される。Burn Rate アラームは CloudWatch Alarms と連携しており、PagerDuty・Slack・SNS への通知も標準的に設定可能だ。
Application Signals のサービス検出はリアルタイムで行われる。ADOT Collector が正しく設定されていれば、アプリケーションへのリクエストが発生した時点で AWS コンソールの「Application Signals → サービスマップ」に新しいノードが追加される。初期設定から動作確認まで、コンソールでの視覚的確認は 5 分以内に完了できる。
Application Signals では、サービス名は ADOT の OTEL_SERVICE_NAME 環境変数で制御される。Lambda では AWS_LAMBDA_FUNCTION_NAME が自動的に使われる。ECS / EKS では OTEL_SERVICE_NAME=my-service を明示的に設定することを推奨する。サービス名が統一されていると、サービスマップでの依存関係グラフと SLO ダッシュボードが自動的に関連付けられる。
OTEL_SERVICE_NAME の命名規則はチーム内で統一しておくことが重要だ。例えば {チーム名}-{機能名} (例: auth-login-api) のような形式にすると、サービスマップのノード数が増えた場合でも構造が把握しやすい。名前を後から変更すると SLO の履歴データとの連続性が失われるため、初期設定時に慎重に決定することを強く推奨する。
3-2. Application Signals vs CloudWatch Metrics 採用判断マトリクス
Application Signals と CloudWatch Metrics の両者は「メトリクスを収集・可視化する」機能を持つが、提供する価値・適用場面が明確に異なる。以下の 5 軸で比較し、どちらを採用すべきかの判断基準を整理する。CloudWatch Metrics は「プッシュ型の汎用メトリクス基盤」であり、Application Signals は「OTel ネイティブの SLO 管理層」として位置づけると理解しやすい。
| 比較軸 | CloudWatch Metrics | Application Signals |
|---|---|---|
| 自動計装 | 手動メトリクス定義必須 | ADOT + 自動計装で即時利用可 |
| SLO ネイティブ | 自前で Error Budget 計算要 | SLO / Error Budget / Burn Rate をコンソールで管理 |
| OTel 互換 | 独自 PutMetricData API | OpenTelemetry Protocol (OTLP) 準拠 |
| Lambda 対応 | カスタムメトリクス + Lambda Insights | ADOT Lambda Layer 追加のみで直結 |
| コスト | メトリクス数 × $0.30/万件 | Application Signals メトリクス料金 + 既存 CloudWatch 料金に上乗せ |
使い分けの原則:
- SLO 管理が必要なシステム → Application Signals 一択。Error Budget と Burn Rate の計算を自前実装する必要がなくなり、SLO 設定から数分でアラームまで構成できる。
- OTel (ADOT) 計装済みの環境 → Application Signals への移行コストはほぼゼロ。既存の ADOT Collector 設定にエクスポーターを追加するだけで全機能が利用可能になる。
- Lambda 単独の簡易監視 → CloudWatch Metrics + Lambda Insights でも十分。SLO 管理が不要で単一 Lambda の基本的な監視に留まる場合は、Application Signals の追加コストを投じるメリットが薄い。
- マルチサービス依存関係の可視化が必要 → Application Signals が圧倒的に優位。サービスマップで自動生成された依存グラフを確認でき、連鎖障害の根本原因特定が高速化される。
- SLO管理が必要 → Application Signals 一択(Error Budget / Burn Rate をコンソールで即管理)
- OTel (ADOT) 計装済み → Application Signals に即切替可能(エクスポーター追加のみ)
- Lambda 単独の簡易監視 → CloudWatch Metrics でも可(導入コスト vs 機能のトレードオフ)
- マルチサービス SLO 統合 → Application Signals(サービスマップ + SLO ダッシュボード)
- コスト: Application Signals は CloudWatch Metrics 料金 + SLO 評価料金(詳細は §7)
コスト面では、Application Signals は通常の CloudWatch メトリクス料金に加え、SLO 評価ごとの追加料金が発生する。月次コストの具体的な試算と最適化手法は §7 のコスト最適化セクションで詳しく解説する。
3-3. SLI / SLO / Error Budget / Burn Rate 用語整理
SRE (Site Reliability Engineering) の文脈で頻出するこれらの概念を、Application Signals の機能と対応づけながら整理する。各用語の数学的定義と実務での使い方を押さえることで、§5 の SLO 設定作業がスムーズになる。
SLI (Service Level Indicator)
サービスの品質を定量化した指標。Application Signals では以下の 3 種類の SLI を標準で計測する。
- 可用性 (Availability SLI): 計測期間内の成功リクエスト率。計算式:
(成功リクエスト数 ÷ 総リクエスト数) × 100。HTTP 2xx/3xx を成功、5xx をエラーとしてカウントする。 - レイテンシ (Latency SLI): リクエストの応答時間パーセンタイル。P50 / P90 / P99 / P99.9 を選択可能。P99 は「100 リクエスト中 99 件がこの時間以内に完了している」ことを意味する。
- エラー率 (Error Rate SLI): HTTP 5xx またはアプリケーション定義のエラーコードの割合。可用性 SLI の補集合として利用できる。
Application Signals では SLI の計測粒度は 1 分 (60 秒) ごとだ。1 分ウィンドウでのメトリクス集計が SLO 達成率の計算に使われるため、一瞬のスパイクよりも継続的なエラーが SLO に大きく影響する。カスタム SLI (アプリケーション定義のメトリクス) を使いたい場合は metric_source_config に MonitoredRequestCount ではなく Metric Math 式を指定できる (詳細は §5)。
SLO (Service Level Objective)
SLI に対して組織が設定する目標値。Application Signals の SLO 設定画面では、SLI の種類・集計ウィンドウ (7 日 / 30 日 / カレンダー月) ・目標値 (%) を指定する。
典型的な SLO 設定例:
| SLO 種類 | 目標値 | 実務での解釈 |
|---|---|---|
| Availability | 99.9% | 月間 43.2 分のダウンタイムが許容範囲 |
| Availability | 99.99% | 月間 4.32 分のダウンタイムが許容範囲 |
| Latency P99 | 99% が 200ms 以内 | 100 リクエスト中 99 件が 200ms 以内 |
| Latency P99.9 | 99.9% が 1000ms 以内 | 1000 リクエスト中 999 件が 1 秒以内 |
SLO の目標値は高いほど良いわけではない。99.999% を目標にすると Error Budget が月間 26 秒しかなく、わずかなインフラ作業でも Error Budget を使い果たす。サービスの重要度とチームの運用コストを勘案して現実的な目標値を設定することが SRE の実践では重要だ。
集計ウィンドウには ローリング (Rolling) と カレンダー (Calendar) の 2 種類がある。Rolling 30 日は常に「直近 30 日」で計算するためリアルタイム性が高い。Calendar Month は「月初〜月末」でリセットされるため、月末で Error Budget が回復するという心理的効果がある。Application Signals のデフォルト設定は Rolling 30 日であり、SRE のベストプラクティスに合致する。
カレンダー月を選ぶ場合、月末でリセットされる直前へリリース作業を集中させるインセンティブを生まないよう注意したい。
Error Budget
SLO 達成のために許容できる「失敗の予算」。SLO を 99.9% に設定した場合、Error Budget は 100% - 99.9% = 0.1% となる。
具体的な計算例 (30 日 / 月次集計の場合):
| SLO | Error Budget (%) | 月次許容ダウンタイム | 月次許容エラー数 (100万req/月) |
|---|---|---|---|
| 99.9% | 0.1% | 43.2 分 | 1,000 件 |
| 99.5% | 0.5% | 216 分 | 5,000 件 |
| 99.99% | 0.01% | 4.32 分 | 100 件 |
Application Signals の「Error Budget」パネルでは、残余予算をパーセンテージとしてリアルタイム表示する。予算が 0% に近づくと Burn Rate アラームがトリガーされ、デプロイ凍結や緊急対応を促す仕組みだ。
Burn Rate
Error Budget の消費速度を表す指標。Burn Rate = 1.0 は「ちょうど SLO 集計期間中に Error Budget を使い切るペース」を意味する。
| Burn Rate | 消費ペース | 区分 | 推奨アクション |
|---|---|---|---|
| < 1.0 | 予算内消費 | 正常 | 問題なし・定期確認継続 |
| 1.0 ~ 2.0 | わずかに超過 | 要監視 | 傾向監視・次スプリントで対処 |
| > 6x (6h 計測) | Slow Burn 検知 | Slow Burn | P2 アラート・予防的調査 |
| > 14x (1h 計測) | Fast Burn 検知 | Fast Burn | P1 緊急インシデント・即時対応 |
Fast Burn Rate (14x / 1 時間) は「このペースが 1 時間続くと Error Budget が枯渇する」状況を検知する。Slow Burn Rate (6x / 6 時間) は「緩やかに消費が進んでいるが、週次でみると予算超過ペース」という状況を早期に捉える。Application Signals では両方のアラームを CloudWatch Alarms 経由で PagerDuty・SNS に通知できる (詳細は §7)。
Burn Rate の具体的な計算例: SLO = 99.9% (30 日間)、月間リクエスト数 = 1,000 万件のシステムを想定する。
- Error Budget = 1,000 万 × 0.1% = 10,000 件 のエラーが月間許容予算
- Fast Burn (14x / 1h): 1 時間で 10,000 × 2% = 200 件消費ペース → 緊急インシデント
- Slow Burn (6x / 6h): 6 時間で 10,000 × 5% = 500 件消費ペース → 予防的対応
- 通常ペース (1x): 月間 10,000 件 ÷ 720 時間 = 約 14 件/時間が正常消費レート
Google SRE の書籍が提唱する 2-window Burn Rate アラーム設計は、Application Signals の Burn Rate アラームに直接適用できる。Fast Burn (1h × 14×) と Slow Burn (6h × 6×) の 2 ウィンドウを組み合わせることで、急激な障害 (分単位) と緩やかな品質劣化 (時間単位) の両方を早期検知できる。2 ウィンドウを採用することで単一ウィンドウと比較してアラートの偽陽性が大幅に減少する。具体的な CloudWatch Alarm Terraform 実装は §5-6 で詳述する。

sequenceDiagram
participant C as クライアント
participant S as アプリサービス
participant AS as Application Signals
participant SLO as SLO Engine
participant CW as CloudWatch Alarms
participant PD as PagerDuty
C->>S: リクエスト
S->>AS: ADOT Collector 経由でメトリクス送出
AS->>AS: SLI 計測 (SuccessRate / Latency / ErrorRatio)
AS->>SLO: SLI 値報告
SLO->>SLO: SLO 達成率算出 (99.9% 目標)
SLO->>SLO: Error Budget 消費量計算
alt Burn Rate > 14x (Fast Burn 1h)
SLO->>CW: BurnRateAlarm 発火 (Critical)
CW->>PD: P1 インシデント作成
else Burn Rate > 6x (Slow Burn 6h)
SLO->>CW: BurnRateAlarm 発火 (Warning)
CW->>PD: P2 インシデント作成
end
3-5. Application Signals の有効化方法
Application Signals を有効化するには、コンソール・AWS CLI・Terraform の 3 通りのアプローチがある。初回有効化はコンソールで確認しながら進め、本番環境の再現性確保には Terraform での管理を推奨する。
コンソール操作:
- AWS マネジメントコンソール → CloudWatch を開く
- 左ナビゲーション → Application Signals → サービス を選択
- 「Start Discovering Services」ボタンをクリック (初回のみ)
- 対象リージョン (例: ap-northeast-1) でサービスの自動検出が開始される
- ADOT が送出しているサービス名がサービスマップに表示されたら有効化完了
AWS CLI による確認コマンド:
# Application Signals サービス一覧確認 (過去1時間)
aws application-signals list-services \
--start-time $(date -v-1H +%s) \
--end-time $(date +%s) \
--region ap-northeast-1
# SLO 一覧の確認
aws application-signals list-service-level-objectives \
--region ap-northeast-1 \
--output table
# 特定 SLO の Error Budget レポート取得
aws application-signals get-service-level-objective \
--id <SLO_ID> \
--region ap-northeast-1
Terraform による有効化:
Application Signals の有効化自体はリージョン単位の AWS 側設定であり、Terraform では aws_applicationsignals_service_level_objective リソースで SLO を定義する。ADOT Collector 設定 (awsapplicationsignals エクスポーター) の Terraform 実装は §4 で詳述する。Burn Rate アラームの Terraform 定義は §7 で扱う。
Application Signals を有効化したあと、最初に確認すべきは aws application-signals list-services の出力だ。ここに自分のサービス名が表示されればデータパスが正常に接続されている。表示されない場合は IAM 権限 (application-signals:PutServiceData) または ADOT Collector の awsapplicationsignals エクスポーター設定を見直す。
3-6. 観測性シリーズ 関連記事
本記事は観測性本番運用シリーズの Vol3 完結巻として位置づけられ、Vol1・Vol2 で構築した技術スタックの上位レイヤーを担う。
- 観測性 Vol1: CloudWatch Logs Insights + Metrics Filter 本番運用 — ログ集約・異常検知・カスタムメトリクス化の基盤
- 観測性 Vol2: X-Ray + ADOT 分散トレーシング本番運用 — ADOT Collector 構築・分散トレーシング → Vol3 で Application Signals のデータソースとして活用
Vol2 で構築した ADOT Collector の設定に awsapplicationsignals エクスポーターを追加することで、追加のコード変更なしに Application Signals との連携が完成する。観測性の 3 層構造 (ログ → トレース → SLO) が完全に統合される仕組みは §4 で図解する。
3 部作を通じた観測性成熟度の高まりを整理すると: Vol1 (ログ層) でインフラの状態を把握し、Vol2 (トレース層) でサービス間の依存関係と処理フローを可視化し、Vol3 (SLO 層・本記事) でエンドユーザー体験の品質目標を定量管理する。各層が独立して動作しながらも相互に参照できることが、このシリーズの設計思想の核心だ。
4. ADOT + Application Signals 統合 Terraform 完全実装 — Lambda / ECS / EKS 3 形態
4-1. Vol2 ADOT Collector → Application Signals への切替ポイント
観測性 Vol2 で構築した ADOT Collector 環境は、awsapplicationsignals exporter を追加するだけで Application Signals へメトリクスを送出できる。
既存の awsxray exporter と並行運用が可能なため、トレースを継続しながら SLO 機能を段階的に追加できる。
exporters:
awsapplicationsignals:
region: ap-northeast-1
service:
pipelines:
metrics:
receivers: [otlp]
processors: [memory_limiter, batch, awsapplicationsignals]
exporters: [awsapplicationsignals]
traces:
receivers: [otlp]
exporters: [awsxray]
Vol2 の ADOT Collector config に awsapplicationsignals exporter と metrics pipeline を追記するだけで移行が完了する。traces pipeline は既存のまま維持するため、X-Ray トレースへの影響はない。

4-2. Lambda: ADOT Layer + Application Signals 自動計装
Lambda では、Application Signals 対応の ADOT Lambda Layer を追加し、環境変数 2 つを設定するだけで自動計装が有効になる。
ランタイムコードの変更は不要であり、既存の Lambda Powertools Tracer と共存できる。
Layer ARN (Python / amd64 / ap-northeast-1):arn:aws:lambda:ap-northeast-1:901920570463:layer:aws-otel-python-amd64-ver-1-21-0:1
最新 ARN は AWS ADOT Lambda Layer ドキュメント を参照すること。
Terraform 実装:
resource "aws_lambda_function" "my_service" {
function_name = "my-service"
runtime = "python3.12"
handler = "app.handler"
filename= "lambda.zip"
role = aws_iam_role.lambda_role.arn
# ADOT Lambda Layer (Application Signals 対応版)
layers = [
"arn:aws:lambda:ap-northeast-1:901920570463:layer:aws-otel-python-amd64-ver-1-21-0:1"
]
environment {
variables = {
AWS_LAMBDA_EXEC_WRAPPER= "/opt/otel-instrument"
OTEL_AWS_APPLICATION_SIGNALS_ENABLED = "true"
OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT = "http://localhost:4316/v1/metrics"
OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf"
OTEL_PROPAGATORS = "tracecontext,baggage,xray"
}
}
}
resource "aws_iam_role_policy" "lambda_application_signals" {
role = aws_iam_role.lambda_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"application-signals:PutServiceData",
"xray:PutTraceSegments",
"xray:PutTelemetryRecords",
"xray:GetSamplingRules",
"xray:GetSamplingTargets",
"cloudwatch:PutMetricData"
]
Resource = "*"
}]
})
}
動作確認 (AWS CLI):
aws application-signals list-services \
--start-time $(date -d '10 minutes ago' +%s) \
--end-time $(date +%s) \
--region ap-northeast-1
Lambda に対して数回リクエストを送った後、上記コマンドでサービスが検出されれば計装成功。
CloudWatch コンソール → Application Signals → サービスマップ でも視覚的に確認できる。
4-3. ECS: ADOT Collector サイドカー + Application Signals 設定
ECS Fargate では、ADOT Collector をサイドカーコンテナとしてタスク定義に追加する。
アプリコンテナは localhost:4317 (OTLP gRPC) に送出するだけでよく、コード変更は最小限に抑えられる。
ADOT Collector の設定は SSM Parameter Store に保存し、タスク定義の secrets 経由で渡す方式が推奨される。
Terraform 実装:
resource "aws_ssm_parameter" "adot_config" {
name = "/myapp/adot/config"
type = "String"
value = yamlencode({
exporters = {
awsapplicationsignals = { region = "ap-northeast-1" }
awsxray= { region = "ap-northeast-1" }
}
service = {
pipelines = {
metrics = {
receivers = ["otlp"]
processors = ["memory_limiter", "batch", "awsapplicationsignals"]
exporters = ["awsapplicationsignals"]
}
traces = {
receivers = ["otlp"]
exporters = ["awsxray"]
}
}
}
})
}
resource "aws_ecs_task_definition" "my_service" {
family = "my-service"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = 512
memory = 1024
execution_role_arn = aws_iam_role.ecs_execution_role.arn
task_role_arn= aws_iam_role.ecs_task_role.arn
container_definitions = jsonencode([
{
name = "app"
image = "my-app:latest"
environment = [
{ name = "OTEL_EXPORTER_OTLP_ENDPOINT", value = "http://localhost:4317" },
{ name = "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", value = "true" },
{ name = "OTEL_PROPAGATORS", value = "tracecontext,baggage,xray" }
]
portMappings = [{ containerPort = 8080, protocol = "tcp" }]
},
{
name = "adot-collector"
image= "public.ecr.aws/aws-observability/aws-otel-collector:latest"
command = ["--config=/etc/otel/config.yaml"]
portMappings = [
{ containerPort = 4317, protocol = "tcp" },
{ containerPort = 4316, protocol = "tcp" }
]
secrets = [{
name= "AOT_CONFIG_CONTENT"
valueFrom = aws_ssm_parameter.adot_config.arn
}]
}
])
}
resource "aws_iam_role_policy" "ecs_application_signals" {
role = aws_iam_role.ecs_task_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"application-signals:PutServiceData",
"xray:PutTraceSegments",
"xray:PutTelemetryRecords",
"xray:GetSamplingRules",
"xray:GetSamplingTargets",
"cloudwatch:PutMetricData"
]
Resource = "*"
}]
})
}
コンソール確認手順:
ECS コンソール → クラスター → タスク → コンテナタブで adot-collector の稼働を確認後、
CloudWatch → Application Signals → サービスマップ に my-service が出現することを確認する。
4-4. EKS: ADOT Operator + Amazon CloudWatch Observability Add-on
EKS では amazon-cloudwatch-observability Add-on を有効化するだけで、ADOT Collector DaemonSet と Application Signals の自動設定が完了する。
Operator が Pod への自動計装用 Init Container を注入するため、アプリコードへの変更は不要。
Terraform 実装:
resource "aws_eks_addon" "cloudwatch_observability" {
cluster_name = aws_eks_cluster.main.name
addon_name = "amazon-cloudwatch-observability"
addon_version = "v2.1.0-eksbuild.1"
configuration_values = jsonencode({
agent = {
config = {
logs = {
metrics_collected = {
application_signals = {}
}
}
}
}
})
depends_on = [aws_eks_node_group.main]
}
# IRSA for CloudWatch Agent (Application Signals)
module "irsa_cloudwatch" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "~> 5.0"
role_name= "cloudwatch-agent-${aws_eks_cluster.main.name}"
attach_cloudwatch_observability_policy = true
oidc_providers = {
main = {
provider_arn= aws_iam_openid_connect_provider.main.arn
namespace_service_accounts = ["amazon-cloudwatch:cloudwatch-agent"]
}
}
}
resource "aws_iam_role_policy_attachment" "cloudwatch_agent" {
role = module.irsa_cloudwatch.iam_role_name
policy_arn = "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
}
動作確認 (kubectl):
# Add-on と Agent の稼働確認
aws eks list-addons --cluster-name my-cluster --region ap-northeast-1
kubectl get pods -n amazon-cloudwatch
# Application Signals 対応 Namespace のアノテーション確認
kubectl get namespace my-app -o yaml | grep instrumentation
Namespace へ instrumentation.opentelemetry.io/inject-python: "true" (ランタイムに応じたキー) を付与すると、
Pod 起動時に ADOT Init Container が自動注入され、Application Signals へのメトリクス送出が開始される。
4-5. IAM 権限設定 — 全形態共通
Lambda 実行ロール・ECS タスクロール・EKS IRSA ServiceAccount のいずれも、以下の IAM アクションが必要。application-signals:PutServiceData が不足すると、サービスは起動していてもメトリクスが Application Signals コンソールに表示されない。
権限エラーは CloudTrail → イベント履歴 → ErrorCode: AccessDenied で即時確認できる。
resource "aws_iam_role_policy" "application_signals_common" {
role = var.role_id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"application-signals:PutServiceData",
"application-signals:GetService",
"application-signals:ListServices",
"cloudwatch:PutMetricData",
"xray:PutTraceSegments",
"xray:PutTelemetryRecords",
"xray:GetSamplingRules",
"xray:GetSamplingTargets"
]
Resource = "*"
}]
})
}
- Lambda 形態:
- ADOT Lambda Layer (Application Signals 対応版) 追加済み
OTEL_AWS_APPLICATION_SIGNALS_ENABLED=true環境変数設定済みAWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument設定済みapplication-signals:PutServiceDataIAM 権限付与済み
- ECS 形態:
- adot-collector サイドカーコンテナ追加済み (ポート 4317/4316)
- ADOT Collector config に
awsapplicationsignalsexporter 設定済み - タスクロールに CloudWatchAgentServerPolicy 相当の権限付与済み
- EKS 形態:
amazon-cloudwatch-observabilityAdd-on 有効化済み- IRSA で CloudWatchAgentServerPolicy 割当て済み
kubectl get pods -n amazon-cloudwatchで Agent 稼働確認済み
- 共通:
application-signals list-servicesでサービス検出確認済み- CloudWatch → Application Signals でサービスマップ表示確認済み
関連記事:
– 観測性 Vol2 — X-Ray + ADOT 分散トレーシング本番運用 — ADOT Collector 構成の前提
– Lambda Vol1 — Lambda コンテナイメージ本番運用 — Lambda 計装の前提
– Lambda Vol3 — Powertools + Layers 本番運用 — Powertools Tracer × Application Signals 連携
– EKS Vol2 — IRSA 本番運用 — IRSA 設定参照
– EKS Vol3 — ALB + Argo CD 本番運用 — Argo CD GitOps 管理
5. SLO 3 種 Terraform 実装 + Error Budget + Burn Rate 2-window アラート設計
5-1. SLO 種別の選択指針
Application Signals がネイティブサポートする SLO は 3 種類あり、監視したい品質指標によって使い分ける。
Availability SLO は成功リクエスト率を基準とした可用性指標です。SLI は SuccessCount / RequestCount × 100 で計算し、99.9% を目標に設定すると月間ダウンタイム許容は 43.2 分となります。API エンドポイントや重要なサービス呼び出しの可用性を継続的に追跡する用途に最適です。
Latency SLO はレスポンスタイムを基準とした応答速度指標です。SLI は「P99 レイテンシが 500ms 以下のリクエスト率」として計測し、95% のリクエストが閾値以内に収まることを目標とします。ユーザー体験に直結するエンドポイントのパフォーマンス劣化を早期検知する用途に適しています。
Error Rate SLO はエラー率を基準とした信頼性指標です。SLI は ErrorCount / RequestCount × 100 が 0.1% 以下であることを計測します。バックグラウンドジョブや非同期処理など、応答速度より信頼性を重視するコンポーネントに向いています。
| SLO 種別 | SLI 計算式 | 目標値例 | 月間許容 | 適用シナリオ |
|---|---|---|---|---|
| Availability | SuccessCount / RequestCount | 99.9% | ダウンタイム 43.2 分 | API 可用性・依存サービス呼び出し |
| Latency | P99 <= 閾値のリクエスト率 | 95.0% | 36 時間分の遅延リクエスト | ユーザー向けエンドポイント |
| Error Rate | (1 – ErrorCount / RequestCount) | 99.9% | エラー 43.2 分相当 | バッチ処理・非同期ジョブ |
5-2. SLO 判断フロー図 + Burn Rate 設計

flowchart TD
A[SLO 種別を選択] --> B{測定したい品質は?}
B -- 可用性・成功率 --> C[Availability SLO\nSuccessCount/RequestCount]
B -- 応答速度 --> D[Latency SLO\nP99 <= 閾値のリクエスト率]
B -- エラー率 --> E[Error Rate SLO\nErrorCount/RequestCount <= 閾値]
C & D & E --> F{Burn Rate 設計}
F --> G[Fast Burn: 1h ウィンドウ\n消費速度 14× でアラート\n= Error Budget の 2% を 1h で消費]
F --> H[Slow Burn: 6h ウィンドウ\n消費速度 6× でアラート\n= Error Budget の 5% を 6h で消費]
G --> I[CloudWatch Alarm → SNS → PagerDuty P1]
H --> J[CloudWatch Alarm → SNS → PagerDuty P2]
5-3. Availability SLO Terraform 実装
resource "aws_applicationsignals_service_level_objective" "availability" {
name = "my-service-availability-slo"
sli {
sli_metric {
metric_source_config {
type = "RequestBasedSli"
request_based_sli_config {
request_based_sli_metric {
operation = "GET /api/users"
total_request_count_metric {
metric_data_queries {
id = "total"
metric_stat {
metric {
namespace= "AWS/ApplicationSignals"
metric_name = "RequestCount"
dimensions {
name = "Service"
value = "my-service"
}
}
stat= "Sum"
period = 60
}
}
}
monitored_request_count_metric {
good_count_metric {
metric_data_queries {
id = "good"
metric_stat {
metric {
namespace= "AWS/ApplicationSignals"
metric_name = "SuccessCount"
dimensions {
name = "Service"
value = "my-service"
}
}
stat= "Sum"
period = 60
}
}
}
}
}
}
}
}
}
goal {
interval {
rolling_interval {
duration_unit = "DAY"
duration= 30
}
}
attainment_goal= 99.9
warning_threshold = 99.5
}
}
CLI での SLO 確認・Error Budget レポート:
# SLO 一覧確認
aws application-signals list-service-level-objectives \
--region ap-northeast-1
# Error Budget レポート
aws application-signals batch-get-service-level-objective-budget-report \
--timestamp $(date +%s) \
--slo-ids '["my-service-availability-slo"]' \
--region ap-northeast-1
コンソール: CloudWatch → Application Signals → SLOs
5-4. Latency SLO Terraform 実装
§5-3 と同構造。monitored_request_count_metric を Latency 用に差し替え、Metric Math 式 IF(latency_p99 <= 500, total, 0) で P99 <= 500ms のリクエスト数を good として計測する。attainment_goal = 95.0 (95% 目標)。
# §5-3 から変更点のみ: name + monitored_request_count_metric + attainment_goal
resource "aws_applicationsignals_service_level_objective" "latency" {
name = "my-service-latency-slo"
# sli 構造 (total_request_count_metric) は §5-3 と同一
# monitored_request_count_metric を以下に差し替え:
# monitored_request_count_metric {
#good_count_metric {
# metric_data_queries { id="good"; expression="IF(latency_p99<=500,total,0)"; return_data=true }
# metric_data_queries {
# id="latency_p99"
# metric_stat { metric { namespace="AWS/ApplicationSignals"; metric_name="Latency"
#dimensions { name="Service"; value="my-service" } }; stat="p99"; period=60 }
# return_data = false
# }
#}
# }
goal {
interval { rolling_interval { duration_unit = "DAY"; duration = 30 } }
attainment_goal= 95.0
warning_threshold = 90.0
}
}
5-5. Error Rate SLO Terraform 実装
§5-3 と同構造。monitored_request_count_metric で bad_count_metric を使い ErrorCount を直接計測する。bad_count_metric は「エラー数が閾値超で SLO 違反」という設定に対応し、attainment_goal = 99.9 (エラー率 0.1% 以下目標)。
# §5-3 から変更点のみ: name + monitored_request_count_metric + attainment_goal
resource "aws_applicationsignals_service_level_objective" "error_rate" {
name = "my-service-error-rate-slo"
# monitored_request_count_metric を以下に差し替え:
# monitored_request_count_metric {
#bad_count_metric {
# metric_data_queries {
# id = "bad"
# metric_stat { metric { namespace="AWS/ApplicationSignals"; metric_name="ErrorCount"
#dimensions { name="Service"; value="my-service" } }; stat="Sum"; period=60 }
# }
#}
# }
goal {
interval { rolling_interval { duration_unit = "DAY"; duration = 30 } }
attainment_goal= 99.9
warning_threshold = 99.5
}
}
5-6. Burn Rate 2-window CloudWatch Alarm Terraform 実装
Error Budget の消費速度 (Burn Rate) を 1h と 6h の 2 ウィンドウで監視する。Fast Burn は短時間での急激な消費を検知し P1 アラートを発報する。Slow Burn は緩やかな消費を長期ウィンドウで検知し P2 アラートを発報する。
# Fast Burn Rate アラーム (1h window・14× 消費速度)
resource "aws_cloudwatch_metric_alarm" "slo_fast_burn" {
alarm_name = "my-service-slo-fast-burn"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
threshold = 14.0
treat_missing_data = "notBreaching"
metric_query {
id = "burn_rate"
expression = "IF(total > 0, 1 - good/total, 0)"
label = "BurnRate"
return_data = true
}
metric_query {
id = "good"
metric {
namespace= "AWS/ApplicationSignals"
metric_name = "SuccessCount"
period= 3600
stat = "Sum"
dimensions = { Service = "my-service" }
}
}
metric_query {
id = "total"
metric {
namespace= "AWS/ApplicationSignals"
metric_name = "RequestCount"
period= 3600
stat = "Sum"
dimensions = { Service = "my-service" }
}
}
alarm_description = "SLO Fast Burn: Error Budget の 2% を 1h で消費 (14× 消費速度) → P1 アラート"
alarm_actions = [aws_sns_topic.slo_alerts.arn]
ok_actions = [aws_sns_topic.slo_alerts.arn]
}
# Slow Burn Rate アラーム (6h window・6× 消費速度)
resource "aws_cloudwatch_metric_alarm" "slo_slow_burn" {
alarm_name = "my-service-slo-slow-burn"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
threshold = 6.0
treat_missing_data = "notBreaching"
metric_query {
id = "burn_rate"
expression = "IF(total > 0, 1 - good/total, 0)"
label = "BurnRate"
return_data = true
}
metric_query {
id = "good"
metric {
namespace= "AWS/ApplicationSignals"
metric_name = "SuccessCount"
period= 21600
stat = "Sum"
dimensions = { Service = "my-service" }
}
}
metric_query {
id = "total"
metric {
namespace= "AWS/ApplicationSignals"
metric_name = "RequestCount"
period= 21600
stat = "Sum"
dimensions = { Service = "my-service" }
}
}
alarm_description = "SLO Slow Burn: Error Budget の 5% を 6h で消費 (6× 消費速度) → P2 アラート"
alarm_actions = [aws_sns_topic.slo_alerts.arn]
ok_actions = [aws_sns_topic.slo_alerts.arn]
}
resource "aws_sns_topic" "slo_alerts" {
name = "my-service-slo-alerts"
}
5-7. SLO 3 種マトリクス + Burn Rate 設計チェックリスト
Availability SLO: SuccessCount / RequestCount → 99.9% 目標
Latency SLO: P99 <= 500ms のリクエスト率 → 95% 目標
Error Rate SLO: ErrorCount / RequestCount → 0.1% 未満目標
Fast Burn (1h): 14× 超過 → P1 アラート (Error Budget の 2% を 1h 消費)
Slow Burn (6h): 6× 超過 → P2 アラート (Error Budget の 5% を 6h 消費)
Error Budget 試算: 99.9% SLO → 月間 43.2 分のダウンタイム許容
5-8. 関連記事・クロスリンク
- 観測性 Vol2: X-Ray + ADOT 分散トレーシング本番運用 — ADOT Collector のメトリクスは SLI の元データとなる
- 観測性 Vol1: CloudWatch Logs Insights + Metrics Filter 本番運用 — ログ × SLO 相関分析に活用できる
6. Synthetic Canary + Real User Monitoring (RUM) + SLO 統合監視 — 外形監視と実ユーザー監視の連携
6-1. Synthetic Canary と RUM の位置付け
Application Signals の SLO はサービス内部のメトリクスを基準に計測するが、エンドポイントが外部から到達可能かどうか、実ユーザーが実際に体験するパフォーマンスはどうかを把握するには追加の監視レイヤーが必要になる。
Synthetic Canary はロボットが 5 分間隔で定期的にエンドポイントにリクエストを送信する外形監視サービスです。Application Signals SLO と連携して可用性・レスポンスタイムを独立した視点で検証し、内部メトリクスでは検出できない DNS 障害やロードバランサー異常を捕捉します。
Real User Monitoring (RUM) は実ユーザーのブラウザ操作データを収集するフロントエンド監視サービスです。JavaScript エラー率・ページロード時間・Core Web Vitals を測定し、X-Ray トレースと連携することでフロントエンドからバックエンドまでの End-to-End の SLO 補完データとして機能します。
2 つを組み合わせることで SLO の完全な可観測性が実現する。Canary が 5 分間隔で Availability SLO の外部検証データを補完し、RUM がユーザー体験ベースの Latency SLO を測定する。X-Ray トレース連携により Application Signals サービスマップ上で Canary・RUM・内部 SLO を一元可視化できる。

6-2. Synthetic Canary Terraform 実装
Canary を Terraform で実装する際は aws_synthetics_canary リソースを使用します。重要なのは active_tracing = true を設定して X-Ray と連携させる点と、Canary スクリプトを S3 経由でデプロイする点です。
resource "aws_synthetics_canary" "api_health" {
name = "my-service-api-health"
artifact_s3_location = "s3://${aws_s3_bucket.canary_artifacts.bucket}/canary/"
execution_role_arn= aws_iam_role.canary_role.arn
handler = "apiCanary.handler"
runtime_version= "syn-nodejs-puppeteer-6.2"
start_canary= true
schedule {
expression = "rate(5 minutes)"
duration_in_seconds = 0
}
run_config {
timeout_in_seconds = 60
memory_in_mb = 960
active_tracing = true
}
zip_file = data.archive_file.canary_script.output_base64sha256
tags = {
Service = "my-service"
MonitorType = "Synthetic"
}
}
resource "aws_iam_role" "canary_role" {
name = "synthetics-canary-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "lambda.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy" "canary_policy" {
role = aws_iam_role.canary_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect= "Allow"
Action= ["s3:PutObject", "s3:GetBucketLocation"]
Resource = ["${aws_s3_bucket.canary_artifacts.arn}/*"]
},
{
Effect= "Allow"
Action= ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"]
Resource = "arn:aws:logs:*:*:*"
},
{
Effect= "Allow"
Action= ["cloudwatch:PutMetricData"]
Resource = "*"
},
{
Effect= "Allow"
Action= ["xray:PutTraceSegments", "xray:PutTelemetryRecords"]
Resource = "*"
}
]
})
}
AWS CLI で Canary を操作する:
# Canary の開始
aws synthetics start-canary \
--name my-service-api-health \
--region ap-northeast-1
# Canary ステータス確認
aws synthetics get-canary \
--name my-service-api-health \
--region ap-northeast-1
# Canary 実行結果確認
aws synthetics get-canary-runs \
--name my-service-api-health \
--region ap-northeast-1
マネジメントコンソール: CloudWatch → Synthetics Canaries → Canary 詳細 → Availability タブ で成功率グラフと最新実行ログを確認できる。
6-3. Canary スクリプト例 (Node.js)
Canary スクリプトは S3 へアップロードした ZIP ファイル内に配置する。synthetics.executeHttpStep を使用してエンドポイントのヘルスチェックを実装し、期待するステータスコードが返らない場合は Error を throw して Canary を失敗扱いにする。
// apiCanary.js
const synthetics = require('Synthetics');
const log = require('SyntheticsLogger');
const apiCanary = async () => {
const requestOptions = {
hostname: 'api.example.com',
port: 443,
path: '/api/health',
method: 'GET',
protocol: 'https:'
};
const validateResponse = async (res) => {
if (res.statusCode !== 200) {
throw new Error(`Expected 200, got ${res.statusCode}`);
}
log.info('Health check passed');
};
await synthetics.executeHttpStep('HealthCheck', requestOptions, validateResponse);
};
exports.handler = async () => {
return await apiCanary();
};
6-4. Real User Monitoring (RUM) Terraform 実装
RUM の aws_rum_app_monitor リソースは監視対象ドメインを指定し、X-Ray 連携・サンプリングレート・収集テレメトリ種別を設定する。本番環境では session_sample_rate = 0.1(10%)から開始してコストを抑制する。
resource "aws_rum_app_monitor" "my_app" {
name= "my-app-rum"
domain = "app.example.com"
app_monitor_configuration {
allow_cookies = true
enable_x_ray = true
session_sample_rate = 0.1
telemetries= ["errors", "http", "performance"]
included_pages = ["https://app.example.com/*"]
excluded_pages = ["https://app.example.com/admin/*"]
}
custom_events {
status = "ENABLED"
}
}
data "aws_rum_app_monitor" "my_app" {
name = aws_rum_app_monitor.my_app.name
}
AWS CLI で RUM を操作する:
# RUM AppMonitor 作成確認
aws rum get-app-monitor \
--name my-app-rum \
--region ap-northeast-1
# RUM メトリクス確認 (直近1時間)
aws rum get-app-monitor-data \
--name my-app-rum \
--time-range "Start=$(date -d '1 hour ago' +%s),End=$(date +%s)" \
--region ap-northeast-1
マネジメントコンソール: CloudWatch → RUM → アプリモニター詳細 → Performance / Errors タブ でページロード時間・JavaScript エラー率・HTTP エラー率をリアルタイム確認できる。
6-5. RUM JavaScript スニペット (フロントエンドへの埋め込み)
RUM データ収集には HTML の <head> 内に JavaScript スニペットを埋め込む。guestRoleArn と identityPoolId は Terraform apply 後に出力される値を使用する。enableXRay: true により RUM セッションと X-Ray トレースが紐付けられる。
// HTML <head> 内に追加 — RUM クライアント初期化
import { AwsRum } from 'aws-rum-web';
try {
const config = {
sessionSampleRate: 0.1,
guestRoleArn: "arn:aws:iam::ACCOUNT_ID:role/RUM-Monitor-ap-northeast-1-XXXXXXXX",
identityPoolId: "ap-northeast-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
endpoint: "https://dataplane.rum.ap-northeast-1.amazonaws.com",
telemetries: ["performance", "errors", "http"],
allowCookies: true,
enableXRay: true
};
const APPLICATION_ID = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';
const APPLICATION_VERSION = '1.0.0';
const APPLICATION_REGION = 'ap-northeast-1';
const awsRum = new AwsRum(
APPLICATION_ID,
APPLICATION_VERSION,
APPLICATION_REGION,
config
);
} catch (error) {
// RUM 初期化エラーはアプリの動作に影響させない
}
6-6. Canary + RUM + SLO 相関監視
Canary・RUM・Application Signals SLO はそれぞれ独立したデータソースだが、CloudWatch の統合基盤上で相関させることで SLO の精度を大幅に高められる。
SLO とのマッピング:
| 監視種別 | SLO への貢献 | 確認場所 |
|---|---|---|
| Canary 成功率 | Availability SLO の外部検証データ補完 | CloudWatch Synthetics |
| Canary レスポンスタイム | Latency SLO の外形監視データ | CloudWatch メトリクス |
| RUM エラー率 | フロントエンド Error Rate SLO | CloudWatch RUM |
| RUM ページロード時間 | ユーザー体感 Latency SLO | CloudWatch RUM |
X-Ray トレース連携: Canary の active_tracing = true と RUM の enable_x_ray = true を有効化すると、Canary・RUM のリクエストが X-Ray トレースとして記録され Application Signals サービスマップ上に表示される。外形監視・実ユーザー監視・内部 SLO を一元可視化することで、サービス境界を越えた障害の根本原因分析が可能になる。
Canary が失敗し内部 SLO が正常を示す場合はネットワーク・DNS・ロードバランサーの問題を示唆する。RUM エラー率が急上昇し Canary が正常な場合は特定ユーザー環境やブラウザ起因の問題を示唆する。両方が悪化する場合はサービス全体の障害として Error Budget の消費速度を確認しアラートの優先度を上げる。
Synthetic Canary:
- aws_synthetics_canary で 5 分間隔 + active_tracing=true 設定済みか
- Canary スクリプトでエンドポイント死活 + ステータスコード確認が実装されているか
- S3 アーティファクトバケット + IAM ロールが Terraform で管理されているか
Real User Monitoring:
- aws_rum_app_monitor でドメイン指定 + X-Ray 連携 (enable_x_ray=true) が有効か
- RUM JavaScript スニペットがフロントエンドの <head> に埋め込まれているか
- セッションサンプリングレートが適切に設定されているか (推奨 10%)
SLO 連携:
- Canary 成功率が Availability SLO の補完指標として CloudWatch で確認できるか
- RUM エラー率がフロントエンド Error Rate SLO に反映されているか
- CloudWatch → Application Signals → SLO で統合確認できるか
6-7. クロスリンク
- X-Ray + ADOT 分散トレーシング本番運用 (観測性 Vol2) — Canary の active_tracing と RUM の enableXRay の前提となる X-Ray トレース連携の詳細
- CloudWatch Logs Insights + Metrics Filter 本番運用 (観測性 Vol1) — Canary 実行ログを Logs Insights で分析する手法
- Lambda Powertools Layers 本番運用 (Lambda Vol3) — RUM + Lambda Powertools の組み合わせによるフルスタック可観測性
7. Burn Rate アラート → PagerDuty / OpsGenie 自動エスカレーション + コスト最適化

SLO Error Budget が急速に消費されたとき(Burn Rate 超過)、人間の目が届く前に自動でインシデント管理ツールに通知することで、対応時間を最小化できます。本章では CloudWatch Alarm → SNS → Lambda → PagerDuty/OpsGenie の完全実装を解説します。
7-1. Fast/Slow Burn Rate アラームの復習
§5 で実装した 2-window アラーム構成をエスカレーションに接続します。
| ウィンドウ | 倍率 | 意味 | 緊急度 |
|---|---|---|---|
| Fast Burn (1h) | 14× | Error Budget の 2% を 1 時間で消費 | 緊急 (P1) |
| Slow Burn (6h) | 6× | Error Budget の 5% を 6 時間で消費 | 注意 (P2) |
7-2. SNS トピック + Lambda エスカレーター Terraform 実装
# SNS トピック (Burn Rate アラーム → Lambda 受信)
resource "aws_sns_topic" "slo_burn_rate" {
name = "slo-burn-rate-alerts"
}
resource "aws_sns_topic_subscription" "lambda_escalator" {
topic_arn = aws_sns_topic.slo_burn_rate.arn
protocol = "lambda"
endpoint = aws_lambda_function.slo_escalator.arn
}
resource "aws_lambda_permission" "sns_invoke" {
statement_id = "AllowSNSInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.slo_escalator.function_name
principal = "sns.amazonaws.com"
source_arn = aws_sns_topic.slo_burn_rate.arn
}
# エスカレーター Lambda (PagerDuty / OpsGenie 両対応)
resource "aws_lambda_function" "slo_escalator" {
function_name = "slo-burn-rate-escalator"
runtime = "python3.12"
handler = "escalator.handler"
filename= "escalator.zip"
role = aws_iam_role.escalator_role.arn
environment {
variables = {
PAGERDUTY_ROUTING_KEY = var.pagerduty_routing_key
OPSGENIE_API_KEY= var.opsgenie_api_key
ESCALATION_TARGET = var.escalation_target # "pagerduty" or "opsgenie"
}
}
}
# CloudWatch Alarm → SNS 接続 (§5 の Fast Burn アラーム)
resource "aws_cloudwatch_metric_alarm" "slo_fast_burn_with_sns" {
alarm_name = "my-service-slo-fast-burn"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
threshold = 14.0
treat_missing_data = "notBreaching"
metric_query {
id = "burn_rate"
expression = "IF(total > 0, 1 - good/total, 0)"
return_data = true
}
metric_query {
id = "good"
metric {
namespace= "AWS/ApplicationSignals"
metric_name = "SuccessCount"
period= 3600
stat = "Sum"
dimensions = { Service = "my-service" }
}
}
metric_query {
id = "total"
metric {
namespace= "AWS/ApplicationSignals"
metric_name = "RequestCount"
period= 3600
stat = "Sum"
dimensions = { Service = "my-service" }
}
}
alarm_actions = [aws_sns_topic.slo_burn_rate.arn]
ok_actions = [aws_sns_topic.slo_burn_rate.arn]
}
7-3. Lambda エスカレーター実装 (PagerDuty / OpsGenie 両対応)
# escalator.py
import json
import os
import urllib.request
import urllib.parse
def handler(event, context):
for record in event['Records']:
message = json.loads(record['Sns']['Message'])
alarm_name = message.get('AlarmName', 'Unknown')
alarm_state = message.get('NewStateValue', 'ALARM')
description = message.get('NewStateReason', '')
severity = 'critical' if 'fast-burn' in alarm_name.lower() else 'warning'
target= os.environ.get('ESCALATION_TARGET', 'pagerduty')
if alarm_state == 'ALARM':
if target == 'pagerduty':
_trigger_pagerduty(alarm_name, description, severity)
else:
_trigger_opsgenie(alarm_name, description, severity)
elif alarm_state == 'OK':
if target == 'pagerduty':
_resolve_pagerduty(alarm_name)
else:
_resolve_opsgenie(alarm_name)
def _trigger_pagerduty(alarm_name, description, severity):
"""PagerDuty Events API v2"""
payload = {
'routing_key': os.environ['PAGERDUTY_ROUTING_KEY'],
'event_action': 'trigger',
'payload': {
'summary': f'SLO Burn Rate Alert: {alarm_name}',
'severity': severity, # 'critical' or 'warning'
'source':'AWS CloudWatch Application Signals',
'custom_details': {'description': description}
},
'dedup_key': alarm_name
}
_post('https://events.pagerduty.com/v2/enqueue', payload)
def _resolve_pagerduty(alarm_name):
payload = {
'routing_key': os.environ['PAGERDUTY_ROUTING_KEY'],
'event_action': 'resolve',
'dedup_key': alarm_name
}
_post('https://events.pagerduty.com/v2/enqueue', payload)
def _trigger_opsgenie(alarm_name, description, severity):
"""OpsGenie Alerts API v2"""
payload = {
'message': f'SLO Burn Rate Alert: {alarm_name}',
'alias': alarm_name,
'priority': 'P1' if severity == 'critical' else 'P2',
'source':'AWS CloudWatch Application Signals',
'description': description
}
_post(
'https://api.opsgenie.com/v2/alerts',
payload,
headers={'Authorization': f"GenieKey {os.environ['OPSGENIE_API_KEY']}"}
)
def _resolve_opsgenie(alarm_name):
encoded = urllib.parse.quote(alarm_name)
_post(
f'https://api.opsgenie.com/v2/alerts/{encoded}/close?identifierType=alias',
{},
headers={'Authorization': f"GenieKey {os.environ['OPSGENIE_API_KEY']}"}
)
def _post(url, payload, headers=None):
data = json.dumps(payload).encode()
req = urllib.request.Request(url, data=data, method='POST')
req.add_header('Content-Type', 'application/json')
if headers:
for k, v in headers.items():
req.add_header(k, v)
with urllib.request.urlopen(req, timeout=10) as resp:
return json.loads(resp.read())
AWS CLI (テスト):
# SNS 経由でアラームをシミュレート
aws sns publish \
--topic-arn $(terraform output -raw slo_sns_topic_arn) \
--message '{"AlarmName":"test-fast-burn","NewStateValue":"ALARM","NewStateReason":"Burn Rate 15x"}' \
--region ap-northeast-1
# Lambda ログ確認
aws logs tail /aws/lambda/slo-burn-rate-escalator \
--follow --region ap-northeast-1
コンソール: CloudWatch → Alarms → アラーム状態確認 → SNS → Lambda ログ
7-4. コスト最適化 5 項目
Application Signals 環境全体のコスト試算と削減策を整理します。
| コスト項目 | 概算 (月間) | 最適化策 |
|---|---|---|
| Application Signals メトリクス | $5-20 (サービス数 × リクエスト量依存) | Canary リクエストは SLI から除外設定 |
| Synthetic Canary | $0.0012/実行 × 8,640回/月 ≒ $10.4 (5分間隔) | 非本番は 15分間隔に変更で $3.5 に削減 |
| RUM | $1/1万セッション → 10万セッション/月 ≒ $10 | セッションサンプリングを 5% に落とす |
| CloudWatch Alarms | $0.10/アラーム × 6アラーム ≒ $0.6 | Burn Rate 2-window を 1-window に統合 (SLO 小規模時) |
| SNS + Lambda | < $1 (イベント発生頻度依存) | 正常時のコストはほぼゼロ |
コスト最適化の優先順位:
1. Canary 実行頻度を非本番環境で 15分間隔に変更 → $7/月削減
2. RUM セッションサンプリングを 10% → 5% に変更 → $5/月削減
3. Application Signals メトリクス: 不要なカスタムメトリクスを削除
# 現在の Application Signals コスト確認
aws ce get-cost-and-usage \
--time-period Start=$(date -d '1 month ago' +%Y-%m-01),End=$(date +%Y-%m-01) \
--granularity MONTHLY \
--filter '{"Dimensions":{"Key":"SERVICE","Values":["AmazonCloudWatch"]}}' \
--metrics BlendedCost \
--region ap-northeast-1
7-5. トラブルシュート 10 選
| # | 症状 | 原因 | 対処法 |
|---|---|---|---|
| 1 | Application Signals にサービスが表示されない | ADOT Collector が Application Signals exporter に送出していない | collector.yaml の exporters に awsapplicationsignals を追加 |
| 2 | SLO の SuccessCount が 0 のまま | Lambda Layer の OTEL_AWS_APPLICATION_SIGNALS_ENABLED が未設定 | 環境変数 OTEL_AWS_APPLICATION_SIGNALS_ENABLED=true を設定 |
| 3 | Burn Rate アラームが誤発火する | total メトリクスが 0 のとき division by zero | IF(total > 0, 1 – good/total, 0) 式で 0 除算を回避 |
| 4 | EKS で amazon-cloudwatch-observability Add-on が起動しない | IAM IRSA 権限不足 | CloudWatchAgentServerPolicy が IRSA ロールにアタッチされているか確認 |
| 5 | Canary が Timeout エラーを繰り返す | VPC 内エンドポイントへのアクセス設定漏れ | Canary の VPC Config + Security Group + NAT Gateway/Endpoint を確認 |
| 6 | RUM JavaScript を埋め込んだが CloudWatch にデータが来ない | CORS ポリシーまたは identityPoolId の誤り | RUM AppMonitor の許可オリジン設定と Cognito Identity Pool 設定を確認 |
| 7 | SLO Error Budget が予期せず急減している | Canary のリクエストが SLI に含まれている | Canary リクエストを SLO の除外フィルタに追加 |
| 8 | PagerDuty インシデントが重複作成される | dedup_key が都度変わっている | dedup_key にアラーム名 (固定値) を使用 |
| 9 | aws_applicationsignals_service_level_objective が plan/apply でエラー | AWS Provider バージョンが古い (5.x 未満) | terraform providers → AWS Provider >= 5.x にアップグレード |
| 10 | SLO の Attainment が 100% なのに Burn Rate アラームが発火する | evaluation_periods の設定が短すぎてノイズを拾っている | evaluation_periods を 2-3 に増やしてノイズ耐性を向上 |
Burn Rate エスカレーション:
– [ ] Fast Burn (1h × 14×) → SNS → Lambda → PagerDuty/OpsGenie P1
– [ ] Slow Burn (6h × 6×) → SNS → Lambda → PagerDuty/OpsGenie P2
– [ ] dedup_key にアラーム名固定値を設定 (重複インシデント防止)
– [ ] Lambda escalator に OK アクション (resolve) も設定
コスト最適化:
– [ ] Canary 非本番は 15分間隔に変更 ($7/月削減)
– [ ] RUM セッションサンプリング 5-10%
– [ ] 不要 Application Signals メトリクス削除
– [ ] aws ce get-cost-and-usage で月次コスト確認
クロスリンク:
– 観測性 Vol2 X-Ray + ADOT 分散トレーシング基盤 — §7 Burn Rate アラームの SLI データは ADOT Collector が収集
– 観測性 Vol1 CloudWatch Logs Insights — Lambda escalator のログを Logs Insights で分析
8. まとめ + 観測性 3 部作完結宣言 + 9 巻 AWS 本番運用シリーズ完結 + 落とし穴 10 選
8-1. 本記事のまとめ
本記事では CloudWatch Application Signals + SLO を使った本番観測性の第 3 層として以下を実装しました。
| 実装内容 | 主要リソース |
|---|---|
| Application Signals 有効化 (Lambda/ECS/EKS) | ADOT Layer / サイドカー / EKS Add-on |
| SLO 3 種 Terraform 定義 | aws_applicationsignals_service_level_objective |
| Burn Rate 2-window アラーム | aws_cloudwatch_metric_alarm (1h/6h) |
| Synthetic Canary 外形監視 | aws_synthetics_canary (5分間隔) |
| Real User Monitoring | aws_rum_app_monitor |
| PagerDuty/OpsGenie 自動エスカレーション | SNS + Lambda escalator |
8-2. 観測性 3 部作完結
- Vol1 (ログ層): CloudWatch Logs Insights + Metrics Filter 本番運用
構造化ログ → Logs Insights クエリ → メトリクスフィルタ → CloudWatch Alarm - Vol2 (トレース層): X-Ray + ADOT 分散トレーシング基盤
ADOT Collector → X-Ray → ServiceLens → サービスマップ + Trace Analytics - Vol3 (SLO 層・本記事): CloudWatch Application Signals + SLO 本番運用
Application Signals → SLO 3種 + Error Budget → Burn Rate → PagerDuty/OpsGenie
3 層が揃うことで「なぜ SLO が割れたか」をログ (Vol1) + トレース (Vol2) で根本原因まで追跡できる完全な観測性スタックが完成します。
8-3. 9 巻 AWS 本番運用シリーズ完結
- Lambda 本番運用 3 部作
- EKS 本番運用 3 部作
- 観測性本番運用 3 部作
- Vol1: CloudWatch Logs Insights + Metrics Filter 本番運用
- Vol2: X-Ray + ADOT 分散トレーシング本番運用
- Vol3: Application Signals + SLO 本番運用 (本記事)
8-4. 落とし穴 10 選
| # | 落とし穴 | 回避策 |
|---|---|---|
| 1 | Application Signals を有効化したが SLO のデータが空 | ADOT Collector に awsapplicationsignals exporter を追加し、application-signals:PutServiceData IAM 権限を付与 |
| 2 | SLO の Availability が常に 100% で現実と乖離 | Canary リクエストを SLI から除外し、実ユーザーリクエストのみで計測 |
| 3 | Burn Rate アラームが発火しすぎる (ノイズ) | evaluation_periods を 2-3 に増やし、treat_missing_data = “notBreaching” を設定 |
| 4 | Error Budget が月末にゼロになる | Rolling 30日間隔で計算し、月初にリセットされると勘違いしないよう注意 |
| 5 | Latency SLO の P99 が外れ値で常に割れる | P99 ではなく P95 で SLO を設定し、単発スパイクを許容する設計に |
| 6 | RUM セッションサンプリングを 100% にしてコスト爆発 | 初期は 5-10% から始め、データ量を確認してから調整 |
| 7 | Canary が VPC 内 API にアクセスできない | Canary の VPC Config を設定し、セキュリティグループで HTTPS 通信を許可 |
| 8 | PagerDuty インシデントが OK 後も残る | Lambda escalator の OK アクション (_resolve) 処理を必ず実装 |
| 9 | SLO Terraform resource で provider エラー | AWS Provider を 5.x 以上に固定 (aws_applicationsignals_service_level_objective は最新 Provider が必要) |
| 10 | 9 巻全記事のクロスリンクが古い URL | Phase5 で各記事の ep-btn URL を最新記事に更新 (観測性 3 部作完結時) |
8-5. SLO 運用成熟度モデル
SLO を導入したばかりのチームが段階的に成熟する 4 段階ロードマップを示します。
| レベル | 状態 | 次のアクション |
|---|---|---|
| Lv.0 (計測なし) | SLI/SLO 未定義。障害時に「どこが壊れたか」がわからない | Vol1 ログ + Vol2 トレースから始める |
| Lv.1 (可視化) | Application Signals でサービスマップとメトリクスが見える | SLO 1 種 (Availability) を定義し Error Budget を算出 |
| Lv.2 (アラート) | Burn Rate アラームで事前検知できる | 2-window (Fast/Slow) を実装し PagerDuty 連携 |
| Lv.3 (自動化) | Error Budget 消費に応じてデプロイ速度を自動調整 | Canary + RUM + SLO 統合でリリースゲートを自動化 |
本記事では Lv.1 → Lv.2 → Lv.3 への移行を Terraform IaC で一気通貫に実装しました。
8-6. Application Signals を本番採用する際の判断基準
Application Signals の導入コストと得られる価値のトレードオフを整理します。
導入を強く推奨するケース:
– Lambda / ECS / EKS のいずれかで ADOT (Vol2) を既に導入済みの場合 → 追加設定のみで SLO 化できる
– 複数サービス間の依存関係が複雑で「どのサービスの SLO が割れているか」を一元把握したい
– SRE チームが Error Budget に基づいたリリース判断プロセスを整備しようとしている
導入を見送る / 段階的に進めるケース:
– 単一 Lambda 関数のみで CloudWatch Alarms が十分に機能している場合
– トラフィックが月 1 万リクエスト未満でコストメリットが薄い場合 (CloudWatch Metrics の方が安価)
– ADOT Collector の運用経験がなく Vol2 が未実施の場合 → Vol2 を先に完了させる
8-7. コマンドチートシート
# Application Signals サービス一覧
aws application-signals list-services \
--start-time $(date -d '1 hour ago' +%s) --end-time $(date +%s) --region ap-northeast-1
# SLO 一覧
aws application-signals list-service-level-objectives --region ap-northeast-1
# Error Budget レポート
aws application-signals batch-get-service-level-objective-budget-report \
--timestamp $(date +%s) --slo-ids '["my-service-availability-slo"]' --region ap-northeast-1
# Canary ステータス
aws synthetics get-canary --name my-service-api-health --region ap-northeast-1
# RUM AppMonitor 確認
aws rum get-app-monitor --name my-app-rum --region ap-northeast-1
# コスト確認
aws ce get-cost-and-usage \
--time-period Start=$(date -d '1 month ago' +%Y-%m-01),End=$(date +%Y-%m-01) \
--granularity MONTHLY \
--filter '{"Dimensions":{"Key":"SERVICE","Values":["AmazonCloudWatch"]}}' \
--metrics BlendedCost --region ap-northeast-1
Vol2 を読む: X-Ray + ADOT 分散トレーシング基盤