LESSON 30分

ストーリー

佐藤CTO
SREの基本原則は理解できたな。次は信頼性を定量的に扱う方法を学ぼう
佐藤CTO
『システムが落ちた』だけでは情報が足りない。どのくらいの頻度で落ちるのか落ちたときにどれくらいで復旧するのかいつ気づけるのか — これらを数値で把握できなければ、改善もできない

佐藤CTOはホワイトボードにタイムラインを描き始めました。

佐藤CTO
信頼性のメトリクスと可用性の計算方法を、しっかり身につけよう

信頼性メトリクス:MTBF / MTTR / MTTD

信頼性を定量的に評価するための主要メトリクスを理解しましょう。

メトリクスの全体像

graph LR
    A["障害発生"] --> B["検知<br/>(MTTD)"] --> C["対応開始<br/>(MTTA)"] --> D["復旧完了<br/>(MTTR)"] --> E["正常稼働期間"] --> F["次の障害発生"]

    A -.->|"MTBF(障害間の平均時間)"| F

各メトリクスの定義

メトリクス正式名称定義理想的な方向
MTBFMean Time Between Failures障害と障害の間の平均時間長いほど良い
MTTDMean Time To Detect障害発生から検知までの平均時間短いほど良い
MTTAMean Time To Acknowledge障害発生から対応開始までの平均時間短いほど良い
MTTRMean Time To Recovery障害発生から復旧完了までの平均時間短いほど良い

メトリクスの計算例

interface Incident {
  id: string;
  occurredAt: Date;     // 障害発生時刻
  detectedAt: Date;     // 検知時刻
  acknowledgedAt: Date; // 対応開始時刻
  resolvedAt: Date;     // 復旧完了時刻
}

function calculateReliabilityMetrics(incidents: Incident[]) {
  const sorted = incidents.sort(
    (a, b) => a.occurredAt.getTime() - b.occurredAt.getTime()
  );

  // MTTD: 検知までの平均時間
  const mttd =
    sorted.reduce((sum, inc) => {
      return sum + (inc.detectedAt.getTime() - inc.occurredAt.getTime());
    }, 0) / sorted.length;

  // MTTA: 対応開始までの平均時間
  const mtta =
    sorted.reduce((sum, inc) => {
      return sum + (inc.acknowledgedAt.getTime() - inc.occurredAt.getTime());
    }, 0) / sorted.length;

  // MTTR: 復旧までの平均時間
  const mttr =
    sorted.reduce((sum, inc) => {
      return sum + (inc.resolvedAt.getTime() - inc.occurredAt.getTime());
    }, 0) / sorted.length;

  // MTBF: 障害間の平均時間
  let mtbf = 0;
  if (sorted.length > 1) {
    const intervals = sorted.slice(1).map((inc, i) => {
      return inc.occurredAt.getTime() - sorted[i].occurvedAt.getTime();
    });
    mtbf = intervals.reduce((sum, v) => sum + v, 0) / intervals.length;
  }

  return {
    mttd: mttd / (1000 * 60),   // 分単位
    mtta: mtta / (1000 * 60),
    mttr: mttr / (1000 * 60),
    mtbf: mtbf / (1000 * 60 * 60), // 時間単位
  };
}

MTTRの改善戦略

改善対象手法効果
MTTD(検知時間)アラート閾値の最適化、合成監視障害を素早く発見
MTTA(応答時間)オンコール体制、PagerDuty連携対応者を素早くアサイン
診断時間ランブック整備、ダッシュボード原因を素早く特定
修復時間自動復旧、ロールバック自動化修復を素早く完了

可用性のNines(9の数)

可用性の計算

可用性は以下の公式で計算されます。

可用性 = 稼働時間 / (稼働時間 + ダウンタイム) × 100%

または

可用性 = MTBF / (MTBF + MTTR) × 100%

Ninesテーブル

可用性Nines年間ダウンタイム月間ダウンタイム週間ダウンタイム
90%One Nine36.5日72時間16.8時間
99%Two Nines3.65日7.2時間1.68時間
99.9%Three Nines8.76時間43.2分10.1分
99.95%Three and a half4.38時間21.6分5.04分
99.99%Four Nines52.6分4.32分1.01分
99.999%Five Nines5.26分25.9秒6.05秒

Ninesの「壁」

xychart-beta
    title "可用性とコストの関係(各Nineで約10倍増)"
    x-axis ["99%", "99.9%", "99.99%", "99.999%"]
    y-axis "コスト(相対)" 0 --> 1100
    line [1, 10, 100, 1000]

コンポーネントの可用性計算

システム全体の可用性は、最も弱いコンポーネントに引きずられます。

// 直列構成: 全コンポーネントが稼働する必要がある
function serialAvailability(components: number[]): number {
  return components.reduce((acc, avail) => acc * avail, 1);
}

// 並列構成(冗長化): どれか1つが稼働していればよい
function parallelAvailability(components: number[]): number {
  const unavailability = components.reduce(
    (acc, avail) => acc * (1 - avail),
    1
  );
  return 1 - unavailability;
}

// 例: Webサーバー(99.9%) → API(99.9%) → DB(99.9%)の直列構成
const serialResult = serialAvailability([0.999, 0.999, 0.999]);
// 結果: 0.997 = 99.7%(Three Ninesが維持できない!)

// 例: DB を2台で冗長化(各99.9%)
const dbRedundant = parallelAvailability([0.999, 0.999]);
// 結果: 0.999999 = 99.9999%

// 冗長化DBを使った直列構成
const improvedResult = serialAvailability([0.999, 0.999, dbRedundant]);
// 結果: 0.998 = 99.8%
実サービスの可用性目標の例
サービス公表SLANines
AWS EC299.99%Four Nines
AWS S399.99%Four Nines
AWS RDS (Multi-AZ)99.95%Three and a half
Google Cloud Compute99.99%Four Nines
Azure Virtual Machines99.99%Four Nines
Stripe API99.99%Four Nines

注意: クラウドプロバイダのSLAは「リージョン内の冗長構成」が前提です。単一インスタンスでの可用性はこれより低くなります。


ダウンタイムのコスト

信頼性の投資判断を行うには、ダウンタイムの事業コストを理解する必要があります。

ダウンタイムコストの計算

interface DowntimeCostModel {
  revenuePerHour: number;        // 時間あたりの売上
  employeeCostPerHour: number;   // 影響を受ける従業員の時間あたりコスト
  affectedEmployees: number;     // 影響を受ける従業員数
  reputationMultiplier: number;  // ブランド毀損係数(1.0〜3.0)
  slaViolationCost: number;      // SLA違反時のペナルティ/時間
}

function calculateDowntimeCost(
  model: DowntimeCostModel,
  downtimeHours: number
): {
  revenueLoss: number;
  productivityLoss: number;
  reputationCost: number;
  slaPenalty: number;
  totalCost: number;
} {
  const revenueLoss = model.revenuePerHour * downtimeHours;
  const productivityLoss =
    model.employeeCostPerHour * model.affectedEmployees * downtimeHours;
  const reputationCost =
    revenueLoss * (model.reputationMultiplier - 1);
  const slaPenalty = model.slaViolationCost * downtimeHours;

  return {
    revenueLoss,
    productivityLoss,
    reputationCost,
    slaPenalty,
    totalCost: revenueLoss + productivityLoss + reputationCost + slaPenalty,
  };
}

// 例: ECサイトの1時間ダウンタイムコスト
const ecSite: DowntimeCostModel = {
  revenuePerHour: 500_000,       // 時間あたり50万円の売上
  employeeCostPerHour: 5_000,    // 1人あたり5,000円/時間
  affectedEmployees: 20,         // 20名の従業員に影響
  reputationMultiplier: 1.5,     // ブランド毀損50%
  slaViolationCost: 100_000,     // SLA違反ペナルティ10万円/時間
};

const cost = calculateDowntimeCost(ecSite, 1);
// revenueLoss:     500,000円
// productivityLoss: 100,000円
// reputationCost:   250,000円
// slaPenalty:       100,000円
// totalCost:        950,000円 (1時間で約95万円の損失)

可用性レベルごとのコスト比較

可用性年間ダウンタイム年間コスト(上記モデル)追加投資目安
99%87.6時間約8,300万円ベースライン
99.9%8.76時間約830万円+数百万円/年
99.95%4.38時間約416万円+数千万円/年
99.99%52.6分約83万円+数億円/年

「この数字を見れば、どこまでの可用性に投資すべきかが判断できる。99.9%から99.99%への改善に年間数億円かける価値があるかは、ビジネスの規模と性質次第だ」 — 佐藤CTO


信頼性の設計原則

Failure is Inevitable(障害は必ず起きる)

graph TD
    T["<b>信頼性の設計原則</b>"]
    P1["1. Design for Failure(障害前提設計)<br/>障害は「もし」ではなく「いつ」の問題"]
    P2["2. Defense in Depth(多層防御)<br/>単一の防御策に頼らない"]
    P3["3. Graceful Degradation(優雅な劣化)<br/>全部落とすより一部を維持する"]
    P4["4. Blast Radius Reduction(影響範囲縮小)<br/>障害の影響を限定的に抑える"]
    P5["5. Automation First(自動化優先)<br/>人間の判断を減らし、復旧を自動化する"]

    T --> P1
    T --> P2
    T --> P3
    T --> P4
    T --> P5

    style T fill:#e3f2fd,stroke:#1565c0,stroke-width:2px

Graceful Degradation の実装例

interface ServiceResponse<T> {
  data: T | null;
  degraded: boolean;
  fallbackUsed: boolean;
  source: 'primary' | 'cache' | 'fallback';
}

class ResilientProductService {
  constructor(
    private primaryDb: Database,
    private cache: CacheStore,
    private fallbackData: FallbackProvider,
  ) {}

  async getProduct(id: string): Promise<ServiceResponse<Product>> {
    // 1. まずプライマリDBを試行
    try {
      const product = await this.primaryDb.findProduct(id);
      await this.cache.set(`product:${id}`, product, 300); // 5分キャッシュ
      return {
        data: product,
        degraded: false,
        fallbackUsed: false,
        source: 'primary',
      };
    } catch (primaryError) {
      console.warn(`Primary DB failed for product ${id}:`, primaryError);
    }

    // 2. キャッシュにフォールバック
    try {
      const cached = await this.cache.get<Product>(`product:${id}`);
      if (cached) {
        return {
          data: cached,
          degraded: true,
          fallbackUsed: false,
          source: 'cache',
        };
      }
    } catch (cacheError) {
      console.warn(`Cache failed for product ${id}:`, cacheError);
    }

    // 3. 最終フォールバック(静的データ)
    try {
      const fallback = await this.fallbackData.getProduct(id);
      return {
        data: fallback,
        degraded: true,
        fallbackUsed: true,
        source: 'fallback',
      };
    } catch {
      return {
        data: null,
        degraded: true,
        fallbackUsed: true,
        source: 'fallback',
      };
    }
  }
}

まとめ

ポイント内容
MTBF/MTTR/MTTD信頼性を定量的に測定する基本メトリクス
可用性のNines99.9%と99.99%の差は約8時間 vs 53分(年間ダウンタイム)
コンポーネント計算直列構成では可用性が掛け算で低下、冗長化で改善
ダウンタイムコスト事業コストを算出して適切な投資判断を行う
設計原則障害前提設計、多層防御、優雅な劣化

チェックリスト

  • MTBF/MTTR/MTTDの定義と計算方法を理解した
  • 可用性のNinesテーブルを説明できる
  • コンポーネントの直列・並列構成の可用性計算ができる
  • ダウンタイムのビジネスコストを見積もれる
  • 信頼性の設計原則(障害前提設計、Graceful Degradation)を理解した

次のステップへ

次は「エラーバジェットの考え方」を学びます。100%の信頼性を目指さない — SREの最も革新的な概念であるエラーバジェットの仕組みと活用方法を深掘りしましょう。


推定読了時間: 30分