Kayenta

Kayenta: Netflixによる自動カナリア分析の全容

目次

  1. Kayentaとは何か
  2. カナリア分析の基本概念
  3. Kayentaのアーキテクチャ
  4. 主要コンポーネント
  5. メトリクス収集とデータソース統合
  6. 統計分析エンジン
  7. Spinnaker との統合
  8. 実装例と設定方法
  9. ベストプラクティス
  10. トラブルシューティングと監視

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が開発した統計学に基づいた自動カナリア分析プラットフォームです。以下の特徴を持つため、本番環境でのリスクを軽減し、デプロイメントの信頼性を向上させます:

主要な利点

  1. 自動化による効率性: 手動判定から統計的自動判定へ
  2. 客観的判定: p値と効果量に基づいた数学的根拠
  3. 高い統合性: Spinnaker パイプラインへのシームレス統合
  4. 柔軟性: 複数のデータソース、メトリクス、判定基準に対応
  5. トレーサビリティ: 詳細な分析レポートと監査ログ

実装のキーポイント

  • 適切なメトリクスの選定が成功の鍵
  • Mann-Whitney U検定と効果量による堅牢な判定
  • 段階的ロールアウトと統計サンプルサイズのバランス
  • 継続的な監視と結果の検証によるチューニング

Kayentaの導入により、組織は迅速で信頼性の高いソフトウェアリリースサイクルを確立できます。


参考資料