ストラングラーフィグパターン: モノリシックアプリケーションを移行する安全な方法

ストラングラーフィグパターン: モノリシックアプリケーションを移行する安全な方法

現代のソフトウェア エンジニアリングでは、レガシーのモノリシック アプリケーションが共通の課題となっています。時間が経つにつれて、成功したコードベースは非常に大きくなり相互接続されるため、単純な変更を行うのは危険になり、デプロイには数時間かかり、個々の機能を拡張することは事実上不可能になります。

チームがマイクロサービスに移行してシステムを最新化することを決定したとき、現在のビジネスを中断することなくシステムを書き直すにはどうすればよいですか? という一か八かの質問に直面します。

選択肢の 1 つは、「ビッグバン」書き換えです。つまり、密室で新しいシステムをゼロから構築し、1 日ですべてを切り替えることです。ただし、これは非常に危険であり、多くの場合失敗につながります。

幸いなことに、より安全で信頼性の高い代替手段、ストラングラー フィグ パターンがあります。このガイドでは、ストラングラー フィグ パターンとは何なのか、なぜ機能するのか、そして明確な図と実際のコードを使用してそれを段階的に適用する方法を説明します。


現実世界のたとえ: ストラングラー イチジクの植物

このパターンは、熱帯雨林に自生する植物であるストラングラー イチジクにちなんで名付けられました。

ストラングラー イチジクの種子は、既存の「宿主」の木の上部の枝で発芽します。イチジクは地面から上に成長するのではなく、下に向かって成長します。

  1. 根を宿主の木の幹に送り込み、林床に到達して土壌に固定します。
  2. 時間の経過とともに、より多くの根が成長し、宿主の周りを包み込み、融合します。
  3. イチジクは、宿主の木に届く光を遮る葉を生やします。
  4. 最終的に、宿主の木は枯れて腐り、中空のストラングラー イチジクの木がその場所にしっかりと立っています。

ソフトウェア アーキテクチャでは、従来のモノリス がホスト ツリーであり、新しいマイクロサービス が絞殺図です。私たちはモノリスのエッジの周りに新しいサービスを構築し、モノリスが完全にシャットダウンできるまでトラフィックをレガシー システムから徐々に移行させます。


「ビッグバン」書き換えが失敗する理由

ストラングラー フィグ パターンの仕組みに入る前に、代替案 (完全な書き換え) がなぜ非常に危険なのかを理解しましょう。

  • 数か月 (または数年) では価値がありません: 開発者はコードの作成に長い時間を費やしますが、プロジェクト全体が完了するまではコードが実際に公開されることはありません。
  • スコープ クリープ: 2 年間の書き換え中に、ビジネス ニーズが変化します。ターゲットは移動し、新しいシステムは書き換え開始時には存在しなかった機能をサポートする必要があります。
  • 暗黙的な動作の欠落: Monoliths には、文書化されていないバグ修正とエッジケースの処理が何年にもわたって含まれています。白紙の状態で書き直すと、これらの詳細が忘れられることがよくあります。
  • 導入リスクが高い: 大規模なレガシー システムをオフにして新しいシステムを一度にオンにすると、何か問題が発生した場合に大きな爆発範囲が発生します。

ストラングラーフィグパターンの仕組み

Strangler Fig パターンの中心となるアイデアは 増分移行 です。システム全体を移行するのではなく、一度に 1 つの小さな機能、つまり「スライス」を移行します。

ストラングラー フィグ パターンの移行段階図

移行プロセスは、次の 5 つの主要な段階で実行されます。

1. 境界のあるコンテキストを特定する

モノリスを見て、簡単に抽出できる単一の自己完結型ビジネス機能を特定します。良い候補者は次のとおりです。

  • 頻繁に変更される機能 (そのため、チームは独立したデプロイメントからすぐに利益を得ることができます)。
  • 移行パイプラインをテストするためのシンプルでリスクの低い機能 (静的な FAQ やユーザー設定セクションなど)。
  • クリーンで明確に定義されたデータベース境界を持つ機能。

2. 新しいマイクロサービスを実装する

特定された機能をまったく新しい最新のマイクロサービスとして構築します。このサービスには独自のデータベースと独自のデプロイメント パイプラインがあり、最新の技術スタックを使用して構築されています。重要なのは、モノリスの古い機能が今のところアクティブで変更されていないことです。

3. インターセプト層の導入

ユーザーに対して移行を透過的にするには、アプリケーションの前に インターセプト レイヤー (API ゲートウェイやリバース プロキシなど) を導入します。すべてのクライアント トラフィックは最初にこのゲートウェイに送られるようになります。

最初に、ゲートウェイはすべてのリクエストを 100% レガシー モノリスにルーティングします。

4. 段階的にトラフィックを移行する

新しいマイクロサービスが完全にテストされ準備が完了したら、インターセプト層のルーティング ルールを更新します。移行された機能 (/api/users など) に対するリクエストをモノリスにルーティングする代わりに、ゲートウェイはリクエストを新しいマイクロサービスにリダイレクトします。

他のすべてのリクエストは引き続きモノリスに送られます。新しいサービスに障害が発生した場合、またはバグが発生した場合は、ゲートウェイをすぐに更新してトラフィックをモノリスにルーティングし、中断を最小限に抑えることができます。

5. 廃止と繰り返し

新しいマイクロサービスが一定期間安定して実行された後、レガシー モノリス内の対応するコードを安全に削除できます。

次に、次の機能を選択し、このプロセスを繰り返します。時間の経過とともに、モノリスはトラフィックがなくなるまで縮小し、レガシー サーバーを完全に廃止できます。


インターセプト層: エクスプレス ルーティングの例

ストラングラー フィグ パターンの中心は インターセプト レイヤー です。これにより、クライアント アプリケーション (Web アプリ、モバイル アプリ) を変更せずにリクエストをリダイレクトできます。

ここでは、Express ベースのゲートウェイ プロキシを使用した実際的な Node.js の例を示します。リクエストを動的にルーティングします。受信リクエストが移行されたパスと一致する場合、新しいサービスに送られます。それ以外の場合は、従来のモノリスに戻ります。

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
const PORT = 8080;

// Configuration: Target server URLs
const LEGACY_MONOLITH_URL = 'http://legacy-monolith-server:3000';
const NEW_USER_SERVICE_URL = 'http://new-user-service:3001';
const NEW_PAYMENT_SERVICE_URL = 'http://new-payment-service:3002';

// Simple logging middleware to track traffic distribution
app.use((req, res, next) => {
    console.log(`[ROUTE LOG] Incoming request: ${req.method} ${req.url}`);
    next();
});

// 1. MIGRATED: User registration & profile requests route to the new microservice
app.use('/api/users', createProxyMiddleware({
    target: NEW_USER_SERVICE_URL,
    changeOrigin: true,
    pathRewrite: {
        '^/api/users': '/v1/users', // Translate path format if necessary
    }
}));

// 2. MIGRATED: Payment transactions route to the new payment microservice
app.use('/api/payments', createProxyMiddleware({
    target: NEW_PAYMENT_SERVICE_URL,
    changeOrigin: true
}));

// 3. FALLBACK: All other legacy routes automatically default to the Monolith
app.use('/', createProxyMiddleware({
    target: LEGACY_MONOLITH_URL,
    changeOrigin: true
}));

app.listen(PORT, () => {
    console.log(`Interception Gateway routing traffic successfully on port ${PORT}`);
});

データベースの処理: 最も難しい部分

API トラフィックのルーティングは比較的簡単ですが、データの管理はモノリシック移行の最も困難な側面です。モノリスには通常、テーブルが高度に結合された単一の大規模データベースがあります。

サービスを抽出するときは、そのデータも抽出する必要があります。これを処理するには、次の 2 つの一般的なアプローチがあります。

  1. 二重書き込み: インターセプト層またはアプリケーションは、移行フェーズ中にレガシー データベースと新しいサービス データベースの両方に同時にデータを書き込みます。これにより、両方のデータベースの同期が維持されます。
  2. 変更データ キャプチャ (CDC): Debezium などのツールは、レガシー データベースのトランザクション ログを監視し、変更を新しいマイクロサービス データベースにほぼリアルタイムで自動的にストリーミングします。

データベースが完全に同期され、新しいデータベースが正しいことが確認できたら、読み取りトラフィックを新しいサービスに切り替え、レガシー テーブルをシャットダウンします。


比較: Big Bang Rewrite と Strangler Fig

機能/指標 ビッグバンリライト ストラングラーフィグパターン
リスクレベル 非常に高い 低コストで管理された
フィードバック ループ 非常に遅い (最後のみ) 高速 (継続的な実稼働テスト)
ロールバック戦略 ハード (バックアップの復元が必要) 簡単 (ゲートウェイでルート ルールを変更)
ビジネスへの影響 破壊的 ダウンタイムゼロ
システムの複雑さ 高 (ビルド段階中) 高 (移行フェーズ中)
展開時間 大量シングルリリース 小規模で頻繁なアップデート

## 結論

Strangler Fig パターンは、モノリスをマイクロサービスに移行するための業界標準です。レガシーコードを一度に置き換えるのではなく段階的に置き換えることで、「ビッグバン」障害のリスクを排除できます。

デプロイメントを小規模に保ち、実際の運用トラフィックからの即時フィードバックを提供し、チームが移行ライフサイクル全体を通じてビジネス価値を提供し続けることができるようにします。

データベースの移行を管理し、2 つの並列システムを実行すると運用が複雑になりますが、安全性、予測可能性、安定性が提供されるため、最新のクラウド移行には推奨される選択肢となっています。


Ghaznix ブログでソフトウェア開発とバックエンド エンジニアリングの洞察をさらに詳しく見る→