技術移行の進め方: ストラングラーフィグパターン・段階的移行・Blue-Green・カナリアリリース
はじめに
技術移行は、プロダクトの成長やビジネス要件の変化に伴って避けて通れない課題です。しかし、移行の失敗はサービスの停止やデータの損失、ユーザーの離脱を招く危険性があります。本記事では、安全に技術移行を進めるためのパターンと判断基準を解説します。
身近な例えで理解する技術移行
技術移行は「走っている電車の車輪を交換する」ようなものです。
- Big Bang移行 = 電車を止めて一気に交換する。最も速いが、失敗したら全てが止まる
- 段階的移行 = 車輪を1つずつ交換する。時間はかかるが、失敗しても他の車輪で走り続けられる
- ストラングラーフィグ = 新しい電車を横に走らせて、乗客を少しずつ移す。旧電車は最後に廃止
- Blue-Green = 新旧2つの電車を用意して、一気に乗客を新電車に移す。問題があればすぐ戻せる
- カナリア = 新電車にまず少数の乗客だけ乗せてテスト。問題なければ全員を移す
移行パターンの全体像
比較表
| パターン | リスク | 移行期間 | コスト | 複雑度 | ダウンタイム |
|---|
| Big Bang | 最大 | 最短 | 低い | 低い | あり |
| 段階的移行 | 中 | 長い | 中 | 中 | なし〜最小 |
| ストラングラーフィグ | 低い | 長い | 高い(並行運用) | 高い | なし |
| Blue-Green | 低い | 短い | 高い(二重環境) | 中 | なし |
| カナリアリリース | 最小 | 中 | 中 | 高い | なし |
パターン1: ストラングラーフィグパターン
概要
ストラングラーフィグ(絞め殺しのイチジク)は、Martin Fowlerが2004年に提唱した移行パターン。旧システムを稼働させたまま、新システムを徐々に構築し、機能を1つずつ新システムに移行する。
名前の由来は、熱帯のイチジクが宿主の木に巻きつき、徐々に宿主を覆い尽くし、最終的に宿主が枯れて新しい木だけが残る現象から。
仕組み
[Phase 1: 初期状態]
[ユーザー] --> [旧システム(モノリス)]
[Phase 2: ファサード導入 + 一部機能を新システムに]
[ユーザー] --> [ファサード/プロキシ]
|
+-- /users/* --> [旧システム]
+-- /products/* --> [旧システム]
+-- /search --> [新システム] ← 最初の移行対象
+-- /notifications --> [新システム]
[Phase 3: 機能を段階的に移行]
[ユーザー] --> [ファサード/プロキシ]
|
+-- /users/* --> [新システム] ← 移行完了
+-- /products/* --> [新システム] ← 移行完了
+-- /search --> [新システム]
+-- /notifications --> [新システム]
+-- /orders/* --> [旧システム] ← まだ移行中
[Phase 4: 移行完了]
[ユーザー] --> [新システム]
[旧システム: 廃止]
実装のポイント
| ポイント | 詳細 |
|---|
| ファサードの実装 | API Gatewayやリバースプロキシ(Nginx、ALB)でルーティング |
| 機能の選定順序 | リスクが低く、独立性が高い機能から移行 |
| データの同期 | 旧新システムのデータを同期するメカニズムが必要 |
| ロールバック | 各機能単位でロールバック可能な設計 |
移行順序の判断基準
| 優先度 | 特徴 | 例 |
|---|
| 高(最初に移行) | 独立性が高い、変更頻度が高い | 通知、検索 |
| 中 | 依存関係がある程度ある | 商品管理、ユーザー管理 |
| 低(最後に移行) | 核心機能、依存関係が多い | 決済、注文処理 |
メリット・デメリット
| メリット | デメリット |
|---|
| ゼロダウンタイム | 並行運用のコストが高い |
| 段階的な検証が可能 | 移行期間が長い |
| ロールバックが容易 | データ同期の複雑さ |
| チームが段階的に学習できる | ファサード層の管理コスト |
パターン2: Blue-Green デプロイメント
概要
本番環境を2つ(Blue/Green)用意し、一方で新バージョンを準備、もう一方で旧バージョンを運用する。切り替えはDNSやロードバランサーで瞬時に行う。
仕組み
[Phase 1: 初期状態 (Blue が本番)]
[ユーザー] --> [ロードバランサー] --> [Blue環境 (v1.0)]
[Green環境 (待機)]
[Phase 2: Greenに新バージョンをデプロイ]
[ユーザー] --> [ロードバランサー] --> [Blue環境 (v1.0)] ← 本番
[Green環境 (v2.0)] ← テスト中
[Phase 3: トラフィックを切り替え]
[ユーザー] --> [ロードバランサー] --> [Blue環境 (v1.0)] ← 待機(ロールバック用)
[Green環境 (v2.0)] ← 本番
[Phase 4: 問題なければBlueを更新または削除]
AWSでの実装
| 方法 | 説明 | 切替時間 |
|---|
| Route 53 Weighted Routing | DNS重み付けでトラフィックを振り分け | 数分(DNS伝播) |
| ALB Target Group | ターゲットグループの切り替え | 数秒 |
| ECS Blue/Green | CodeDeployによる自動切り替え | 数分 |
| CloudFormation Stack | スタックの切り替え | 数分 |
データベースの移行
Blue-Greenの最大の課題はデータベース。
| 方式 | 説明 | 適用 |
|---|
| 共有DB | Blue/Greenが同じDBを使う | スキーマ変更がない場合 |
| DBマイグレーション先行 | 先にDBスキーマを変更(後方互換性を保つ) | スキーマ変更がある場合 |
| DB複製 | Blue/Greenそれぞれ別DBで、データを同期 | 完全な分離が必要な場合 |
後方互換性のあるスキーマ変更
[NG: 後方互換性がない変更]
ALTER TABLE users RENAME COLUMN name TO full_name;
→ 旧バージョンが動かなくなる
[OK: 後方互換性のある変更(3ステップ)]
Step 1: 新カラムを追加(旧バージョンも動く)
ALTER TABLE users ADD COLUMN full_name VARCHAR(255);
Step 2: 新バージョンをデプロイ(両カラムに書き込み)
INSERT INTO users (name, full_name) VALUES ('田中', '田中');
Step 3: 旧カラムを削除(旧バージョンを完全に廃止後)
ALTER TABLE users DROP COLUMN name;
メリット・デメリット
| メリット | デメリット |
|---|
| 瞬時の切り替え | 二重環境のコスト |
| 即座のロールバック | DBの移行が複雑 |
| 本番同等の環境でテスト | ステートフルなシステムでは難しい |
| ダウンタイムなし | リソースが2倍必要 |
パターン3: カナリアリリース
概要
新バージョンを少数のユーザーにのみ公開し、問題がないことを確認してから段階的に全ユーザーに展開する方式。「カナリア」の名前は、炭鉱でカナリアを使って有毒ガスを検知した慣習に由来する。
仕組み
[Phase 1: カナリア開始 (5%)]
[ユーザー] --> [ロードバランサー]
|
+-- 95% --> [旧バージョン (v1.0)] (10台)
|
+-- 5% --> [新バージョン (v2.0)] (1台)
[Phase 2: 問題なし → 拡大 (25%)]
[ユーザー] --> [ロードバランサー]
|
+-- 75% --> [旧バージョン (v1.0)] (8台)
|
+-- 25% --> [新バージョン (v2.0)] (3台)
[Phase 3: 問題なし → さらに拡大 (50%)]
[ユーザー] --> [ロードバランサー]
|
+-- 50% --> [旧バージョン (v1.0)] (5台)
|
+-- 50% --> [新バージョン (v2.0)] (5台)
[Phase 4: 完全移行 (100%)]
[ユーザー] --> [ロードバランサー]
|
+-- 100% --> [新バージョン (v2.0)] (10台)
カナリアの判断基準
| メトリクス | 閾値(例) | 自動/手動 |
|---|
| エラー率 | 旧バージョンの1.5倍以下 | 自動ロールバック |
| レスポンスタイム(p99) | 旧バージョンの2倍以下 | 自動ロールバック |
| CPU/メモリ使用率 | 80%以下 | 自動アラート |
| ビジネスメトリクス | コンバージョン率が下がっていない | 手動判断 |
AWSでの実装
[ECS + CodeDeploy カナリアデプロイ]
CodeDeploy の設定:
- デプロイメントタイプ: Blue/Green (カナリア)
- トラフィック設定:
- Linear10PercentEvery1Minutes
(1分ごとに10%ずつ新バージョンに移行)
- Canary10Percent5Minutes
(最初に10%を5分間テスト、問題なければ残り90%を一気に移行)
自動ロールバックトリガー:
- CloudWatchアラーム(エラー率 > 5%)
- ヘルスチェック失敗
メリット・デメリット
| メリット | デメリット |
|---|
| リスクが最も小さい | 実装が複雑 |
| 実際のユーザートラフィックでテスト | モニタリング基盤が必要 |
| 問題を早期発見 | 新旧バージョンの互換性が必要 |
| 段階的なロールアウト | セッションの粘着性(Sticky Session)の管理 |
パターン4: 段階的移行(Feature Flag + A/B テスト)
概要
Feature Flag(機能フラグ)を使って、同一バージョンのアプリケーション内で新旧の機能を切り替える方式。
仕組み
[同一アプリケーション内での切り替え]
function getTimeline(userId) {
if (featureFlag.isEnabled('new-timeline', userId)) {
// 新しいタイムラインアルゴリズム
return newTimelineService.get(userId);
} else {
// 旧タイムラインアルゴリズム
return oldTimelineService.get(userId);
}
}
Feature Flagツール
| ツール | 特徴 | 料金 |
|---|
| LaunchDarkly | 業界標準、豊富な機能 | $10/月〜 |
| Unleash | OSS、セルフホスト可能 | 無料(OSS) |
| PostHog | 分析ツール統合 | 無料枠あり |
| AWS AppConfig | AWS統合 | 従量課金 |
| 自作 | DB/Redisベース | 無料 |
Feature Flagの活用パターン
| パターン | 説明 | 例 |
|---|
| リリーストグル | 新機能の段階的公開 | 新UIを10%のユーザーに公開 |
| 実験トグル | A/Bテスト | 新しいレコメンドアルゴリズムのテスト |
| 運用トグル | 障害時の機能無効化 | 負荷が高い時に重い機能をオフ |
| 権限トグル | ユーザー種別での機能制御 | プレミアムユーザーのみの機能 |
データベース移行の実践
DBマイグレーションの安全な進め方
[安全なDB移行の手順]
Phase 1: 準備(ダウンタイムなし)
├── 新カラム/テーブルを追加(既存に影響なし)
├── アプリを更新(新旧両方に書き込み)
└── データ同期ジョブで既存データを移行
Phase 2: 切り替え(ダウンタイムなし)
├── アプリの読み取りを新カラム/テーブルに変更
├── 旧カラム/テーブルへの書き込みを停止
└── 動作確認
Phase 3: クリーンアップ(ダウンタイムなし)
├── 旧カラム/テーブルを削除
└── マイグレーションジョブを削除
大規模データ移行のパターン
| パターン | 適用 | ツール |
|---|
| AWS DMS | RDB間の移行 | AWS Database Migration Service |
| ダンプ&リストア | 小規模DB | pg_dump/pg_restore |
| 論理レプリケーション | ゼロダウンタイム移行 | PostgreSQL Logical Replication |
| 段階的移行 | テーブル単位の移行 | 自作スクリプト + SQS |
移行判断のチェックリスト
移行を開始する前のチェック
| チェック項目 | 確認内容 |
|---|
| 移行の目的は明確か | パフォーマンス?コスト?保守性? |
| ROIは算出したか | 移行コスト vs 移行後のメリット |
| タイムラインは現実的か | 十分なバッファがあるか |
| ロールバック計画はあるか | 失敗時にどう戻すか |
| チームのスキルは十分か | 新技術の学習期間を確保 |
| テスト計画はあるか | 移行後の動作確認方法 |
| ステークホルダーの合意は | ビジネス側の理解と承認 |
| データのバックアップは | 移行前の完全バックアップ |
移行中のチェック
| チェック項目 | 確認内容 |
|---|
| メトリクスを監視しているか | エラー率、レスポンスタイム |
| ロールバックの準備は整っているか | いつでも戻せる状態 |
| コミュニケーションは取れているか | チーム間の情報共有 |
| ドキュメントは更新しているか | 移行の進捗と決定事項 |
移行後のチェック
| チェック項目 | 確認内容 |
|---|
| 全機能が正常動作しているか | E2Eテストの実行 |
| パフォーマンスは改善したか | 移行前後の比較 |
| 旧システムは安全に廃止できるか | 依存関係の確認 |
| チームは新システムを理解しているか | ドキュメント、トレーニング |
| モニタリングは適切か | アラート設定の確認 |
移行パターンの選び方
[移行パターン選定フロー]
|
v
[移行対象は?]
|
+-- インフラ(サーバー、DB等)
| |
| +-- [ダウンタイムが許容できる?]
| |
| +-- はい --> Big Bang or Blue-Green
| |
| +-- いいえ --> Blue-Green or ストラングラーフィグ
|
+-- アプリケーション(言語、FW変更)
| |
| +-- [段階的に移行できる?]
| |
| +-- はい --> ストラングラーフィグ
| |
| +-- いいえ --> Blue-Green + 十分なテスト
|
+-- 機能リリース(新機能の展開)
|
+-- [リスクが高い変更?]
|
+-- はい --> カナリアリリース + Feature Flag
|
+-- いいえ --> ローリングアップデート
実際の企業での移行事例
Amazon: モノリスからマイクロサービスへ
| 時期 | 内容 |
|---|
| 2001年 | 巨大なモノリス(内部では「The Big Ball of Mud」と呼ばれた) |
| 2002年 | Jeff Bezosの「API Mandate」(全チームはAPIでのみ通信すること) |
| 2002-2006年 | 段階的にサービスを分離 |
| 2006年 | AWS誕生(自社のインフラをサービス化) |
Stripe: Ruby→Go への段階的移行
| 内容 | 詳細 |
|---|
| 移行対象 | 決済処理のコア部分 |
| 移行方式 | ストラングラーフィグパターン |
| 期間 | 数年にわたる段階的移行 |
| ポイント | 決済処理という最もリスクの高い部分を慎重に移行 |
GitHub: MySQL→Vitess への移行
| 内容 | 詳細 |
|---|
| 移行対象 | メインデータベース |
| 移行方式 | 段階的移行 + Shadow Traffic |
| 期間 | 数年 |
| ポイント | Shadow Traffic(新システムにも同じリクエストを送って結果を比較)で安全性を確保 |
Shadow Traffic パターン
概要
本番トラフィックのコピーを新システムに送り、結果を比較する方法。実際のユーザーには影響を与えずに、新システムの正確性とパフォーマンスを検証できる。
[ユーザー] --> [プロキシ]
|
+-- [旧システム] --> [レスポンスをユーザーに返す]
|
+-- [新システム] --> [レスポンスを比較のみ(返さない)]
|
[結果を比較/記録]
- レスポンスの一致率
- レスポンスタイム
- エラー率
Shadow Trafficのメリット
| メリット | 詳細 |
|---|
| ゼロリスク | ユーザーには一切影響がない |
| 本番データでテスト | テストデータでは見つからない問題を発見 |
| パフォーマンス比較 | 新旧システムのパフォーマンスを正確に比較 |
| 段階的な信頼構築 | 一致率が上がるにつれて移行の信頼性が高まる |
まとめ
各パターンの使い分け
| パターン | 最適なケース |
|---|
| ストラングラーフィグ | 大規模なアプリケーション移行 |
| Blue-Green | インフラ移行、メジャーバージョンアップ |
| カナリア | 新機能リリース、リスクの高い変更 |
| Feature Flag | 機能単位の段階的公開、A/Bテスト |
| Shadow Traffic | DB移行、アルゴリズム変更 |
移行の鉄則
| 鉄則 | 詳細 |
|---|
| Big Bangを避ける | 一度に全てを変えない |
| ロールバック計画を立てる | 失敗時の対応を事前に決める |
| メトリクスを監視する | 数値に基づいて判断する |
| 小さく始める | 最もリスクが低い部分から |
| ドキュメントを残す | 移行の経緯と判断を記録 |
技術移行は「いかに安全に進めるか」が最も重要。新技術への期待よりも、既存ユーザーへの影響を最小限にすることを常に最優先に考えるべきである。
参考リンク