目次
AWSオブザーバビリティ運用ランブック
周辺資料: 学習インデックス · AWSサービス一覧(2026) · セキュリティ設計ハンドブック · Well-Architectedチェックリスト
メトリクス・ログ・トレースの設計から障害対応手順まで、AWS オブザーバビリティの実践ランブック。
1. オブザーバビリティの3本柱
[Metrics(メトリクス)]
何が起きているか(数値の変化)
ツール: CloudWatch Metrics / Embedded Metrics Format
対象: CPU/メモリ/レイテンシ/エラー率/スループット
[Logs(ログ)]
なぜ起きているか(イベントの記録)
ツール: CloudWatch Logs / OpenSearch Service
対象: アクセスログ / アプリログ / 監査ログ
[Traces(トレース)]
どこで起きているか(リクエストの経路)
ツール: AWS X-Ray / CloudWatch ServiceLens
対象: マイクロサービス間のレイテンシ / エラー伝播
[ビジネス KPI]
ビジネス影響の把握
ツール: QuickSight / CloudWatch ダッシュボード(カスタムメトリクス)
対象: DAU / 購入完了率 / 決済成功率
2. CloudWatch 監視設計
アラーム設計の優先順位
[アラーム優先度の判断軸]
P1(即座に対応): ユーザーへの影響が継続している
P2(30分以内に対応): 影響が局所的または潜在的
P3(翌営業日に対応): 警告・予防的な通知
[優先度 P1 の例]
- ALB 5XX エラー率 > 1%(5分間継続)
- API レスポンスタイム P99 > 5秒(3分間継続)
- RDS 接続数 > 最大接続数の 80%
- ECS サービスの Running タスク数 = 0
[優先度 P2 の例]
- Lambda エラー率 > 5%(10分間)
- SQS DLQ メッセージ数 > 0
- EC2 CPU 使用率 > 85%(15分間継続)
- Aurora フェイルオーバー発生
[優先度 P3 の例]
- S3 バケット容量 > 1TB
- Lambda コールドスタート率上昇
- Savings Plans カバレッジ低下
CloudWatch アラーム設定パターン
import boto3
class ObservabilitySetup:
def __init__(self):
self.cw = boto3.client('cloudwatch')
self.sns_arn = 'arn:aws:sns:ap-northeast-1:123456789:alerts'
def create_api_latency_alarm(self, api_name: str, threshold_ms: float = 2000):
"""API レイテンシアラーム(P99)"""
self.cw.put_metric_alarm(
AlarmName=f'{api_name}-latency-p99-high',
AlarmDescription='API P99 レイテンシが閾値超過',
MetricName='TargetResponseTime',
Namespace='AWS/ApplicationELB',
Statistic='p99',
Period=300,
EvaluationPeriods=2,
Threshold=threshold_ms / 1000,
ComparisonOperator='GreaterThanThreshold',
ExtendedStatistic='p99',
AlarmActions=[self.sns_arn],
OKActions=[self.sns_arn],
TreatMissingData='notBreaching'
)
def create_error_rate_alarm(self, service_name: str, threshold_pct: float = 1.0):
"""5XX エラー率アラーム(Metric Math)"""
self.cw.put_metric_alarm(
AlarmName=f'{service_name}-error-rate-high',
AlarmDescription=f'5XXエラー率が{threshold_pct}%超',
Metrics=[
{
'Id': 'errors',
'MetricStat': {
'Metric': {
'Namespace': 'AWS/ApplicationELB',
'MetricName': 'HTTPCode_Target_5XX_Count',
},
'Period': 300,
'Stat': 'Sum'
}
},
{
'Id': 'requests',
'MetricStat': {
'Metric': {
'Namespace': 'AWS/ApplicationELB',
'MetricName': 'RequestCount',
},
'Period': 300,
'Stat': 'Sum'
}
},
{
'Id': 'error_rate',
'Expression': 'errors / requests * 100',
'Label': 'ErrorRate'
}
],
ComparisonOperator': 'GreaterThanThreshold',
Threshold=threshold_pct,
EvaluationPeriods=2,
DatapointsToAlarm=2,
AlarmActions=[self.sns_arn],
TreatMissingData='notBreaching'
)
def create_composite_alarm(self, service_name: str):
"""複合アラーム(複数条件のAND/OR)"""
self.cw.put_composite_alarm(
AlarmName=f'{service_name}-service-degraded',
AlarmDescription='サービス劣化検知(レイテンシ上昇 AND エラー率上昇)',
AlarmRule=(
f'ALARM("{service_name}-latency-p99-high") '
f'AND ALARM("{service_name}-error-rate-high")'
),
AlarmActions=[self.sns_arn]
)
def create_anomaly_detector_alarm(self, metric_name: str, namespace: str):
"""異常検知アラーム(機械学習ベースの動的しきい値)"""
# まず異常検知モデルを作成
self.cw.put_anomaly_detector(
Namespace=namespace,
MetricName=metric_name,
Stat='Average',
Configuration={
'ExcludedTimeRanges': [],
'MetricTimezone': 'Asia/Tokyo'
}
)
# 異常検知アラームを設定(バンドの外側でアラーム)
self.cw.put_metric_alarm(
AlarmName=f'{metric_name}-anomaly',
AlarmDescription='異常検知: 通常範囲を逸脱',
Metrics=[
{
'Id': 'actual',
'MetricStat': {
'Metric': {'Namespace': namespace, 'MetricName': metric_name},
'Period': 300,
'Stat': 'Average'
}
},
{
'Id': 'anomaly_band',
'Expression': 'ANOMALY_DETECTION_BAND(actual, 2)'
}
],
ComparisonOperator='GreaterThanUpperThreshold',
ThresholdMetricId='anomaly_band',
EvaluationPeriods=3,
AlarmActions=[self.sns_arn],
TreatMissingData='notBreaching'
)
CloudWatch ダッシュボード設計
[ゴールデンシグナルダッシュボード(Google SRE 4指標)]
行1: サービスの健全性サマリ
├── Latency P50/P95/P99(折れ線グラフ)
├── Error Rate(面グラフ、赤色)
├── Traffic(リクエスト数/分)
└── Saturation(CPU/メモリ使用率)
行2: アプリケーション詳細
├── Lambda: Duration / Error / Throttle / ConcurrentExecutions
├── ECS: CPUUtilization / MemoryUtilization / TaskCount
└── ALB: ActiveConnectionCount / HealthyHostCount
行3: データ層
├── RDS: CPUUtilization / DatabaseConnections / ReadLatency / WriteLatency
├── ElastiCache: CurrConnections / CacheHits / CacheMisses / Evictions
└── DynamoDB: SuccessfulRequestLatency / ThrottledRequests
行4: インフラ
├── SQS: NumberOfMessagesSent / ApproximateNumberOfMessagesVisible / NumberOfMessagesSentToDLQ
└── CloudFront: Requests / ErrorRate / OriginLatency
3. CloudWatch Logs 活用
ログ収集設計
[ログの種類と収集先]
アプリケーションログ:
ECS/Fargate → awslogs ドライバー → CloudWatch Logs
Lambda → 自動で /aws/lambda/<function-name> に送信
EC2 → CloudWatch Logs Agent(CWAgent)でストリーム
アクセスログ:
ALB → S3(バケット policy で強制)+ CloudWatch Logs(Firehose経由)
CloudFront → S3 + Kinesis Firehose → OpenSearch
監査ログ:
CloudTrail → S3(全リージョン)+ CloudWatch Logs(アラーム連携)
VPC Flow Logs → S3 or CloudWatch Logs
[ログフォーマット標準化]
推奨: JSON 形式(CloudWatch Logs Insights でクエリ可能)
必須フィールド: timestamp / level / requestId / userId / action / message
例:
{
"timestamp": "2026-04-20T10:30:00Z",
"level": "ERROR",
"requestId": "abc-123",
"userId": "user-456",
"action": "CreateOrder",
"message": "Payment service timeout",
"latencyMs": 5002
}
CloudWatch Logs Insights クエリ集
-- エラー率の時系列(1時間ごと)
fields @timestamp, @message
| filter level = "ERROR"
| stats count() as errorCount by bin(1h)
| sort @timestamp desc
-- レイテンシのパーセンタイル分布
fields @timestamp, latencyMs
| filter ispresent(latencyMs)
| stats
avg(latencyMs) as avgLatency,
pct(latencyMs, 50) as p50,
pct(latencyMs, 95) as p95,
pct(latencyMs, 99) as p99
by bin(5m)
-- ユーザーIDごとのエラー数(上位10)
fields userId, @message
| filter level = "ERROR"
| stats count() as errorCount by userId
| sort errorCount desc
| limit 10
-- 特定のアクションに対するレスポンスタイム
fields action, latencyMs
| filter action = "CreateOrder"
| stats avg(latencyMs), max(latencyMs), min(latencyMs), count() by bin(5m)
-- 最近30分のエラーメッセージを集約
fields @timestamp, message
| filter level = "ERROR" and @timestamp > ago(30m)
| stats count() as cnt by message
| sort cnt desc
| limit 20
-- Lambda コールドスタートの検出
fields @timestamp, @message
| filter @message like /Init Duration/
| parse @message "Init Duration: * ms" as initDuration
| stats avg(initDuration), max(initDuration), count() by bin(1h)
メトリクスフィルターの設定例
def setup_metric_filters(log_group_name: str):
logs = boto3.client('logs')
# エラー率のカスタムメトリクス
logs.put_metric_filter(
logGroupName=log_group_name,
filterName='ErrorCount',
filterPattern='{ $.level = "ERROR" }',
metricTransformations=[{
'metricName': 'ErrorCount',
'metricNamespace': 'MyApp/Errors',
'metricValue': '1',
'defaultValue': 0,
'unit': 'Count'
}]
)
# 特定のビジネスイベント(注文完了)をメトリクス化
logs.put_metric_filter(
logGroupName=log_group_name,
filterName='OrderCompleted',
filterPattern='{ $.action = "OrderCompleted" }',
metricTransformations=[{
'metricName': 'OrderCompletedCount',
'metricNamespace': 'MyApp/Business',
'metricValue': '1',
'defaultValue': 0,
'unit': 'Count'
}]
)
# レイテンシのカスタムメトリクス(Embedded Metrics Format 推奨)
logs.put_metric_filter(
logGroupName=log_group_name,
filterName='RequestLatency',
filterPattern='[timestamp, level, ..., latencyMs]',
metricTransformations=[{
'metricName': 'RequestLatency',
'metricNamespace': 'MyApp/Performance',
'metricValue': '$latencyMs',
'unit': 'Milliseconds'
}]
)
4. AWS X-Ray によるトレース
X-Ray 設計パターン
[分散トレースの流れ]
Client → API Gateway(X-Ray Tracing有効)
│ TraceID ヘッダーを付与
Lambda(X-Ray SDK)
│ サービスマップにセグメント追加
ECS / EC2(X-Ray デーモン起動)
│
DynamoDB / RDS / S3(サブセグメント)
[X-Ray サンプリングルール]
本番環境:
固定レート: 5%(コスト削減)
上限: 5 req/s(最初の5件は必ずサンプル)
開発環境:
固定レート: 100%(全トレースを収集)
エラー/スロースタート:
エラー: 常にサンプル(SampledCount > 0 の条件)
遅延 > 5秒: 常にサンプル
X-Ray SDK の実装例
from aws_xray_sdk.core import xray_recorder, patch_all
from aws_xray_sdk.core.context import Context
import boto3
# AWS SDK のすべての呼び出しを自動計測
patch_all()
@xray_recorder.capture('process_order')
def process_order(order_id: str, user_id: str):
"""X-Ray でトレースするビジネスロジック"""
# カスタムアノテーション(フィルタリング可能)
xray_recorder.current_subsegment().put_annotation('order_id', order_id)
xray_recorder.current_subsegment().put_annotation('user_id', user_id)
# カスタムメタデータ(詳細情報、フィルタ不可)
xray_recorder.current_subsegment().put_metadata('request', {
'order_id': order_id,
'timestamp': '2026-04-20T10:30:00Z'
})
# サブセグメントで処理を分割
with xray_recorder.in_subsegment('validate_inventory'):
inventory_check = check_inventory(order_id)
with xray_recorder.in_subsegment('process_payment'):
payment_result = process_payment(user_id)
return {'order_id': order_id, 'status': 'completed'}
# Lambda ハンドラー
def lambda_handler(event, context):
xray_recorder.configure(service='order-service')
order_id = event.get('order_id')
user_id = event.get('user_id')
result = process_order(order_id, user_id)
return result
CloudWatch ServiceLens の活用
[ServiceLens = X-Ray トレース + CloudWatch メトリクス/ログの統合ビュー]
サービスマップ:
→ 各サービス間の依存関係と健全性を可視化
→ ノードの色: 緑(正常)/ 黄(警告)/ 赤(エラー)
トレース分析:
→ エラーになったリクエストのみフィルタ
→ レイテンシ上位 5% のリクエストを特定
→ 特定のユーザーのリクエスト経路を追跡
[実践的なX-Ray クエリ]
フィルタ式:
エラーのみ: error = true
高レイテンシ: duration > 5
特定ユーザー: annotation.user_id = "user-123"
特定サービス: service("order-service") { error = true }
5. SLO(サービスレベル目標)の設計と監視
SLI / SLO / SLA の定義
[SLI(Service Level Indicator): 測定する指標]
可用性: 成功レスポンス数 / 全リクエスト数 × 100
レイテンシ: P99 レスポンスタイム < 2秒の割合
エラー率: 5XX / 全レスポンス × 100
[SLO(Service Level Objective): 内部目標値]
可用性: 99.9%(月次 43分のダウンタイム許容)
レイテンシ: P99 < 2秒 を 99% の時間維持
エラー率: < 0.1% を 99.9% の時間維持
[Error Budget(エラーバジェット)]
99.9% SLO の場合:
月間エラーバジェット = (1 - 0.999) × 30日 × 24時間 × 60分 = 43.2分
バジェット消費率が 50% を超えたら警告
100% 消費 → 新機能リリース凍結・信頼性改善にリソース集中
SLO モニタリングの実装
def calculate_slo_compliance(service_name: str, period_days: int = 30):
"""SLO 達成率を計算する"""
cw = boto3.client('cloudwatch')
end_time = datetime.now()
start_time = end_time - timedelta(days=period_days)
# 成功リクエスト数
success_response = cw.get_metric_statistics(
Namespace='AWS/ApplicationELB',
MetricName='HTTPCode_Target_2XX_Count',
StartTime=start_time,
EndTime=end_time,
Period=period_days * 86400,
Statistics=['Sum']
)
# 全リクエスト数
total_response = cw.get_metric_statistics(
Namespace='AWS/ApplicationELB',
MetricName='RequestCount',
StartTime=start_time,
EndTime=end_time,
Period=period_days * 86400,
Statistics=['Sum']
)
if total_response['Datapoints'] and success_response['Datapoints']:
total = total_response['Datapoints'][0]['Sum']
success = success_response['Datapoints'][0]['Sum']
slo_pct = success / total * 100
slo_target = 99.9
error_budget_used = max(0, (slo_target - slo_pct) / (100 - slo_target) * 100)
return {
'service': service_name,
'availability': round(slo_pct, 4),
'slo_target': slo_target,
'compliant': slo_pct >= slo_target,
'error_budget_used_pct': round(error_budget_used, 1)
}
6. 障害対応ランブック
インシデント重大度分類
| 重大度 | 定義 | 対応時間 | 対応者 |
|---|---|---|---|
| P1(Critical) | 本番サービス全停止 / 重大データ漏洩 | 即時(5分以内) | オンコール + エスカレ |
| P2(High) | 本番機能の一部停止 / 著しい性能劣化 | 30分以内 | オンコール |
| P3(Medium) | 非重要機能の停止 / 予兆アラート | 翌営業日 | 担当チーム |
| P4(Low) | 警告・最適化機会 | 1週間以内 | 担当チーム |
障害初動フロー
[Step 1: アラート受信(0〜5分)]
1. アラートの重大度(P1/P2/P3)を確認
2. 同一アラートが重複していないかチェック
3. 他のオンコールへの事前連絡(P1のみ)
4. インシデント管理ツール(PagerDuty/Opsgenie)でチケット作成
[Step 2: 影響範囲確認(5〜15分)]
□ CloudWatch ダッシュボードでゴールデンシグナル確認
□ X-Ray サービスマップでエラー伝播の経路確認
□ 直近のデプロイ履歴確認(CodePipeline/CodeDeploy)
□ AWS Health Dashboard で AWS 側障害がないか確認
□ 影響ユーザー数・影響機能を特定
[Step 3: 初期対応(15〜30分)]
□ ロールバック可能か判断(直近デプロイが原因なら即ロールバック)
□ フェイルオーバー可能か判断(AZ / リージョン)
□ 緊急スケールアウト(EC2 Auto Scaling / ECS タスク数増加)
□ ステータスページ更新(ユーザーへの通知)
[Step 4: 根本原因分析(30分〜解決)]
□ CloudWatch Logs Insights でエラーログを分析
□ X-Ray トレースで高レイテンシ / エラーの経路を特定
□ RDS Performance Insights でスロークエリを確認
□ Detective で異常な API 呼び出しパターンを調査(セキュリティ起因の場合)
[Step 5: 復旧確認]
□ ゴールデンシグナルが正常値に戻ったか確認
□ エラーバジェットの消費を記録
□ ステータスページをクリア
□ ポストモーテム(事後分析)のスケジュールを設定(24時間以内)
よくある障害パターンと診断手順
| 症状 | 原因候補 | 確認コマンド / CloudWatch メトリクス |
|---|---|---|
| ALB 5XX 急増 | ECS タスク不足 / アプリエラー | ECS: RunningTaskCount / CloudWatch Logs: エラーログ |
| RDS 応答遅延 | スロークエリ / 接続数上限 | Performance Insights: Top SQL / DatabaseConnections |
| Lambda タイムアウト | 外部API遅延 / メモリ不足 | X-Ray: 外部呼び出しのレイテンシ / Duration P99 |
| SQS メッセージ滞留 | コンシューマ処理不足 / エラーループ | ApproximateNumberOfMessagesVisible / NumberOfMessagesSentToDLQ |
| EC2 CPU 100% | メモリリーク / バースト処理 | CloudWatch: CPUUtilization / CWAgent: mem_used_percent |
| CloudFront 5XX | オリジン障害 / WAF ブロック | Origin5xxErrorRate / WAF ブロックカウント |
| DynamoDB スロットリング | WCU/RCU 不足 / Hot Partition | ConsumedWriteCapacityUnits / ThrottledRequests |
| ElastiCache 高ミス率 | TTL 期限切れ / キャパシティ不足 | CacheMisses / Evictions / CurrConnections |
7. ポストモーテム(事後分析)テンプレート
## インシデント事後分析
### 概要
- インシデントID: INC-YYYY-NNN
- 発生日時: YYYY-MM-DD HH:MM JST
- 解決日時: YYYY-MM-DD HH:MM JST
- 重大度: P1 / P2 / P3
- 影響ユーザー数: N件
- 影響継続時間: N分
### タイムライン
| 時刻 | 出来事 |
|---|---|
| HH:MM | アラート発火(CloudWatch → PagerDuty) |
| HH:MM | オンコールが対応開始 |
| HH:MM | 原因特定(XXX) |
| HH:MM | 対応策を適用(ロールバック / スケールアウト) |
| HH:MM | サービス復旧確認 |
### 根本原因
(例: DynamoDB の WCU 不足によるスロットリングが連鎖して Lambda タイムアウトが発生)
### 影響
- サービス: 注文APIが5分間応答不能
- ユーザー: 約200件の注文失敗
- 売上影響: 推定 N万円
### 何が良かったか
- X-Ray トレースで根本原因の特定が5分以内にできた
- ロールバック手順が整備されており素早く実行できた
### 何が悪かったか / 改善すべき点
- DynamoDB の Auto Scaling の反応が遅く、スパイクに追いつかなかった
- 最初のアラートから対応開始まで10分かかった(深夜帯)
### 再発防止策
| アクション | 担当 | 期限 |
|---|---|---|
| DynamoDB を On-Demand モードに変更 | バックエンドチーム | 1週間 |
| DLQ アラームを P1 に格上げ | SREチーム | 3日 |
| 深夜帯のエスカレーション手順を整備 | マネージャー | 2週間 |
8. オブザーバビリティ設計チェックリスト
[メトリクス]
□ ゴールデンシグナル(レイテンシ・エラー率・スループット・飽和度)を全サービスで収集
□ ビジネス KPI をカスタムメトリクスで計測
□ 複合アラームで誤検知を削減
□ 異常検知アラームで動的しきい値を使用
[ログ]
□ JSON 形式で構造化ログを出力
□ 全ログに requestId / userId を含める
□ CloudWatch Logs の保持期間を設定(無期限を避ける)
□ 重要なエラーをメトリクスフィルターでカウント
[トレース]
□ X-Ray を全 Lambda / ECS に有効化
□ サンプリングルールを環境ごとに設定(本番 5% / 開発 100%)
□ サービスマップで依存関係を定期確認
[アラート・対応]
□ アラームに重大度(P1/P2/P3)のラベルを付与
□ SNS → PagerDuty/Opsgenie で適切にルーティング
□ SLO と Error Budget を定義・可視化
□ ポストモーテムを全 P1/P2 インシデントで実施
[ダッシュボード]
□ ゴールデンシグナルダッシュボードを全本番サービスに用意
□ オンコール開始時にすぐ開けるブックマークを整備
□ CloudWatch ServiceLens でサービスマップを常時表示