📄
概念 📚 software-design-concepts

データマイグレーション

スキーマ変更・データ移行の安全な実施手順とロールバック戦略・ゼロダウンタイム移行の設計

データマイグレーションとは、データベーススキーマの変更や既存データの新構造への移行を、稼働中のシステムに対して安全に行う作業を指す。単純なカラム追加であっても、テーブルロックや長時間実行によってサービスに影響を与えることがあるため、変更の種類と規模に応じた戦略の選択が重要になる。マイグレーションの失敗は即座にデータ破損やサービス停止につながるため、あらゆる変更に対してロールバック手順を事前に定義しておかなければならない。

ゼロダウンタイムマイグレーションを実現する代表的な手法がExpand-Contract(拡張-縮小)パターンである。まず新しいカラムや構造を追加し(Expand)、アプリケーション側を新旧両方に対応するよう更新した後、古い構造を削除する(Contract)という段階的なアプローチを取る。これにより、デプロイとマイグレーションを切り離し、いつでも安全にロールバックできる状態を維持できる。

大量データのマイグレーションでは、一括変換はI/Oをブロックしてサービスに影響を与えるため、バックフィル(Backfill)戦略を用いる。バックフィルとは既存データを少量ずつ新形式に変換するバッチ処理であり、レート制限と進捗モニタリングを組み合わせることで本番トラフィックへの影響を最小化する。

コードレビューで着目するポイント

  • マイグレーションのロールバックSQL(またはdown処理)が実装されているか
  • NOT NULL制約の追加など破壊的変更を行う前に、既存データへのバックフィルが完了しているか
  • インデックス追加を本番の大テーブルに対して CONCURRENTLY オプション等で非ロックで実行しているか
  • Expand-Contractパターンで段階的な変更が計画されているか(一度にスキーマ変更とアプリ変更を行っていないか)
  • バックフィルバッチにレート制限(バッチサイズ・インターバル)が設定されており、本番DBに過負荷をかけない設計か
  • マイグレーション実行時間が事前に見積もられており、メンテナンスウィンドウの計画があるか
  • マイグレーションのべき等性(複数回実行しても安全か)が確保されているか

典型的なアンチパターン

NOT NULL カラムの即時追加: 大量データが存在するテーブルへのNOT NULL制約付きカラム追加は、テーブルロックを伴い長時間サービスを止める。まずNULLABLEで追加し、バックフィルで既存データを埋め、最後にNOT NULL制約を付与するという3ステップが必要である。

ロールバック手順の未定義: 「問題が起きたら戻す」という方針だけでロールバックSQLを用意しないまま本番適用を行うと、障害時に手が止まる。特にデータを削除・変換するマイグレーションは前の状態に戻す方法を事前に検証しておく必要がある。

本番での一括バックフィル: 数千万件のデータを一つのトランザクションで更新すると、ロック競合・レプリケーション遅延・ディスクI/O枯渇を引き起こす。小さなバッチサイズ(数百〜数千件)で分割実行し、スロットリングを設けることが不可欠である。

参考リソース

  • ツール: Flyway - SQLベースのデータベースマイグレーション管理ツール
  • ツール: Liquibase - XML/YAML/SQLでマイグレーションを定義できる柔軟なツール
  • ツール: gh-ost - GitHubが開発したMySQL向けのオンラインスキーマ変更ツール
  • 書籍: 「Refactoring Databases」(Scott W. Ambler, Pramodkumar J. Sadalage) - データベースリファクタリングのパターン集
  • パターン: Expand-Contract - Martin Fowlerによるパラレルチェンジパターンの解説