2019 年以降のマイクロサービスの構築

マイクロサービス アーキテクチャは常に進化しています。それを正しく実行するための最新のベスト プラクティスをご確認ください。

Sten Pittet Sten Pittet

「マイクロサービス」は、一般的な最新のソフトウェア エンジニアリング組織プラクティスです。マイクロサービスの指針は、ビジネスのコンポーネントを相互に独立してデプロイして運用できる小規模なサービスに分割することによって、アプリケーションを構築することです。サービス間の懸念の分離は、「サービスの境界」として定義されます。

サービスの境界は、ビジネス需要と組織階層の境界に密接に関連しています。個々のサービスは、別々のチーム、予算、ロードマップに関連付けられる場合があります。サービス境界の例としては、「決済」サービスと「ユーザー認証」サービスが考えられます。マイクロサービスは、すべてのコンポーネントが 1 つになったレガシー ソフトウェア開発プラクティスとは異なります。

このドキュメントでは「Pizzup」と呼ばれる架空のスタートアップを参照して、マイクロサービスを最新のソフトウェア ビジネスに適用する方法を説明します。

マイクロサービスの構築方法

ステップ 1: モノリスから始める

マイクロサービスの最初のベスト プラクティスは、おそらくそれを必要としないということです。アプリケーションのユーザーがいなければ、MVP を構築している間、ビジネス要件が急速に変化する可能性があります。これは、単にソフトウェア開発の性質と、システムが提供する必要のある主要なビジネス機能を特定している間に発生する必要があるフィードバック サイクルによるものです。マイクロサービスでは、管理の負担と複雑さが指数関数的に増加します。このため、アプリケーションのさまざまなモジュールの境界を移動しやすくなるため、新しいプロジェクトがすべてのコードとロジックを単一のコードベース内に保持する負担が遥かに軽くなります。

たとえば Pizzup では、顧客のために解決したい問題の非常に基本的な考えから始めたかもしれません。人々にオンラインでピザを注文してもらいたいだとか。

「ユーザーとしてピザをオンラインで注文できる!」と言っている Pizzup ユーザー

ピザ注文の課題について考え始めると、そのニーズを満たすためにアプリケーションで必要なさまざまな機能を特定し始めます。私たちは、作れるさまざまなピザのリストを管理できるようにする必要があります。顧客が 1 枚または多くのピザをチョイスして決済し、配達のスケジュールなどをできるようにする必要があります。顧客にアカウントを作成させることで、次回 Pizzup を使用するときに簡単に再注文できるようにするという発想もあります。私たちの最初のユーザーと話をすると、配達とモバイル サポートのライブ追跡によって、確実に競合他社より優位に立つということがわかるかもしれません。

Pizzup アプリのエンド ユーザーと管理者の使用法の違いを示すグラフィック。

開始時に単純に必要だったことが、提供する必要がある機能のリストに変わります。

マイクロサービスは、システムが必要とするさまざまなサービスの役割を十分に把握している場合に適しています。アプリケーションのコア要件がまだ考案中の場合、処理は遥かに困難です。マイクロサービスでサービスの相互作用、API、データ構造を再定義することは、発生しかねない多くの不確定要素を調整する必要がるため、実際には非常にコストがかかります。そのため、顧客の基本的なニーズを理解して計画していることを確信できる十分なユーザー フィードバックを収集するまで、物事をシンプルに保つことをお勧めします。

しかし注意点として、モノリスを構築すると、細かく分解するのが難しい複雑なコードにすぐに繋がる可能性があります。後でモノリスから抽出できるように、できる限り明確なモジュールを特定させてみてください。また、Web UI からロジックを分離することから始めて、HTTP による RESTful API を介してバックエンドと相互作用することを確認できます。これによって、将来的に API リソースの一部を異なるサービスに移動するときに、マイクロサービスへの移行が容易になります。

ステップ 2: チームを正しく編成する

これまでは、マイクロサービスの構築はほとんど技術的な問題だと思われていたでしょう。コードベースを複数のサービスに分割、故意に失敗してネットワークの課題から回復するための適切なパターンを実装、データの一貫性を処理、サービス負荷を監視するなどを行う必要があります。把握するべき新しい概念がたくさんありますが、無視してはならないのは、チームの編成方法を再構築する必要があるということです。

システムを設計する組織 (広義) は、どの構造が組織の通信構造のコピーであるかを設計します。

- Conway's Law

コンウェイの法則は本物で、あらゆるタイプのチームで観察できます。ソフトウェア チームがバックエンド チーム、フロントエンド チーム、オペレーション チームに分かれていれば、別々のフロントエンドとバックエンドのモノリスが提供されて、本番環境で管理できるようにオペレーション チームに渡されます。

各サービスは他のサービスとは独立してリリースする必要がある独自の製品と見なせるため、このタイプの構造はマイクロサービスには適していません。代わりに、担当しているサービスを開発して維持する際に必要なすべての能力を持つ、小規模なチームを作成する必要があります。Amazon の CTO (最高技術責任者) である Werner Vogels は、この状況を「あなたが構築して実行する」と説明しました。この方法でチームを手配するのは、大きなメリットがあります。まず、開発者は、本番環境におけるコードの影響をより深く理解します。これによって、より適切なリリースが生み出されて、顧客に課題がリリースされるというリスクを軽減できます。次に、デプロイは各チームにとって 2 つめの性質になります。コードの改善とデプロイ パイプラインの自動化に取り組めるようになるためです。

ステップ 3: モノリスを分割してマイクロサービス アーキテクチャを構築する

サービスの境界を特定してコンピテンシーの面でチームをより縦型に変更する方法を理解したら、モノリスを分割してマイクロサービスを構築し始められます。その時に考える重要なポイントは次のとおりです。

RESTful API でサービス間の通信をシンプルに保つ

まだ RESTful API を使用していない場合は、システムに採用するなら今でしょう。Martin Fowler は、ユーザーには「賢いエンドポイントと愚直なパイプ」が必要と説明しています。つまり、データを変換せずに送信するだけなど、サービス間の通信プロトコルはできる限り単純でなければなりません。すべての魔法はエンドポイント自体で起こります。エンドポイントは、リクエストを受け取って処理し、代わりに回答を発行します。

また、Enterprise サービス バスの複雑さを回避することで、ここでマイクロサービスを SOA と区別できます。マイクロサービス アーキテクチャは、コンポーネントの緊密な結合を避けるために、できるだけ物事を単純に保とうとします。場合によっては、非同期メッセージベースの通信でイベントドリブン アーキテクチャを使用していることがあります。しかし、もう一度 RabbitMQ のような基本的なメッセージ キュー サービスを調べて、ネットワーク経由で送信されるメッセージが複雑にならないようにする必要があります。

データ構造を分割する

モノリスのすべての異なる機能に対して単一のデータベースを持つことは、非常に一般的です。ユーザーがその注文にアクセスする際は、ユーザー テーブルを直接確認して顧客情報を表示します。同じテーブルを使用して、課金システムによって管理される請求書にデータを入力する場合があります。これは論理的で単純に見えますが、マイクロサービスでは、発注システムがダウンしていても請求書にアクセスできるように、また請求書テーブルを他のテーブルとは無関係に最適化/進化できるため、サービスを切り離したくなります。つまり、各サービスは必要なデータを永続化するために、独自のデータストアを持つ可能性があります。

別のデータベースで一部のデータが重複してしまうため、新しい問題を発生させることは自明です。この場合は、最終的な整合性を目指す必要があります。イベントドリブン アーキテクチャを採用すると、複数のサービス間でデータを同期できます。たとえば、請求サービスと配達追跡サービスは、顧客が個人情報を更新した際にアカウント サービスから発生するイベントをリッスンしている場合があります。イベントを受信すると、これらのサービスはそれに応じてデータストアを更新します。このイベントドリブン アーキテクチャでは、他のすべての依存サービスを理解する必要がないため、アカウント サービス ロジックをシンプルに保てます。それは単に実行した内容をシステムに伝えて、他のサービスはそれに応じてリッスンして動作します。

また、すべての顧客情報をアカウント サービスに保存して、外部キー参照のみを請求と配達サービスに保持できます。その後、アカウント サービスと対話して、必要に応じて既存のレコードを複製するのではなく、関連する顧客データを取得できます。これらの問題に対する普遍的な解決策はないので、最良のアプローチが何であるかを判断するために、それぞれの特定のケースを調べる必要があります。

障害に備えたマイクロサービス アーキテクチャの構築

どのようにマイクロサービスがモノリシック アーキテクチャよりも大きなメリットを実現できるかを見てきました。サイズがより小さいマイクロサービスは、分かりやすさも突出しています。マイクロサービスは切り離されているため、システムの他のコンポーネントを壊したり他のチームの開発を遅らせたりするのを恐れることなく、サービスをリファクタリングできます。また、他のサービスのニーズに制約されることなく、必要に応じてさまざまなテクノロジーを選択できるため、開発者の柔軟性が高まります。

要するに、マイクロサービス アーキテクチャを持つことで、各ビジネス機能を簡単に開発して維持できるようになります。しかし、すべてのサービスを俯瞰してアクションを完了するためにどのように相互作用する必要があるかを確認すると、物事はより複雑になります。システムは複数の障害点で分散されて、それに対応する必要があります。サービスが応答していないだけでなく、遅いネットワーク応答に対処できるケースを考慮する必要があります。復旧して稼働しているサービスが保留中のメッセージによってフラッディングしないようにする必要があるため、障害からの回復は時には難しい場合があります。

モノリシック システムから機能を抽出し始めたら、設計が最初から障害向けに構築されていることを確認します。

マイクロサービスのテストを容易にするために監視を重視する

テストは、モノリシック システムと比較した際のマイクロサービスのもう 1 つの欠点です。単一のコードベースとして構築されるアプリケーションは、テスト環境を稼働させる必要はそこまでありません。ほとんどの場合、テスト スイートを実行できるようにするには、データベースと一体化されたバックエンド サーバーを起動する必要があります。

マイクロサービスの世界では、物事はそんなに簡単ではありません。ユニット テストに関しては、モノリスとはまだ然したる違いもないため、そのレベルにおいてはさほどの困難も伴わないはずです。しかし、統合とシステム テストに関しては、物事は遥かに難しくなります。複数のサービスをまとめて起動して、異なるデータストアを稼働させなければならない場合があります。また、モノリスでは不要なメッセージ キューを設定に含めなければならない場合があります。このような状況では、機能テストの実行には遥かにコストがかかります。不確定要素の数が増えると、発生する可能性のあるさまざまなタイプの障害を予測することは非常に困難になります。

そのため、課題を早期に特定して適切な対応をできるようにするために、監視に重点を置く必要があります。さまざまなサービスの基準を理解することで、サービスがダウンしたときだけでなく予期せぬ動作をしているときにも反応できるようにする必要があります。マイクロサービス アーキテクチャを導入するメリットの 1 つとして、システムが部分的な障害に対して耐障害性があることがあげられます。これによって、Pizzup アプリケーションの配達追跡サービスに異常が見え始めても、モノリシック システムほど悪くなることはないでしょう。私たちのアプリケーションは、他のすべてのサービスが適切に反応することで、ライブトラッキングを復元しながら顧客がピザを注文できるように設計する必要があります。

継続的なデリバリーを活用してデプロイの摩擦を軽減する

モノリシック システムを本番環境に手動でリリースすることは面倒で危険な作業ですが、できることです。もちろん、このアプローチはお勧めしません。また、すべてのソフトウェア チームがあらゆる種類の開発で継続的なデリバリーを活用することを推奨しますが、プロジェクトの開始時にコマンド ラインを使用して最初のデプロイを自分で行う場合があります。

1 日に複数回デプロイする必要があるサービスの数が増えている場合、このアプローチは持続可能ではありません。したがって、マイクロサービスへの移行の一環として、リリース障害のリスクを軽減するために継続的なデリバリーを活用し、さらにチームがアプリケーションのデプロイを中断するのではなく、アプリケーションの構築と実行に集中することが重要です。また、継続的なデリバリーの実践は、本番環境への移行前にサービスが受け入れテストに合格したことを意味します。もちろんバグが発生しますが、時間の経過とともに堅牢なテスト スイートを構築して、リリースの品質に対するチームの信頼性を高める必要があります。

マイクロサービスの実行はスプリントではない

マイクロサービスは、急速に普及して広く採用されている業界のベスト プラクティスになりつつあります。複雑なプロジェクトの場合は、ソフトウェアを構築してデプロイする方法における柔軟性が向上します。また、システムのビジネス コンポーネントの識別と形式化にも役立ちます。これは、複数のチームが同じアプリケーションに取り組んでいる場合に便利です。しかし、分散システムの管理には明らかな欠点もあります。モノリシック アーキテクチャの分割は、サービスの境界を明確に理解している場合のみ行う必要があります。

マイクロサービスの構築は、チーム当面の目標ではなくジャーニーとして捉える必要があります。小規模から始めて、分散システムの技術要件、故意の失敗、個々のコンポーネントの拡張方法を理解します。その後、さらに経験を積んで知識を得るにつれて、徐々にサービスを抽出できます。

マイクロサービス アーキテクチャへの移行は、1 つの包括的な努力で達成する必要はありません。小規模なコンポーネントをマイクロサービスへ順次移行する反復戦略の方がより確実です。確立されたモノリス アプリケーション内で最も明確に定義されたサービス境界を特定して、それらを独自のマイクロサービスに分離するように反復して取り組みます。

概要

要約すると、マイクロサービスは、生の技術コード開発プロセスと全体的なビジネス組織戦略の両方にとって有益な戦略です。マイクロサービスは、チームを特定のビジネス機能の開発と所有に重点を置くユニットに編成するのに役立ちます。このようにきめ細かく重点的に取り組むことで、ビジネス全体のコミュニケーションと効率性が向上します。マイクロサービスのメリットには犠牲が伴います。マイクロサービス アーキテクチャに移行する前に、サービスの境界を明確に定義することが重要です。マイクロサービス アーキテクチャはまだかなり若いですが、それはアプリケーションを開発する有望な手段であり、間違いなく一考の価値があります。それは (まだ) あなたのチームに最適でないかもしれないことを覚えておいてください。