Kayenta
Kayenta: Netflixによる自動カナリア分析の全容
目次
- Kayentaとは何か
- カナリア分析の基本概念
- Kayentaのアーキテクチャ
- 主要コンポーネント
- メトリクス収集とデータソース統合
- 統計分析エンジン
- Spinnaker との統合
- 実装例と設定方法
- ベストプラクティス
- トラブルシューティングと監視
1. Kayentaとは何か
1.1 概要
Kayenta(カヤンタ)はNetflixとGoogleが共同で開発した、Spinnaker統合の自動カナリア分析プラットフォームです。デプロイ時に新しいバージョン(カナリア)と既存バージョン(ベースライン)のメトリクスを自動比較し、統計的に有意な差異があるかを判定します。
従来のカナリアテストは手動で結果を観察して判断する必要がありましたが、Kayentaはこれを完全に自動化し、客観的な数値に基づいた意思決定を可能にします。
1.2 主な特徴
- 自動メトリクス比較: 複数のデータソースからメトリクスを自動収集し比較
- 統計的信頼度: 有意差検定により数学的に堅牢な判定
- マルチメトリクス対応: Prometheus、Datadog、Google Cloud Monitoring等複数のデータソースをサポート
- Spinnaker統合: パイプラインの一部として自動実行
- カスタマイズ可能な判定基準: チーム固有のビジネス要件に応じた設定
- 詳細なレポート生成: 判定根拠の完全な可視化
1.3 ユースケース
- 本番環境へのデプロイ前のリスク検証
- ブルーグリーンデプロイメントの自動判定
- 段階的ロールアウトの自動制御
- SLO違反の早期検出
- パフォーマンス低下の自動検知
2. カナリア分析の基本概念
2.1 カナリア分析とは
カナリア分析は、新しいバージョンのソフトウェアを一部のユーザーに対して段階的にロールアウトし、その過程で収集したメトリクスデータを使用して品質を評価するアプローチです。
名称は、炭鉱でガスの危険性を検知するために使用された「カナリア」に由来します。
2.2 比較基準
Kayentaでのカナリア分析には以下の3つの比較パターンがあります:
パターン1:カナリア vs ベースライン(本番環境)
Before: ████████████████ 本番環境(安定版)
After: ████░░░░ カナリア(新バージョン)
メトリクス比較
- エラー率の増加
- レスポンスタイムの遅延
- CPU使用率
- メモリ消費量
パターン2:カナリア vs 前回のデプロイ
前回のリリースと比較して、今回のカナリアが改善または悪化していないかを検証します。
パターン3:段階的ロールアウトの連続比較
複数段階のカナリアロールアウト時に、各段階でメトリクスを連続的に比較します。
2.3 重要なメトリクス
カナリア分析において通常監視される主要メトリクス:
| カテゴリ | メトリクス例 | 警告閾値 |
|---|---|---|
| 可用性 | エラー率、HTTP 5xx率 | +5% |
| パフォーマンス | レスポンスタイム(P50/P95/P99) | +10% |
| リソース | CPU、メモリ、ディスクI/O | +15% |
| ビジネス | トランザクション完了率、コンバージョン率 | -2% |
3. Kayentaのアーキテクチャ
3.1 システム構成図
┌─────────────────────────────────────────────────────────┐
│ Spinnaker Pipeline │
│ (Deploy Stage → Canary Analysis) │
└────────────────────┬────────────────────────────────────┘
│
▼
┌───────────────────────────┐
│ Kayenta Controller │
│ (Canary Orchestrator) │
└───────────┬───────────────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌─────────────┐
│Metrics │ │Storage │ │Judge Engine │
│Fetcher │ │(Redis) │ │(Analysis) │
└────┬───┘ └────────┘ └──────┬──────┘
│ │
┌────┴─────────────────────────┴──────┐
│ Metric Data Sources │
├──────────────────────────────────────┤
│ Prometheus│Datadog│Stackdriver│ │
│ CloudWatch│New Relic│Dynatrace │
└──────────────────────────────────────┘
3.2 基本フロー
1. デプロイ開始
│
2. カナリアインスタンス起動
│
3. トラフィック制御(段階的ロールアウト)
│
4. メトリクス収集開始(ベースライン+カナリア)
│
5. 指定時間の観察期間
│
6. メトリクス分析・統計検定
│
7. 判定(Pass/Fail/Unknown)
│
├─→ Pass: 完全ロールアウト
├─→ Fail: ロールバック
└─→ Unknown: 手動判定待機
3.3 主要コンポーネント間の相互作用
Spinnaker Pipeline Trigger
↓
Kayenta Orchestrator
├→ Metrics Fetcher: メトリクス取得リクエスト生成
├→ Storage (Redis): 中間結果キャッシュ
├→ Judge Engine: 統計分析実行
├→ Data Collectors: 各種メトリクスシステムと連携
└→ Reporter: 結果レポート生成
↓
Spinnaker Pipeline Execution Control
├→ Deploy (成功)
├→ Rollback (失敗)
└→ Manual Judgment (判定不可)
4. 主要コンポーネント
4.1 Kayenta Controller
責務
- カナリア分析の全体的なオーケストレーション
- Spinnaker パイプラインからのイベント受信
- 分析ライフサイクルの管理
- 各コンポーネント間の調整
処理フロー
# Kayenta Controller の処理フロー
start_canary_analysis:
request:
pipelineId: "prod-deploy"
stageId: "canary-analysis"
clusterPair:
baseline: "v1.0.0-prod"
canary: "v1.1.0-canary"
steps:
1. リクエスト検証
2. 分析セッション作成
3. メトリクスコレクター起動
4. 観察期間スケジュール
5. 定期的なステータスチェック
6. 完了時の判定報告
4.2 Metrics Fetcher
機能
- 複数のメトリクスプロバイダーとの統合
- 非同期メトリクス取得
- データの正規化と集約
- 欠落データの処理
実装例
// Kayenta Metrics Fetcher の基本構造
public interface MetricsService {
// メトリクス取得
List<MetricSetPair> fetchMetrics(
MetricsServiceQueryBuilder builder,
String metricsAccountName,
String filter,
String groupByFields
);
// 複数メトリクスの一括取得
List<MetricSetPair> queryMetrics(
String accountName,
MetricsServiceQueryBuilder queryBuilder,
long startTimeMillis,
long endTimeMillis
);
}
4.3 Judge Engine
役割
- 統計分析の実行
- 信頼度の計算
- Pass/Fail/Unknown の判定ロジック
判定アルゴリズム
judge_canary(baselineMetrics, canaryMetrics, thresholds):
for each metric in metrics:
baselineValue = calculate_statistics(baselineMetrics[metric])
canaryValue = calculate_statistics(canaryMetrics[metric])
# Mann-Whitney U検定 (ノンパラメトリック)
pValue = mann_whitney_u_test(baselineValue, canaryValue)
# 効果量の計算 (Cohen's d)
effectSize = cohens_d(baselineValue, canaryValue)
if pValue < threshold.pValue AND effectSize > threshold.effectSize:
return FAIL
elif pValue < threshold.pValue AND effectSize < threshold.effectSize:
return PASS
else:
return UNKNOWN
# 全メトリクスの集約判定
return aggregate_judgments(individual_judgments)
4.4 Storage Layer
Redis の使用
# Kayenta での Redis キャッシュ構造
canary_session:{sessionId}:
- baseline_metrics: {JSON}
- canary_metrics: {JSON}
- timestamp: {epoch_ms}
- status: "RUNNING|COMPLETED|FAILED"
- judgments: {analysis_results}
キャッシュ戦略
- セッション情報の短期保持(TTL: 7日)
- メトリクスデータのキャッシュ(検索パフォーマンス向上)
- 中間分析結果の一時保存
5. メトリクス収集とデータソース統合
5.1 サポートされるデータソース
Kayentaは以下のメトリクスプロバイダーをサポート:
Prometheus
dataSourceType: prometheus
accountName: prometheus-prod
url: "http://prometheus.monitoring:9090"
Datadog
dataSourceType: datadog
accountName: datadog-prod
apiKey: "${DATADOG_API_KEY}"
appKey: "${DATADOG_APP_KEY}"
Google Cloud Monitoring (Stackdriver)
dataSourceType: stackdriver
accountName: gcp-prod
projectId: "my-gcp-project"
Amazon CloudWatch
dataSourceType: cloudwatch
accountName: aws-prod
region: "us-east-1"
その他
- New Relic
- Dynatrace
- Elastic
- SignalFx
5.2 メトリクス収集の仕組み
Time Flow:
├─ T0: カナリアデプロイ開始
├─ T0+30s: ベースライン+カナリアから均等にトラフィック
├─ T0+1m: メトリクス収集開始
│
├─ [観察期間: 通常 5-10分]
│ ├─ 1分ごと: メトリクス取得
│ ├─ 集約: 複数のデータポイントから統計量計算
│ └─ 保存: Redis へキャッシュ
│
├─ T0+5m: 最初の判定(early judgment)
├─ T0+10m: 最終判定(final judgment)
└─ T0+10m+: ロールアウト継続または ロールバック
メトリクス取得スケジュール:
Time Baseline Canary Status
----- -------- ------ ------
1m [data] [data] collecting
2m [data] [data] collecting
3m [data] [data] collecting
...
5m [aggregated stats] analyzing
pValue: 0.042
effect_size: 0.15
judgment: PASS
5.3 Prometheus インテグレーション実装例
# Kayenta Prometheus DataSource Configuration
prometheus:
enabled: true
accounts:
- name: prometheus-prod
url: http://prometheus.monitoring.svc.cluster.local:9090
supportedTypes:
- METRICS_STORE
# メトリクス定義
metrics:
- name: http_request_duration_seconds
query: |
rate(http_request_duration_seconds_bucket{le="+Inf"}[1m])
- name: http_requests_total
query: |
rate(http_requests_total{status=~"5.."}[1m])
- name: container_memory_usage_bytes
query: |
container_memory_usage_bytes{pod=~"canary.*"}
- name: container_cpu_usage_seconds_total
query: |
rate(container_cpu_usage_seconds_total[1m])
# クエリ生成ロジック
query_template:
baseline: |
{metric_name}{deployment="baseline",env="prod"}[{interval}]
canary: |
{metric_name}{deployment="canary",env="prod"}[{interval}]
5.4 Datadog インテグレーション実装例
# Kayenta Datadog DataSource Configuration
datadog:
enabled: true
accounts:
- name: datadog-prod
apiKey: "${DD_API_KEY}"
appKey: "${DD_APP_KEY}"
queries:
error_rate:
query: "avg:trace.web.request.errors{service:{{service}},env:prod}"
metric_type: ERROR_RATE
latency_p99:
query: "p99:trace.web.request.duration{service:{{service}},env:prod}"
metric_type: LATENCY
apm_errors:
query: "sum:trace.web.errors{service:{{service}},env:prod}"
metric_type: COUNT
# タグベースのスコーピング
filters:
baseline: 'tag:"version:stable"'
canary: 'tag:"version:canary"'
6. 統計分析エンジン
6.1 統計検定方法
Mann-Whitney U Test (ウィルコクソンの順位和検定)
Kayentaで採用されている主要な統計検定。
特徴:
- ノンパラメトリック(分布の形を仮定しない)
- 外れ値に強い
- サンプルサイズが異なる場合でも適用可能
実装例:
public class ManualWitnessUTest {
/**
* Mann-Whitney U統計量を計算
*/
public static double calculateMannWhitneyU(
List<Double> baseline,
List<Double> canary) {
// ステップ1: 全データを結合してランク付け
List<Double> combined = new ArrayList<>(baseline);
combined.addAll(canary);
Collections.sort(combined);
// ステップ2: 各データのランクを計算
Map<Double, Double> ranks = assignRanks(combined);
// ステップ3: ベースラインのランク合計を計算
double R1 = baseline.stream()
.mapToDouble(ranks::get)
.sum();
// ステップ4: U統計量を計算
int n1 = baseline.size();
int n2 = canary.size();
double U = n1 * n2 +
(n1 * (n1 + 1.0)) / 2.0 -
R1;
return U;
}
/**
* p値を計算
*/
public static double calculatePValue(
double U, int n1, int n2) {
// 標準化スコア Z を計算
double mean = (n1 * n2) / 2.0;
double stdDev = Math.sqrt(
(n1 * n2 * (n1 + n2 + 1.0)) / 12.0
);
double Z = Math.abs((U - mean) / stdDev);
// 標準正規分布から p値を取得
return 2 * (1 - normalCDF(Z));
}
}
Cohen's d (効果量)
ベースラインとカナリア間の実質的な差の大きさを測定。
public class CohensD {
/**
* Cohen's d を計算
*/
public static double calculateCohensD(
List<Double> baseline,
List<Double> canary) {
// 平均値
double meanBaseline = baseline.stream()
.mapToDouble(Double::doubleValue)
.average()
.orElse(0.0);
double meanCanary = canary.stream()
.mapToDouble(Double::doubleValue)
.average()
.orElse(0.0);
// 標本標準偏差(プール後)
double pooledStd = calculatePooledStdDev(baseline, canary);
// Cohen's d
double d = (meanCanary - meanBaseline) / pooledStd;
return d;
}
/**
* 解釈
* |d| < 0.2: 効果なし (negligible)
* 0.2 ≤ |d| < 0.5: 小 (small)
* 0.5 ≤ |d| < 0.8: 中 (medium)
* |d| ≥ 0.8: 大 (large)
*/
}
6.2 判定ロジック
# Kayenta 判定基準の設定例
analysis_config:
judge:
# 統計的有意性の閾値
statistical_significance_level: 0.05 # p < 0.05
# 実質的意義の閾値(Cohen's d)
effect_size_threshold: 0.1
# スコアの計算方法
scoring_method: MANN_WHITNEY_PLUS_EFFECT_SIZE
# メトリクス単位の判定
metrics:
http_request_duration_seconds:
direction: HIGHER_IS_WORSE
critical: true
threshold:
p_value: 0.05
effect_size: 0.1
http_requests_error_rate:
direction: HIGHER_IS_WORSE
critical: true
threshold:
p_value: 0.05
effect_size: 0.05
cpu_usage:
direction: HIGHER_IS_WORSE
critical: false
threshold:
p_value: 0.10
effect_size: 0.15
# 全体的な判定ロジック
aggregation:
# PASS: すべてのメトリクスが許容範囲
# FAIL: クリティカルメトリクス1つ以上が有意差
# UNKNOWN: データ不足など判定不可
pass_rate_threshold: 0.8 # 80%以上のメトリクスがパス
6.3 判定フロー
Analysis Start
│
├─ Baseline Metrics: n1 = 60 samples
├─ Canary Metrics: n2 = 60 samples
│
├─ Metric: http_latency_p99
│ ├─ Mean(baseline) = 100ms
│ ├─ Mean(canary) = 105ms
│ ├─ U-test: p = 0.032 ✓ (< 0.05)
│ ├─ Cohen's d: 0.12
│ ├─ Direction: HIGHER_IS_WORSE
│ ├─ Effect Size Check: 0.12 > 0.1 ✓
│ └─ → FAIL (有意で実質的な劣化)
│
├─ Metric: error_rate
│ ├─ Mean(baseline) = 0.5%
│ ├─ Mean(canary) = 0.52%
│ ├─ U-test: p = 0.087 (> 0.05)
│ ├─ Cohen's d: 0.03
│ └─ → PASS (有意差なし)
│
├─ Metric: cpu_usage
│ ├─ Mean(baseline) = 45%
│ ├─ Mean(canary) = 47%
│ ├─ U-test: p = 0.042 ✓
│ ├─ Cohen's d: 0.08 (< 0.15)
│ └─ → PASS (有意差小さい)
│
└─ Final Judgment:
Critical FAIL detected in http_latency_p99
Overall: FAIL ✗ (Rollback recommended)
7. Spinnaker との統合
7.1 Spinnaker パイプラインでのカナリア分析
# Spinnaker Pipeline 設定例
stages:
- name: Deploy Baseline
type: Deploy
config:
deployment: canary-baseline
replicas: 10
- name: Deploy Canary
type: Deploy
config:
deployment: canary-canary
replicas: 2
dependsOn:
- Deploy Baseline
- name: Canary Analysis
type: Canary
config:
# Kayenta 設定
canaryConfig:
serviceName: my-service
canaryDeployment: canary-canary
baselineDeployment: canary-baseline
# Namespace/リソース定義
namespaceA: default
namespaceB: default
# メトリクスアカウント
metricsAccountName: prometheus-prod
# スコープ(タグやラベル)
scopes:
- name: "pod_namespace"
controlScope: default
experimentScope: default
# 観察期間(秒)
canaryAnalysisIntervalSeconds: 60
canaryAnalysisIntervals: 10 # 10分間
# 判定基準
failureAnalysisType: MANN_WHITNEY # or WELCHS_T_TEST
notificationLevel: ONLY_FAILURES
# メトリクス定義
metrics:
- name: http_request_duration_seconds
query: |
rate(http_request_duration_seconds_bucket[1m])
direction: HIGHER_IS_WORSE
critical: true
- name: requests_errors_total
query: |
rate(requests_errors_total[1m])
direction: HIGHER_IS_WORSE
critical: true
- name: container_memory_usage_bytes
direction: HIGHER_IS_WORSE
critical: false
dependsOn:
- Deploy Canary
onFailure:
- Rollback
onSuccess:
- Full Deploy
7.2 パイプライン実行フロー
┌─────────────────────────────────────────────────────┐
│ Spinnaker Pipeline Execution │
└────────────────────┬────────────────────────────────┘
│
▼
┌───────────────────────────┐
│ 1. Deploy Baseline (v1.0) │ 10 replicas
└────────────┬──────────────┘
│ success
▼
┌───────────────────────────┐
│ 2. Deploy Canary (v1.1) │ 2 replicas
└────────────┬──────────────┘
│ success
▼
┌───────────────────────────┐
│ 3. Start Canary Analysis │
│ - Traffic split: 90/10 │
│ - Observation: 5 minutes │
└────────────┬──────────────┘
│
├─ Every 60 seconds:
│ 1. Fetch metrics from Prometheus
│ 2. Aggregate statistics
│ 3. Run Mann-Whitney U test
│ 4. Check effect size
│ 5. Update status
│
▼
┌──────────────────────────────────┐
│ 4. Analysis Complete │
│ Judgment: PASS / FAIL / SKIP │
└────────────┬─────────────────────┘
│
├─ PASS ──────────┐
│ ▼
│ ┌──────────────────────┐
│ │ 5. Scale Up Canary │ 10 replicas
│ │ 6. Remove Baseline │ Scale down
│ └──────────┬───────────┘
│ ▼
│ ┌──────────────────────┐
│ │ Complete Deployment │
│ └──────────────────────┘
│
├─ FAIL ───────────┐
│ ▼
│ ┌──────────────────────┐
│ │ Rollback │
│ │ - Remove Canary │
│ │ - Remove Baseline │
│ │ - Send Notification │
│ └──────────────────────┘
│
└─ SKIP ────────────┐
▼
┌──────────────────────┐
│ Manual Judgment Req. │
│ Engineer decides │
└──────────────────────┘
7.3 REST API による Kayenta 連携
# Kayenta に直接カナリア分析をリクエスト
curl -X POST http://kayenta:8090/api/v1/canaries \
-H "Content-Type: application/json" \
-d '{
"application": "my-app",
"canaryConfig": {
"name": "production-canary",
"description": "Production canary test",
"accountName": "my-prometheus",
"scopes": [
{
"scopeName": "default",
"controlScope": "default",
"experimentScope": "default"
}
],
"metrics": [
{
"name": "latency",
"query": "rate(http_request_duration_seconds_bucket[1m])",
"direction": "HIGHER_IS_WORSE"
}
],
"judge": {
"judgeType": "MANN_WHITNEY"
}
},
"executionRequest": {
"pipelineId": "prod-deploy-pipeline",
"application": "my-app",
"user": "user@example.com"
}
}'
# レスポンス例
{
"canaryExecutionId": "canary-123456",
"application": "my-app",
"status": "RUNNING",
"startTime": 1680000000000,
"executionProgress": {
"totalSteps": 10,
"completedSteps": 3,
"currentStep": 3
}
}
8. 実装例と設定方法
8.1 Kayenta のデプロイ
Kubernetes 環境でのデプロイ
# kayenta-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: kayenta
namespace: spinnaker
spec:
replicas: 3
selector:
matchLabels:
app: kayenta
template:
metadata:
labels:
app: kayenta
spec:
containers:
- name: kayenta
image: gcr.io/spinnaker-marketplace/kayenta:v0.26.0
ports:
- containerPort: 8090
name: http
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod,k8s"
- name: REDIS_HOST
value: redis.spinnaker.svc.cluster.local
- name: REDIS_PORT
value: "6379"
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
livenessProbe:
httpGet:
path: /health
port: 8090
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8090
initialDelaySeconds: 10
periodSeconds: 5
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
---
apiVersion: v1
kind: Service
metadata:
name: kayenta
namespace: spinnaker
spec:
selector:
app: kayenta
ports:
- port: 8090
targetPort: 8090
type: ClusterIP
8.2 Kayenta 設定ファイル
# kayenta-config.yaml (ConfigMap として Kubernetes に保存)
server:
port: 8090
servlet:
context-path: /
spring:
application:
name: kayenta
datasource:
hikari:
maximum-pool-size: 20
redis:
host: redis.spinnaker.svc.cluster.local
port: 6379
timeout: 2000
database: 0
kayenta:
# 全般設定
defaultMetricsAccount: prometheus-prod
# メトリクスアカウント定義
metricsAccounts:
- name: prometheus-prod
type: prometheus
url: http://prometheus.monitoring:9090
supportedTypes:
- METRICS_STORE
skipSSLValidation: false
- name: datadog-prod
type: datadog
apiKey: ${DATADOG_API_KEY}
appKey: ${DATADOG_APP_KEY}
supportedTypes:
- METRICS_STORE
- name: cloudwatch-prod
type: cloudwatch
region: us-east-1
supportedTypes:
- METRICS_STORE
# カナリア分析デフォルト設定
canary:
# 観察期間設定
observationIntervalSeconds: 300 # 5 minutes
analysisIntervalSeconds: 60 # 1 minute
# デフォルト判定方法
judge:
judgeType: MANN_WHITNEY_PLUS_EFFECT_SIZE
alpha: 0.05 # 有意水準
effectSizeThreshold: 0.1
# ロールアウト設定
rollout:
# 段階的ロールアウトの設定
stages:
- name: "10%"
percentage: 10
duration: 300
- name: "50%"
percentage: 50
duration: 300
- name: "100%"
percentage: 100
# 通知設定
notifications:
enabled: true
slack:
enabled: true
webhookUrl: ${SLACK_WEBHOOK_URL}
email:
enabled: true
smtpServer: smtp.example.com
fromAddress: kayenta@example.com
8.3 メトリクスクエリの詳細設定
# メトリクス定義の詳細例
metrics_definitions:
# レスポンスタイム(Prometheus)
response_time:
metricName: http_request_duration_seconds
query: |
histogram_quantile(0.99,
rate(http_request_duration_seconds_bucket[1m])
)
scopes:
- scopeName: default
resources:
- deployment:canary-baseline
- deployment:canary-canary
units: seconds
direction: HIGHER_IS_WORSE
critical: true
thresholds:
p_value: 0.05
effect_size: 0.1
# エラー率(Prometheus)
error_rate:
metricName: http_request_errors_rate
query: |
sum(rate(http_requests_total{status=~"5.."}[1m]))
/
sum(rate(http_requests_total[1m]))
units: percentage
direction: HIGHER_IS_WORSE
critical: true
thresholds:
p_value: 0.05
effect_size: 0.05
# CPU 使用率(Prometheus)
cpu_usage:
metricName: container_cpu_usage_percentage
query: |
rate(container_cpu_usage_seconds_total[1m]) * 100
units: percentage
direction: HIGHER_IS_WORSE
critical: false
thresholds:
p_value: 0.10
effect_size: 0.15
# メモリ使用量(Prometheus)
memory_usage:
metricName: container_memory_usage_bytes
query: |
container_memory_usage_bytes
/
(1024 * 1024) # Convert to MB
units: megabytes
direction: HIGHER_IS_WORSE
critical: false
thresholds:
p_value: 0.10
effect_size: 0.15
# ビジネスメトリクス(トランザクション成功率)
transaction_success_rate:
metricName: transaction_success_rate
query: |
sum(rate(transactions_success_total[1m]))
/
sum(rate(transactions_total[1m]))
units: percentage
direction: LOWER_IS_WORSE # 低下は悪い
critical: true
thresholds:
p_value: 0.05
effect_size: 0.05
8.4 Spinnaker 統合設定
# Spinnaker (Orca/Deck) の設定
# ~/.hal/config に追加
canary:
enabled: true
serviceEndpoint: http://kayenta.spinnaker:8090
# UIメトリクス表示設定
metrics:
interval: 60
groups:
- name: Errors
metrics:
- error_rate
- name: Latency
metrics:
- response_time_p50
- response_time_p95
- response_time_p99
- name: Resource Usage
metrics:
- cpu_usage
- memory_usage
- name: Business
metrics:
- transaction_success_rate
# 分析結果フィルタ
judgeConfig:
# 判定基準の詳細
scoreThresholds:
pass: 0.95
marginal: 0.50
# 通知ルール
notificationRules:
- event: PASS
notifyOn: NEVER
- event: FAIL
notifyOn: ALWAYS
channels:
- type: slack
webhook: ${SLACK_WEBHOOK_URL}
9. ベストプラクティス
9.1 メトリクス選択の指針
適切なメトリクスの条件
✓ 有用性:ビジネス価値に直結している
✓ 測定可能性:信頼性の高いデータソースから取得可能
✓ 反応性:変化をすぐに検知できる(遅延が小さい)
✓ 安定性:ノイズが少ない
✓ 独立性:他のメトリクスと独立している
メトリクス選定の具体例
# 良い例
good_metrics:
- name: error_rate_5xx
reason: |
- クリティカル(ユーザー影響大)
- 即座に測定可能
- ビジネス損失に直結
- name: latency_p99
reason: |
- ユーザー体験に直結
- 本番環境で測定可能
- 高い応答性
# 悪い例
bad_metrics:
- name: total_requests_count
reason: |
- デプロイと無関係に変動
- ノイズが多い(ビジネス変動)
- name: internal_cache_hit_rate
reason: |
- 実装詳細に過度に依存
- ユーザー体験との関連性が薄い
9.2 観察期間の最適化
# 観察期間選択の考慮事項
observation_period_guidance:
# 短期間観察(1-5分)
short_window:
use_cases:
- 高頻度デプロイメント
- 即時フィードバックが必要
- 比較的安定したシステム
trade_offs:
- 統計的信頼度が低下
- ノイズに敏感
# 中期間観察(5-15分)
medium_window:
use_cases:
- 標準的な本番環境
- バランスの取れた判定が必要
trade_offs:
- 適切な統計サンプルサイズ
- 合理的なフィードバック時間
# 長期間観察(15-60分)
long_window:
use_cases:
- 低頻度のデプロイ
- 時間的変動が大きいシステム
trade_offs:
- デプロイ完了が遅延
- 統計信頼度が高い
# 計算例
sample_size_calculation:
baseline_samples_per_minute: 60 # 1秒ごと
scenarios:
5_minute_window:
total_samples: 300
adequate_for: most_systems
statistical_power: 80%
10_minute_window:
total_samples: 600
adequate_for: high_variability_systems
statistical_power: 90%
9.3 アラート設定ガイドライン
# Kayenta での重要度別アラート設定
alerting_configuration:
critical_issues:
# エラー率の大幅な増加
- metric: error_rate
p_value_threshold: 0.01
effect_size_threshold: 0.15
action: IMMEDIATE_ROLLBACK
notification: PAGE_ONCALL
# レスポンスタイムの大幅悪化
- metric: latency_p99
p_value_threshold: 0.01
effect_size_threshold: 0.2
action: IMMEDIATE_ROLLBACK
notification: PAGE_ONCALL
warning_issues:
# 軽微なメトリクス悪化
- metric: cpu_usage
p_value_threshold: 0.05
effect_size_threshold: 0.1
action: CONTINUE_MONITORING
notification: SLACK
# メモリ使用量の増加
- metric: memory_usage
p_value_threshold: 0.05
effect_size_threshold: 0.1
action: CONTINUE_MONITORING
notification: SLACK
information:
# 改善メトリクス
- metric: latency_p50
direction: IMPROVEMENT
notification: LOG_ONLY
9.4 段階的ロールアウト戦略
# 段階的ロールアウトの実装パターン
rollout_strategies:
# カンビアスロールアウト(推奨)
canary_rollout:
stages:
- name: "Canary (2%)"
percentage: 2
duration_minutes: 5
analysis_interval: 1
rollback_on: FAIL
approval_required: false
- name: "Early Adopters (10%)"
percentage: 10
duration_minutes: 10
analysis_interval: 2
rollback_on: FAIL
approval_required: false
- name: "Rolling (50%)"
percentage: 50
duration_minutes: 15
analysis_interval: 5
rollback_on: FAIL
approval_required: false
- name: "Full (100%)"
percentage: 100
duration_minutes: 0
rollback_on: NONE
approval_required: false
# ブルーグリーンロールアウト
blue_green_rollout:
pre_deployment:
- run_integration_tests: true
- smoke_tests: true
deployment:
stage_1:
percentage: 100
duration_minutes: 10
validation: AUTOMATED
stage_2:
action: SWITCH_TRAFFIC
drain_timeout_minutes: 5
post_deployment:
- health_checks: true
- monitoring_duration_minutes: 15
# 線形ロールアウト
linear_rollout:
increment_percentage: 10
increment_interval_minutes: 5
max_error_rate: 0.5
rollback_on: THRESHOLD_EXCEEDED
10. トラブルシューティングと監視
10.1 一般的な問題と解決方法
問題1:メトリクスが取得されない
診断手順:
step_1:
action: "Kayenta ログ確認"
command: |
kubectl logs -f deployment/kayenta -n spinnaker
look_for: "MetricsService" OR "Connection refused"
step_2:
action: "メトリクスデータソース接続テスト"
test: |
curl -X GET \
"http://prometheus:9090/api/v1/query?query=up" \
-H "Accept: application/json"
expected: "prometheus up"
step_3:
action: "Kayenta メトリクスエンドポイント確認"
command: |
curl -X POST \
"http://kayenta:8090/api/v1/metrics" \
-H "Content-Type: application/json" \
-d '{...query...}'
resolution: |
- ネットワーク接続確認
- メトリクスプロバイダー認証確認
- Firewall/NSP ルール確認
- メトリクスクエリの妥当性確認
問題2:判定結果が常に "UNKNOWN"
原因分析:
insufficient_data:
symptoms:
- "Insufficient data to make a judgment"
causes:
- "サンプルサイズが不足"
- "観察期間が短すぎる"
- "メトリクスデータに空白"
solutions:
- "観察期間を延長"
- "サンプリング間隔を短縮"
- "クエリを確認して正常なデータ取得を確認"
statistical_issue:
symptoms:
- "Unable to compute statistics"
causes:
- "すべてのサンプルが同じ値"
- "データの分散がゼロ"
solutions:
- "メトリクスクエリの精度確認"
- "スコープの定義を確認"
# デバッグ用ログレベル設定
kayenta_debug_config: |
logging:
level:
com.netflix.kayenta: DEBUG
com.netflix.kayenta.judge: DEBUG
com.netflix.kayenta.metrics: DEBUG
問題3:False Positive (誤検知)
症状: |
- 正常なデプロイがフェイルと判定される
- メトリクスにノイズが多い
原因:
- p値閾値が厳しすぎる
- 外れ値の影響
- メトリクス選択が不適切
解決方法:
adjust_thresholds: |
judge:
alpha: 0.05 → 0.10 # より寛容に
effectSizeThreshold: 0.1 → 0.2
filter_outliers: |
metrics:
response_time:
outlier_filter: "PERCENTILE_95" # 95パーセンタイル以下のみ使用
switch_test_method: |
judge:
judgeType: MANN_WHITNEY_PLUS_EFFECT_SIZE
# より堅牢な手法を使用
問題4:False Negative (見落とし)
症状: |
- 問題のあるデプロイが通過してしまう
- 検知漏れ
原因:
- 閾値が緩すぎる
- クリティカルメトリクスの欠落
- 観察期間が短い
解決方法:
tighten_thresholds: |
judge:
alpha: 0.05 # より厳しく
effectSizeThreshold: 0.05 → 0.05
add_critical_metrics: |
metrics:
- error_rate (critical: true)
- latency_p99 (critical: true)
- transaction_success_rate (critical: true)
increase_observation_period: |
canary:
analysisIntervalSeconds: 60
canaryAnalysisIntervals: 10 → 20 # 10分 → 20分
10.2 監視とメトリクス
# Kayenta 自身の監視設定
kayenta_monitoring:
prometheus_metrics:
# カナリア分析の実行統計
- name: kayenta_canary_executions_total
type: counter
labels:
- outcome (PASS/FAIL/SKIP/ERROR)
- application
- stage
- name: kayenta_canary_execution_duration_seconds
type: histogram
buckets: [1, 5, 10, 30, 60, 300]
labels:
- application
# メトリクス取得パフォーマンス
- name: kayenta_metrics_fetch_duration_seconds
type: histogram
labels:
- datasource
- metric_type
- name: kayenta_metrics_fetch_errors_total
type: counter
labels:
- datasource
- error_type
# 判定エンジン統計
- name: kayenta_judge_execution_duration_seconds
type: histogram
labels:
- judge_type
# Redis キャッシュ
- name: kayenta_redis_operations_total
type: counter
labels:
- operation (SET/GET/DEL)
- success
# アラート設定
alerts:
- name: KayentaHighErrorRate
expr: |
rate(kayenta_canary_executions_total{outcome="ERROR"}[5m])
>
0.1
for: 5m
severity: critical
- name: KayentaMetricsFetchFailures
expr: |
rate(kayenta_metrics_fetch_errors_total[5m]) > 0.05
for: 10m
severity: warning
- name: KayentaSlowAnalysis
expr: |
histogram_quantile(0.95,
kayenta_canary_execution_duration_seconds
)
>
600 # 10分以上
for: 15m
severity: warning
10.3 ダッシュボード例
# Grafana ダッシュボード設定
grafana_dashboard:
row_1_overview:
- panel: "Canary Pass Rate (24h)"
query: |
sum(increase(kayenta_canary_executions_total{outcome="PASS"}[24h]))
/
sum(increase(kayenta_canary_executions_total[24h]))
format: percentage
- panel: "Canary Execution Count (24h)"
query: |
sum(increase(kayenta_canary_executions_total[24h]))
by (application)
format: bar_chart
row_2_performance:
- panel: "Average Analysis Duration"
query: |
histogram_quantile(0.50,
kayenta_canary_execution_duration_seconds
)
format: seconds
- panel: "P99 Analysis Duration"
query: |
histogram_quantile(0.99,
kayenta_canary_execution_duration_seconds
)
format: seconds
row_3_errors:
- panel: "Error Rate by Type"
query: |
rate(kayenta_metrics_fetch_errors_total[5m])
by (error_type)
format: line_chart
- panel: "Failing Canaries"
query: |
topk(10,
sum(increase(kayenta_canary_executions_total{outcome="FAIL"}[24h]))
by (application)
)
format: table
10.4 パフォーマンスチューニング
# Kayenta パフォーマンス最適化
performance_tuning:
redis_optimization:
# Redis コネクション設定
redis:
jedis:
pool:
max-active: 20
max-idle: 10
min-idle: 5
timeout: 2000ms
# キャッシュ戦略
cache:
ttl: 86400 # 24時間
eviction: ALLKEYS_LRU
metrics_fetching:
# 並列取得
concurrent_fetchers: 10
# タイムアウト設定
fetch_timeout_seconds: 30
# リトライ設定
retry:
max_attempts: 3
backoff_multiplier: 2.0
initial_backoff_ms: 100
judge_engine:
# マルチスレッド処理
thread_pool_size: 8
# キャッシュメトリクス計算
statistics_cache_enabled: true
statistics_cache_ttl_minutes: 5
# ログレベルの最適化
logging:
level:
com.netflix.kayenta: INFO # 本番環境
com.netflix.kayenta.metrics: INFO
com.netflix.kayenta.judge: WARN
まとめ
Kayentaは、Netflix/Googleが開発した統計学に基づいた自動カナリア分析プラットフォームです。以下の特徴を持つため、本番環境でのリスクを軽減し、デプロイメントの信頼性を向上させます:
主要な利点
- 自動化による効率性: 手動判定から統計的自動判定へ
- 客観的判定: p値と効果量に基づいた数学的根拠
- 高い統合性: Spinnaker パイプラインへのシームレス統合
- 柔軟性: 複数のデータソース、メトリクス、判定基準に対応
- トレーサビリティ: 詳細な分析レポートと監査ログ
実装のキーポイント
- 適切なメトリクスの選定が成功の鍵
- Mann-Whitney U検定と効果量による堅牢な判定
- 段階的ロールアウトと統計サンプルサイズのバランス
- 継続的な監視と結果の検証によるチューニング
Kayentaの導入により、組織は迅速で信頼性の高いソフトウェアリリースサイクルを確立できます。