目次
この記事の内容
現代のシステム運用において、監視とオブザーバビリティは不可欠な要素です。本記事では、監視の基本概念から、主要ツールの活用方法までを解説します。
監視とオブザーバビリティの違い
従来の監視(Monitoring)
**「システムが正常に動作しているか」**を確認する活動です。
【監視の主な対象】
・CPU 使用率
・メモリ使用量
・ディスク容量
・ネットワークトラフィック
・サービスのアップ/ダウン
特徴:
- 事前に指標(メトリクス)を定義
- 閾値を超えた場合にアラート
- 「何がおかしいか」を検知
オブザーバビリティ(Observability)
**「システム内部の状態を外部から観測・理解する能力」**です。
【オブザーバビリティの 3 本柱】
1. メトリクス(Metrics)—— 時系列の数値データ
2. ログ(Logs)—— イベント記録
3. トレース(Traces)—— リクエストの流れ
特徴:
- 予期せぬ問題の調査が可能
- 「なぜおかしいか」を理解
- 分散システム時代に必須
比較表
| 特徴 | 監視 | オブザーバビリティ |
|---|---|---|
| 目的 | 問題の検知 | 問題の理解 |
| アプローチ | トップダウン(既知の問題) | ボトムアップ(未知の問題) |
| データ | メトリクス中心 | メトリクス+ログ+トレース |
| 質問 | 「何が壊れたか?」 | 「なぜ壊れたか?」 |
| 適する状況 | 単純なシステム | 分散システム、マイクロサービス |
重要な洞察: オブザーバビリティは監視を置き換えるものではなく、補完するものです。両方必要です。
メトリクス監視:Prometheus
Prometheus とは
オープンソースの監視・アラートツールキットです。CNCF(Cloud Native Computing Foundation)の 2 番目のプロジェクトとして採択されました。
アーキテクチャ
┌─────────────────────────────────────────────┐
│ Prometheus Server │
│ ┌─────────┐ ┌─────────┐ │
│ │ TSDB │ │ Alert │ │
│ │(時系列DB)│ │ Manager │ │
│ └─────────┘ └─────────┘ │
└─────────┬─────────────────┬─────────────────┘
│ Pull │
┌─────▼─────┐ ┌────▼─────┐
│ Job 1 │ │ Job 2 │
│ (Node) │ │ (App) │
└───────────┘ └──────────┘
│ │
┌─────▼─────┐ ┌──────▼─────┐
│ Exporter │ │ Instrument │
└───────────┘ └────────────┘
主要コンポーネント
| コンポーネント | 説明 |
|---|---|
| Prometheus Server | メトリクス収集・保存・クエリ処理 |
| Exporter | 外部システムからメトリクスをエクスポート |
| Pushgateway | 短期間ジョブ用メトリクス受付 |
| Alertmanager | アラート通知管理 |
インストール(Docker)
# docker-compose.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
restart: unless-stopped
volumes:
prometheus_data:
設定ファイル(prometheus.yml)
global:
scrape_interval: 15s # 収集間隔
evaluation_interval: 15s # ルール評価間隔
# アラートルール
rule_files:
- "alerts.yml"
# スクレイプ設定
scrape_configs:
# Prometheus 自身
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# Node Exporter(サーバー監視)
- job_name: 'node'
static_configs:
- targets: ['node-exporter:9100']
# アプリケーション
- job_name: 'app'
static_configs:
- targets: ['app:8080']
metrics_path: '/metrics'
主要メトリクス
Prometheus は 4 つのメトリクス型をサポート:
| 型 | 説明 | 例 |
|---|---|---|
| Counter | 増加のみ(リセットあり) | リクエスト数、エラー数 |
| Gauge | 増減する値 | CPU 使用率、メモリ使用量 |
| Histogram | 分布(ヒストグラム) | レイテンシ、レスポンスタイム |
| Summary | 分布(パーセンタイル) | レイテンシの 95 パーセンタイル |
PromQL(クエリ言語)
# 基本クエリ
http_requests_total # 全リクエスト数
node_cpu_seconds_total # CPU 時間
# 変化率(5 分間)
rate(http_requests_total[5m])
# 平均(5 分間)
avg_over_time(node_memory_usage[5m])
# 95 パーセンタイル
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# aggregated
sum(rate(http_requests_total[5m])) by (service)
アラート設定(alerts.yml)
groups:
- name: example
rules:
# サービスダウン
- alert: ServiceDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Service {{ $labels.job }} is down"
description: "{{ $labels.instance }} has been down for more than 1 minute."
# 高 CPU
- alert: HighCPU
expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
annotations:
summary: "High CPU usage on {{ $labels.instance }}"
description: "CPU usage is above 80% for more than 5 minutes."
# メモリ不足
- alert: LowMemory
expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 < 10
for: 5m
labels:
severity: warning
annotations:
summary: "Low memory on {{ $labels.instance }}"
description: "Memory available is below 10%."
ログ管理:ELK スタック
ELK スタックとは
Elasticsearch、Logstash、Kibanaの 3 つのオープンソースプロジェクトを統合したログ管理ソリューションです。
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Logstash │ → │Elasticsearch│ ← │ Kibana │
│ (収集・変換) │ │ (保存・検索) │ │ (可視化) │
└─────────────┘ └─────────────┘ └─────────────┘
↑
┌──────┴──────┐
│ 各種ログ │
│ (App, Nginx)│
└─────────────┘
近年: Filebeat などの軽量フォワーダーを追加しELK StackまたはElastic Stackと呼ばれます。
各コンポーネント
| コンポーネント | 説明 |
|---|---|
| Elasticsearch | 分散型検索・分析エンジン |
| Logstash | ログ収集・変換パイプライン |
| Kibana | 可視化・ダッシュボード |
| Filebeat | 軽量ログフォワーダー |
Docker Compose 設定
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- "9200:9200"
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
logstash:
image: docker.elastic.co/logstash/logstash:8.11.0
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
ports:
- "5000:5000"
depends_on:
- elasticsearch
kibana:
image: docker.elastic.co/kibana/kibana:8.11.0
ports:
- "5601:5601"
depends_on:
- elasticsearch
filebeat:
image: docker.elastic.co/filebeat/filebeat:8.11.0
volumes:
- ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
- /var/log:/var/log:ro
depends_on:
- elasticsearch
volumes:
elasticsearch_data:
Logstash 設定(logstash.conf)
input {
beats {
port => 5000
}
tcp {
port => 5001
codec => json
}
}
filter {
# 日付パース
date {
match => ["timestamp", "ISO8601"]
}
# JSON パース
json {
source => "message"
target => "parsed"
}
# 不要フィールド削除
mutate {
remove_field => ["@version", "host"]
}
# 環境フィールド追加
if [environment] == "" {
mutate {
add_field => { "environment" => "production" }
}
}
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "logs-%{+YYYY.MM.dd}"
}
# デバッグ用標準出力
stdout {
codec => rubydebug
}
}
Filebeat 設定(filebeat.yml)
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/*.log
fields:
environment: production
multiline.pattern: '^\d{4}-\d{2}-\d{2}'
multiline.negate: true
multiline.match: after
- type: container
paths:
- /var/lib/docker/containers/*/*.log
processors:
- add_host_metadata: ~
- add_cloud_metadata: ~
output.elasticsearch:
hosts: ["elasticsearch:9200"]
indices:
- index: "filebeat-%{+yyyy.MM.dd}"
logging.level: info
分散トレース:Jaeger
分散トレースとは
マイクロサービス間でのリクエストフローを追跡する技術です。
【ユーザーリクエスト】
│
▼
┌─────────────┐
│ API Gateway │ ← トレース開始(ルートスパン)
└──────┬──────┘
│
├─────────────┐
▼ ▼
┌───────────┐ ┌───────────┐
│ User Svc │ │ Order Svc │ ← 子スパン
└─────┬─────┘ └─────┬─────┘
│ │
▼ ▼
┌───────────┐ ┌───────────┐
│ Database │ │ Payment │ ← 孫スパン
└───────────┘ └───────────┘
【各スパンに共通の Trace ID】
Jaeger アーキテクチャ
┌──────────────────────────────────────────┐
│ Application │
│ (OpenTelemetry SDK Instrumented) │
└────────────┬─────────────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ Jaeger Agent │
│ (サイドカーとしてデプロイ) │
└────────────┬─────────────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ Jaeger Collector │
└────────────┬─────────────────────────────┘
│
┌─────┴─────┐
▼ ▼
┌───────────┐ ┌───────────┐
│ Cassandra │ │ Query │
│ (DB) │ │ Service │
└───────────┘ └─────┬─────┘
│
▼
┌───────────┐
│ UI │
└───────────┘
Docker Compose 設定
version: '3.8'
services:
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686" # UI
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
environment:
- COLLECTOR_OTLP_ENABLED=true
restart: unless-stopped
アプリケーション計装(Node.js 例)
// OpenTelemetry 設定
const opentelemetry = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const sdk = new opentelemetry.NodeSDK({
traceExporter: new OTLPTraceExporter({
url: 'http://jaeger:4317'
}),
instrumentations: [
getNodeAutoInstrumentations()
],
});
sdk.start();
// マニュアル計装
const { trace, context } = require('@opentelemetry/api');
const tracer = trace.getTracer('my-app');
async function processOrder(orderId) {
return tracer.startActiveSpan('processOrder', async (span) => {
try {
span.setAttribute('order.id', orderId);
// 処理実行
await validateOrder(orderId);
await chargePayment(orderId);
await shipOrder(orderId);
span.setStatus({ code: 0 }); // OK
} catch (error) {
span.setStatus({ code: 2, message: error.message }); // ERROR
span.recordException(error);
throw error;
} finally {
span.end();
}
});
}
可視化:Grafana
Grafana とは
メトリクス・ログ・トレースのための可視化プラットフォームです。
主要機能
- ダッシュボード: 複数のパネルを配置
- データソース接続: Prometheus、Elasticsearch、Jaeger など
- アラート: 閾値ベースの通知
- テンプレート変数: 動的なダッシュボード
Docker Compose 設定
version: '3.8'
services:
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=grafana123
- GF_INSTALL_PLUGINS=grafana-piechart-panel
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
- ./grafana/dashboards:/var/lib/grafana/dashboards
restart: unless-stopped
volumes:
grafana_data:
データソース設定(provisioning/datasources.yml)
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: true
- name: Elasticsearch
type: elasticsearch
access: proxy
url: http://elasticsearch:9200
database: "logs-*"
basicAuth: false
- name: Jaeger
type: jaeger
access: proxy
url: http://jaeger:16686
ダッシュボード設定(provisioning/dashboards.yml)
apiVersion: 1
providers:
- name: 'default'
orgId: 1
folder: ''
type: file
disableDeletion: false
updateIntervalSeconds: 10
options:
path: /var/lib/grafana/dashboards
実践的クエリ例
システムダッシュボード(Prometheus)
# CPU 使用率(ノード別)
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# メモリ使用率
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
# ディスク使用率
(1 - (node_filesystem_avail_bytes / node_filesystem_size_bytes)) * 100
# ネットワークトラフィック
sum(rate(node_network_receive_bytes_total[5m])) by (instance)
アプリケーションダッシュボード
# リクエストレート(5 分間平均)
sum(rate(http_requests_total[5m])) by (service)
# エラーレート
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
# レイテンシ(P95)
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))
# HTTP ステータス分布
sum(rate(http_requests_total[5m])) by (status)
アラート設計のベストプラクティス
アラートレベルの定義
| レベル | 説明 | 対応時間 | 通知方法 |
|---|---|---|---|
| Critical | サービス停止、データ損失 | 即時(24 時間 365 日) | PagerDuty、電話 |
| Warning | 性能劣化、容量逼迫 | 営業時間内 | Slack、メール |
| Info | 参考情報 | 定例レビュー | ダッシュボードのみ |
アラート設計原則
✅ 良いアラート
・アクション可能(何かすべきことがある)
・誤報が少ない
・ビジネスインパクトに基づく
・自動復旧を待つ(一時的なスパイク)
❌ 悪いアラート
・「何かおかしい」だけ
・誤報が多くオンコール疲れ
・技術指標のみ(ビジネス無関係)
・一時的なスパイクで毎回流れる
アラート例(Prometheus)
groups:
- name: application
rules:
# サービスダウン(Critical)
- alert: ServiceDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "サービスダウン:{{ $labels.job }}"
description: "{{ $labels.instance }} が 1 分以上ダウンしています"
# エラーレート増加(Warning)
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "エラーレート上昇"
description: "5 分間のエラーレートが 5% を超えています"
# レイテンシ悪化(Warning)
- alert: HighLatency
expr: |
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket[5m]))
by (le, service)
) > 1
for: 10m
labels:
severity: warning
annotations:
summary: "レイテンシ悪化"
description: "P95 レイテンシが 1 秒を超えています"
運用プラクティス
1. ゴールデンシグナルの監視
Google SRE が推奨する 4 つの主要指標:
| シグナル | 説明 | 例 |
|---|---|---|
| レイテンシ | リクエスト処理時間 | P95、P99 |
| トラフィック | システム負荷 | リクエスト数、QPS |
| エラー | 失敗率 | エラーレート、5xx |
| サチュレーション | リソース飽和 | CPU、メモリ、ディスク |
2. RED メソッド(マイクロサービス向け)
| 指標 | 説明 |
|---|---|
| Rate | リクエストレート |
| Errors | エラーレート |
| Duration | レスポンス時間 |
3. USE メソッド(インフラ向け)
| 指標 | 説明 |
|---|---|
| Utilization | リソース使用率 |
| Saturation | リソース飽和度 |
| Errors | ハードウェアエラー |
監視システム構築のステップ
ステップ 1: 可観測性の要件定義
【質問事項】
1. 何を監視する必要がありますか?
- インフラ(サーバー、ネットワーク)
- アプリケーション(API、バッチ)
- ビジネス(売上、ユーザー数)
2. 誰が監視データを使いますか?
- 開発者
- 運用チーム
- 経営陣
3. どのくらいの頻度でデータが必要ですか?
- リアルタイム(秒単位)
- 近リアルタイム(分単位)
- 集計(時間・日単位)
ステップ 2: ツール選定
【小规模システム】
・Prometheus + Grafana(メトリクス)
・Filebeat + Elasticsearch(ログ)
【中規模システム】
・Prometheus + Grafana
・ELK Stack
・Jaeger(トレース)
【大規模システム】
・マネージドサービス検討(Datadog, New Relic)
・カスタムメトリクス対応
・自動スケーリング連携
ステップ 3: 実装・計装
【チェックリスト】
□ メトリクス収集ポイント定義
□ ログフォーマット標準化(JSON 推奨)
□ トレースコンテキスト伝播実装
□ ダッシュボード作成
□ アラートルール設定
□ 通知チャネル設定
ステップ 4: 運用・改善
【継続的改善】
・アラート精度の定期的レビュー
・誤報アラートの削除・調整
・新しいメトリクスの追加
・ダッシュボードの更新
・インシデントからの学習
よくある落とし穴
1. アラート疲れ
【問題】
・多すぎるアラート
・誤報の繰り返し
・結果:重要なアラートを見逃す
【対策】
・アラート件数を制限(10 件以下)
・閾値調整
・自動復旧を待つ
2. メトリクス過多
【問題】
・全てを収集しようとする
・ストレージコスト増大
・ノイズに埋もれる
【対策】
・ビジネス価値に基づく選別
・サンプリング検討
・集計粒度の調整
3. 計装の遅れ
【問題】
・本番後付けで計装
・データ不足で調査不能
【対策】
・開発初期から計装を設計
・標準ライブラリ用意
・コードレビューでチェック
まとめ
監視とオブザーバビリティの核心:
- 監視: 問題を検知する(何がおかしいか)
- オブザーバビリティ: 問題を理解する(なぜおかしいか)
- 3 本柱: メトリクス、ログ、トレース
- 主要ツール: Prometheus、ELK、Jaeger、Grafana
- 継続的改善: アラート疲れを防ぎ、精度向上
「監視は手段であって目的ではない。健全なシステム運用のために」
参考資料
- Prometheus 公式ドキュメント
- Elastic Stack 公式ドキュメント
- Jaeger 公式ドキュメント
- Grafana 公式ドキュメント
- Google SRE ブック「第 4 章 監視分散システム」
- 「実践的オブザーバビリティ」O’Reilly
免責事項 — 掲載情報は執筆時点のものです。料金・機能は変更される場合があります。最新情報は各公式サイトをご確認ください。