LESSON 30分

ストーリー

「バックアップは取ってありますか?」「…取ってたと思います」

本番データベースの誤操作で大量のデータが消失。バックアップを確認したところ、1週間前のものしかなかった。高橋アーキテクトが厳しい顔で言う。

「バックアップは『あるかどうか』じゃない。『いつの時点に戻せるか』と『復旧にどれくらいかかるか』だ。そしてバックアップはリストアテストなしには信頼できない」


バックアップの基本指標

RPO と RTO

指標意味質問
RPO(Recovery Point Objective)許容できるデータ損失の時間「何時間前までのデータを失っても良いか?」
RTO(Recovery Time Objective)許容できる復旧時間「復旧までに何時間かかっても良いか?」
  データ損失(RPO)      ダウンタイム(RTO)
  ←─────────────→      ←─────────────→
  最後のバックアップ   障害発生   サービス復旧

サービスレベル別の指標目安

サービスレベルRPORTO
ミッションクリティカル0(ゼロ)数分金融、決済
ビジネスクリティカル1時間以内1時間以内EC、SaaS
一般業務24時間以内4時間以内社内ツール
開発・ステージング1週間24時間非本番環境

バックアップの種類

1. フルバックアップ

データベース全体のコピーを取得する。

# PostgreSQL: フルバックアップ
pg_dump -h localhost -U postgres -d myapp -F c -f backup_20240315.dump

# リストア
pg_restore -h localhost -U postgres -d myapp backup_20240315.dump

2. 差分・増分バックアップ

前回バックアップからの変更分のみ取得する。

# PostgreSQL: 物理バックアップ(pg_basebackup)
pg_basebackup -h localhost -D /backups/base -Ft -z -P

# WAL (Write-Ahead Log) の連続アーカイブ
# postgresql.conf
# archive_mode = on
# archive_command = 'cp %p /backups/wal/%f'

3. Point-in-Time Recovery(PITR)

WALを使って任意の時点に復旧する。

# 特定時刻まで復旧
# recovery.conf
restore_command = 'cp /backups/wal/%f %p'
recovery_target_time = '2024-03-15 14:30:00+09'
recovery_target_action = 'promote'

バックアップ戦略の設計

3-2-1 ルール

3つのコピー: 本番 + バックアップ2つ
2つの異なるメディア: ディスク + クラウドストレージ
1つはオフサイト: 異なるリージョン or データセンター

スケジュール例

// バックアップスケジュールの設計
const backupStrategy = {
  // フルバックアップ: 日次
  full: {
    schedule: '0 2 * * *',  // 毎日 AM 2:00
    retention: '30 days',
    storage: 's3://backups/full/',
  },

  // WALアーカイブ: 連続
  wal: {
    mode: 'continuous',
    retention: '7 days',
    storage: 's3://backups/wal/',
  },

  // スナップショット: 時間ごと(クラウドDB)
  snapshot: {
    schedule: '0 * * * *',  // 毎時
    retention: '48 hours',
  },
};

クラウドでのバックアップ

AWS RDS

// AWS RDS の自動バックアップ設定(CDK例)
import * as rds from 'aws-cdk-lib/aws-rds';

const database = new rds.DatabaseInstance(this, 'MyDB', {
  engine: rds.DatabaseInstanceEngine.postgres({
    version: rds.PostgresEngineVersion.VER_15,
  }),

  // 自動バックアップ
  backupRetention: cdk.Duration.days(30),
  preferredBackupWindow: '17:00-18:00',  // UTC (JST 02:00-03:00)

  // ポイントインタイムリカバリ
  // RDS は自動的に5分ごとのトランザクションログを保存

  // 削除保護
  deletionProtection: true,

  // マルチAZ(高可用性)
  multiAz: true,
});

手動スナップショット

# AWS CLI でスナップショット取得
aws rds create-db-snapshot \
  --db-instance-identifier myapp-db \
  --db-snapshot-identifier myapp-db-20240315-pre-migration

# スナップショットからリストア
aws rds restore-db-instance-from-db-snapshot \
  --db-instance-identifier myapp-db-restored \
  --db-snapshot-identifier myapp-db-20240315-pre-migration

リストアテスト

バックアップはリストアテストなしには信頼できない。

// リストアテストの自動化
async function weeklyRestoreTest(): Promise<TestResult> {
  const steps = [
    // 1. 最新バックアップからリストア
    async () => {
      await restoreFromLatestBackup('test-restore-db');
      return { step: 'restore', success: true };
    },

    // 2. データ整合性チェック
    async () => {
      const userCount = await testDb.query('SELECT COUNT(*) FROM users');
      const orderCount = await testDb.query('SELECT COUNT(*) FROM orders');
      return {
        step: 'integrity',
        success: userCount > 0 && orderCount > 0,
        details: { userCount, orderCount },
      };
    },

    // 3. アプリケーション接続テスト
    async () => {
      const result = await testApp.healthCheck();
      return { step: 'app_connection', success: result.ok };
    },

    // 4. テスト環境のクリーンアップ
    async () => {
      await destroyTestDatabase('test-restore-db');
      return { step: 'cleanup', success: true };
    },
  ];

  const results = [];
  for (const step of steps) {
    results.push(await step());
  }

  // 結果をSlackに通知
  await notifySlack({
    channel: '#db-ops',
    message: `Weekly restore test: ${results.every(r => r.success) ? 'PASSED' : 'FAILED'}`,
    details: results,
  });

  return { results, allPassed: results.every(r => r.success) };
}

マイグレーション前のバックアップ手順

#!/bin/bash
# pre-migration-backup.sh

set -e

DB_NAME="myapp"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="pre_migration_${TIMESTAMP}.dump"

echo "1. Taking pre-migration backup..."
pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME -F c -f $BACKUP_FILE

echo "2. Uploading to S3..."
aws s3 cp $BACKUP_FILE s3://backups/pre-migration/$BACKUP_FILE

echo "3. Verifying backup..."
pg_restore --list $BACKUP_FILE > /dev/null 2>&1

echo "4. Backup complete: $BACKUP_FILE"
echo "   To restore: pg_restore -h \$DB_HOST -U \$DB_USER -d $DB_NAME $BACKUP_FILE"

まとめ

ポイント内容
RPO/RTO許容データ損失時間と許容復旧時間を定義
バックアップ種類フル、差分/増分、PITR
3-2-1 ルール3コピー、2メディア、1オフサイト
リストアテスト定期的にリストアを検証する
マイグレーション前必ずバックアップを取得

理解度チェックリスト

  • RPO と RTO の違いを説明できる
  • バックアップの3種類を説明できる
  • 3-2-1 ルールを理解している
  • リストアテストの重要性を説明できる

次のステップ

次のレッスンではデータベースのモニタリングを学ぶ。パフォーマンスの可視化、異常検知、アラート設定で運用品質を高めよう。


推定読了時間: 30分