モノリスからマイクロサービスへのリファクタリング

NGINX | 2016年3月08日

編集者注 – 全7回の記事シリーズが完結しました:

  1. マイクロサービス入門
  2. マイクロサービスの構築:APIゲートウェイの使用
  3. マイクロサービスの構築:マイクロサービスアーキテクチャにおけるプロセス間通信
  4. マイクロサービスアーキテクチャにおけるサービスディスカバリ
  5. マイクロサービス向けイベント駆動型データ管理
  6. マイクロサービスのデプロイ戦略の選択
  7. モノリスをマイクロサービスにリファクタリングする(本記事)

一連の記事に加え、NGINX Plusを使用したマイクロサービスの実装に関する情報をまとめた電子書籍「マイクロサービス:設計からデプロイまで」もダウンロードできます。また、マイクロサービスリファレンスアーキテクチャのシリーズと、マイクロサービスソリューションのページもご覧ください。

本稿は、マイクロサービスを使用したアプリケーション構築に関するシリーズの第7回であり、最終回です。第1回の記事では、マイクロサービスアーキテクチャパターンを紹介し、マイクロサービスを使用するメリットとデメリットについて説明しています。以降の記事では、マイクロサービスアーキテクチャのさまざまな側面を取り上げています。具体的には、API Gatewayの使用<.htmla>、プロセス間通信、サービスディスカバリ、イベント駆動型データ管理、およびマイクロサービスのデプロイです。本稿では、モノリシックアプリケーションをマイクロサービスへ移行するための戦略について説明します。

この一連の記事を通じて、マイクロサービスアーキテクチャ、そのメリットとデメリット、そしてどのような場合に採用すべきかについて、理解を深めていただけたなら幸いです。マイクロサービスアーキテクチャは、皆さまの組織にも適しているかもしれません。

しかし、実際には大規模で複雑なモノリシックアプリケーションに取り組んでいる可能性がかなり高いでしょう。日々のアプリケーション開発とデプロイには時間がかかり、苦労が絶えません。マイクロサービスは、はるか遠くの理想郷のように思えるかもしれません。幸い、モノリシック地獄から抜け出すための戦略があります。この記事では、モノリシックアプリケーションを段階的にリファクタリングし、複数のマイクロサービスへと移行する方法を説明します。

マイクロサービスへのリファクタリングの概要

モノリシックアプリケーションをマイクロサービスへ移行するプロセスは、アプリケーションモダナイゼーションの一形態です。これは、開発者が数十年にわたって取り組んできたことです。そのため、アプリケーションをマイクロサービスへリファクタリングする際に再利用できる考え方がいくつかあります。

避けるべき戦略の1つが、「ビッグバン」方式の書き換えです。これは、開発リソースをすべて投入し、マイクロサービスベースの新しいアプリケーションをゼロから構築する手法です。魅力的に思えるかもしれませんが、リスクが極めて高く、失敗に終わる可能性が高い手法です。Martin Fowlerが語ったとされるように、「ビッグバン方式の書き換えが保証するのは、ビッグバンだけです!」

Big Bangリライトではなく、モノリシックアプリケーションを段階的にリファクタリングすることを推奨します。マイクロサービスで構成される新しいアプリケーションを徐々に構築し、モノリシックアプリケーションと並行して稼働させます。時間の経過とともに、モノリシックアプリケーションが担う機能を減らしていき、最終的には完全に廃止するか、1つのマイクロサービスとして残します。この戦略は、高速道路を時速70マイルで走行しながら車を整備するようなものです。容易ではありませんが、Big Bangリライトを試みるよりもはるかにリスクを抑えられます。

Martin Fowlerは、このアプリケーションモダナイゼーション戦略を「Strangler Application」と呼んでいます。この名称は、熱帯雨林に生育する絞め殺し植物(別名、絞め殺しイチジク)に由来します。絞め殺し植物は、林冠の上から差し込む日光を得るため、樹木に巻き付いて成長します。やがて樹木が枯れ、樹木の形をしたつるだけが残ることもあります。アプリケーションモダナイゼーションも同じパターンに従います。レガシーアプリケーションを取り囲むように、マイクロサービスで構成される新しいアプリケーションを構築し、最終的にレガシーアプリケーションを廃止します。

これを実現するためのさまざまな戦略を見ていきましょう。

戦略1 – 深追いしない

「穴の法則」では、穴に落ちたら掘るのをやめるべきだとされています。これは、モノリシックアプリケーションが管理不能になった場合に従うべき優れた助言です。つまり、モノリスをこれ以上大きくしないことです。そのため、新しい機能を実装する際は、モノリスにコードを追加してはなりません。代わりに、この戦略では、その新しいコードを独立したマイクロサービスに配置することが重要です。次の図は、このアプローチを適用した後のシステムアーキテクチャを示しています。

新しいサービスと従来のモノリスに加えて、ほかに2つのコンポーネントがあります。1つ目は、受信したHTTPリクエストを処理するリクエストルーターです。これは、以前の記事<.htmla>で説明したAPIゲートウェイに似ています。ルーターは、新機能に対応するリクエストを新しいサービスに送信し、従来のリクエストをモノリスにルーティングします。

もう1つのコンポーネントは、サービスとモノリスを統合するグルーコードです。サービスが単独で存在することはほとんどなく、多くの場合、モノリスが所有するデータにアクセスする必要があります。モノリス、サービス、またはその両方に配置されるグルーコードが、データ統合を担います。サービスはグルーコードを使用して、モノリスが所有するデータを読み書きします。

サービスがモノリスのデータにアクセスする方法には、次の3つがあります。

  • モノリスが提供するリモートAPIを呼び出す
  • モノリスのデータベースに直接アクセスする
  • 独自のデータコピーを保持し、モノリスのデータベースと同期する

グルーコードは、腐敗防止層と呼ばれることもあります。これは、独自の純粋なドメインモデルを持つサービスに、レガシーモノリスのドメインモデルの概念が入り込むのをグルーコードが防ぐためです。グルーコードは、異なる2つのモデル間を変換します。「腐敗防止層」という用語は、Eric Evansの必読書『Domain Driven Design』で初めて登場し、その後、ホワイトペーパーでさらに洗練されました。腐敗防止層の開発は、決して容易ではない場合があります。しかし、モノリス地獄から段階的に脱却するには、腐敗防止層の構築が不可欠です。

新しい機能を軽量なサービスとして実装することには、いくつかのメリットがあります。モノリスがさらに管理しにくくなるのを防げます。また、そのサービスはモノリスとは独立して開発、デプロイ、スケーリングできます。新しいサービスを作成するたびに、マイクロサービスアーキテクチャのメリットを得られます。

しかし、このアプローチではモノリスの問題は解決できません。問題を解決するには、モノリスを分割する必要があります。そのための戦略を見ていきましょう。

戦略2 – フロントエンドとバックエンドの分離

モノリシックアプリケーションを縮小する戦略の1つは、プレゼンテーション層をビジネスロジック層およびデータアクセス層から分離することです。一般的なエンタープライズアプリケーションは、少なくとも次の3種類のコンポーネントで構成されます。

  • プレゼンテーション層 – HTTPリクエストを処理し、(REST)APIまたはHTMLベースのWeb UIを実装するコンポーネント。高度なユーザーインターフェースを備えたアプリケーションでは、プレゼンテーション層が大規模なコード群となることも少なくありません。
  • ビジネスロジック層 – アプリケーションの中核を成し、ビジネスルールを実装するコンポーネント。
  • データアクセス層 – データベースやメッセージブローカーなどのインフラストラクチャコンポーネントにアクセスするコンポーネント。

通常、プレゼンテーションロジックと、ビジネスロジックおよびデータアクセスロジックは明確に分離されています。ビジネス層には、ビジネスロジックコンポーネントをカプセル化する1つ以上のファサードで構成された、粒度の粗いAPIがあります。このAPIは、モノリスを2つの小さなアプリケーションに分割する際の自然な境界となります。一方のアプリケーションにはプレゼンテーション層が含まれ、もう一方にはビジネスロジックとデータアクセスロジックが含まれます。分割後、プレゼンテーションロジックのアプリケーションは、ビジネスロジックのアプリケーションをリモートで呼び出します。次の図は、リファクタリング前後のアーキテクチャを示しています。

このようにモノリスを分割することには、主に2つのメリットがあります。2つのアプリケーションをそれぞれ独立して開発、デプロイ、スケーリングできます。特に、プレゼンテーション層の開発者は、ユーザーインターフェースを迅速に反復改善し、A/Bテストなどを容易に実施できます。もう1つのメリットは、開発するマイクロサービスから呼び出せるリモートAPIが公開されることです。

ただし、この戦略は部分的な解決策にすぎません。一方または両方のアプリケーションが、管理困難なモノリスになる可能性が非常に高いためです。残ったモノリスを解消するには、3つ目の戦略を使用する必要があります。

戦略3 – サービスの抽出

3つ目のリファクタリング戦略は、モノリス内の既存モジュールを独立したマイクロサービスに変換することです。モジュールを切り出してサービスに変換するたびに、モノリスは縮小します。十分な数のモジュールを変換すれば、モノリスは問題ではなくなります。完全に消滅するか、単なる1つのサービスと見なせるほど小さくなります。

サービス化するモジュールの優先順位付け

大規模で複雑なモノリシックアプリケーションは、数十から数百のモジュールで構成されており、そのすべてが切り出しの候補となります。どのモジュールから先にサービスへ変換するかを決めるのは、容易ではありません。まずは、切り出しやすいモジュールをいくつか選ぶとよいでしょう。これにより、マイクロサービス全般、特に切り出しプロセスに関する経験を積むことができます。その後、最も大きなメリットが得られるモジュールを切り出します。

モジュールをサービスに変換するには、通常、多くの時間がかかります。そのため、得られるメリットに基づいてモジュールに優先順位を付ける必要があります。一般に、変更頻度の高いモジュールを抽出すると効果的です。モジュールをサービスに変換すれば、モノリスとは独立して開発およびデプロイできるようになり、開発の迅速化につながります。

モノリスの他の部分とはリソース要件が大きく異なるモジュールを切り出すことも有効です。たとえば、インメモリデータベースを持つモジュールをサービス化すれば、大容量メモリを搭載したホストにデプロイできます。同様に、計算負荷の高いアルゴリズムを実装するモジュールを切り出すことも有効です。サービス化することで、多数のCPUを搭載したホストにデプロイできるためです。特有のリソース要件を持つモジュールをサービス化することで、アプリケーションをはるかに容易にスケーリングできるようになります。

抽出するモジュールを検討する際は、既存の粗粒度の境界(シームとも呼ばれます)を探すと効果的です。このような境界があれば、モジュールをより容易かつ低コストでサービス化できます。その一例が、アプリケーションの他の部分とは非同期メッセージのみで通信するモジュールです。このようなモジュールは、比較的容易かつ低コストでマイクロサービス化できます。

モジュールを抽出する方法

モジュールを抽出する最初のステップは、モジュールとモノリスの間に粗粒度のインターフェースを定義することです。モノリスはサービスが所有するデータを必要とし、サービスも同様にモノリスが所有するデータを必要とするため、ほとんどの場合、双方向APIになります。モジュールとアプリケーションの他の部分との間には、複雑に絡み合った依存関係と細粒度のやり取りのパターンがあるため、このようなAPIの実装は容易ではありません。ドメインモデルパターンを使用して実装されたビジネスロジックは、ドメインモデルのクラス間に多数の関連があるため、特にリファクタリングが困難です。こうした依存関係を解消するには、多くの場合、コードに大幅な変更を加える必要があります。次の図は、このリファクタリングを示しています。

粗粒度のインターフェースを実装したら、次にモジュールを独立したサービスにします。そのためには、モノリスとサービスが、プロセス間通信(IPC)メカニズムを使用するAPIを介して通信できるようにするコードを記述する必要があります。次の図は、リファクタリング前、実行中、実行後のアーキテクチャを示しています。

この例では、Module Zが抽出対象の候補モジュールです。そのコンポーネントはModule Xから使用され、Module ZはModule Yを使用します。リファクタリングの最初のステップでは、粗粒度のAPIを2つ定義します。1つ目は、Module XがModule Zを呼び出すために使用するインバウンドインターフェースです。2つ目は、Module ZがModule Yを呼び出すために使用するアウトバウンドインターフェースです。

リファクタリングの第2段階では、モジュールをスタンドアロンサービスに変換します。インバウンドインターフェースとアウトバウンドインターフェースは、IPCメカニズムを使用するコードによって実装されます。多くの場合、Module Zと、サービスディスカバリなどの横断的関心事を処理するMicroservice Chassisフレームワークを組み合わせてサービスを構築する必要があります。

モジュールを抽出すると、モノリスや他のサービスから独立して開発、デプロイ、スケーリングできるサービスが新たに加わります。そのサービスをゼロから書き直すことも可能です。その場合、サービスをモノリスと統合するAPIコードは、2つのドメインモデル間を変換する腐敗防止層になります。サービスを抽出するたびに、マイクロサービス化が一歩進みます。時間の経過とともにモノリスは縮小し、マイクロサービスの数は増えていきます。

まとめ

既存のアプリケーションをマイクロサービスへ移行するプロセスは、アプリケーションモダナイゼーションの一形態です。アプリケーションをゼロから書き直してマイクロサービスへ移行するべきではありません。代わりに、アプリケーションを段階的にリファクタリングし、一連のマイクロサービスへと移行します。利用できる戦略は3つあります。新機能をマイクロサービスとして実装する、プレゼンテーションコンポーネントをビジネスコンポーネントおよびデータアクセスコンポーネントから分離する、モノリス内の既存モジュールをサービスへ変換する、という方法です。時間の経過とともにマイクロサービスの数が増え、開発チームの俊敏性と開発速度が向上します。

編集者注 – 全7回の記事シリーズが完結しました:

  1. マイクロサービス入門
  2. マイクロサービスの構築:API Gatewayの使用
  3. マイクロサービスの構築:マイクロサービスアーキテクチャにおけるプロセス間通信
  4. マイクロサービスアーキテクチャにおけるサービスディスカバリ
  5. マイクロサービス向けイベント駆動型データ管理
  6. マイクロサービスのデプロイ戦略の選択
  7. モノリスからマイクロサービスへのリファクタリング(本記事)

一連の記事全文と、NGINX Plusを使用したマイクロサービスの実装に関する情報をまとめた電子書籍「マイクロサービス:設計からデプロイまで」もダウンロードできます。また、「マイクロサービスリファレンスアーキテクチャ」シリーズと「マイクロサービスソリューションのページ」もご覧ください。

ゲストブロガーのChris Richardson氏は、Amazon EC2向けの初期のJava PaaS(Platform as a Service)である、初代CloudFoundry.comの創設者です。現在は、アプリケーションの開発およびデプロイ方法の改善に向けて、組織へのコンサルティングを行っています。また、マイクロサービスについてhttps://microservices.io


共有
タグ: F5 NGINX, Tech

関連するブログ記事

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
NGINX | 2024/01/18

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する

OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
NGINX | 2023/05/31

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正

Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
NGINX | 2023/02/09

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法

Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINX | 2022/05/24

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング

NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
NGINX | 2018/08/17

SELinuxでNGINXおよびNGINX Plusを使用する

Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。

NGINX PlusによるAWS Auto Scalingグループの負荷分散
NGINX | 2017/03/06

NGINX PlusによるAWS Auto Scalingグループの負荷分散

新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります