マイクロサービスのトレードオフ
多くの開発チームは、マイクロサービスアーキテクチャスタイルが、モノリシックアーキテクチャよりも優れたアプローチであると考えています。しかし、他のチームは、マイクロサービスが生産性を低下させる重荷であると感じています。他のアーキテクチャスタイルと同様に、マイクロサービスにはコストと利点があります。賢明な選択をするには、これらを理解し、特定の状況に適用する必要があります。
2015年7月1日
- 強力なモジュール境界: マイクロサービスはモジュール構造を強化します。これは大規模なチームにとって特に重要です。
- 独立したデプロイ: 単純なサービスはデプロイが容易で、自律的であるため、問題が発生した場合にシステム障害を引き起こす可能性が低くなります。
- 技術の多様性: マイクロサービスを使用すると、複数の言語、開発フレームワーク、およびデータストレージテクノロジーを混在させることができます。
マイクロサービスはメリットをもたらします…
強力なモジュール境界 (メリット)
マイクロサービスの最初の大きな利点は、強力なモジュール境界です。これは重要な利点ですが、奇妙な利点でもあります。理論的には、マイクロサービスはモノリスよりも強力なモジュール境界を持つべき理由はないからです。
では、強力なモジュール境界とはどういう意味でしょうか?ほとんどの人が、ソフトウェアをモジュールに分割することに同意すると思います。モジュールとは、互いに分離されたソフトウェアの塊のことです。モジュールが機能することで、システムの特定の部分を変更する必要がある場合、ほとんどの場合、その変更を行うためにシステムの小さな部分を理解するだけで済み、その小さな部分を簡単に見つけることができるようにする必要があります。優れたモジュール構造は、どのプログラムでも役立ちますが、ソフトウェアの規模が大きくなるにつれて指数関数的に重要になります。おそらくさらに重要なことに、それを開発するチームの規模が大きくなるにつれて、重要性が増します。
マイクロサービスの支持者は、ソフトウェアシステムの構造がそれを構築した組織のコミュニケーション構造を反映するという概念であるコンウェイの法則をすぐに導入します。大規模なチーム、特にこれらのチームが異なる場所に拠点を置いている場合は、チーム間コミュニケーションがチーム内コミュニケーションよりも頻度が少なく、より形式的になることを認識するようにソフトウェアを構造化することが重要です。マイクロサービスを使用すると、各チームは、その種のコミュニケーションパターンを持つ比較的独立したユニットを管理できます。
前述したように、モノリシックシステムが優れたモジュール構造を持つべきではない理由はありません。[1]しかし、多くの人が、それがまれであるように見えると観察しています。そのため、泥団子が最も一般的なアーキテクチャパターンになっています。実際、モノリスの一般的な運命に対するこの不満が、いくつかのチームをマイクロサービスへと駆り立てています。モジュールとの分離が機能するのは、モジュール境界がモジュール間の参照に対する障壁となるためです。問題は、モノリシックシステムでは、通常、障壁をこっそり回避するのが非常に簡単であるということです。これを行うことは、機能を迅速に構築するための便利な戦術的なショートカットになる可能性がありますが、広く行われると、モジュール構造が損なわれ、チームの生産性が低下します。モジュールを個別のサービスに配置すると、境界がより堅固になり、これらの有害な回避策を見つけることがはるかに困難になります。
この結合の重要な側面は、永続的なデータです。マイクロサービスの重要な特性の1つは分散型データ管理であり、各サービスが独自のデータベースを管理し、他のサービスはサービスAPIを介してのみデータベースにアクセスする必要があることを示しています。これにより、大規模なシステムで厄介な結合の主な原因である統合データベースが排除されます。
モノリスでも堅固なモジュール境界を持つことは完全に可能ですが、規律が必要であることを強調することが重要です。同様に、マイクロサービスの泥団子を得ることもできますが、間違ったことをするにはより多くの労力が必要です。私が考えているのは、マイクロサービスを使用すると、より優れたモジュール性が得られる可能性が高まるということです。チームの規律に自信がある場合は、おそらくその利点を排除できますが、チームが成長するにつれて、モジュール境界を維持することがより重要になるのと同じように、規律を維持することがますます難しくなります。
この利点は、境界線を正しく設定しないとハンディキャップになります。これは、モノリスファースト戦略の2つの主な理由の1つであり、マイクロサービスを早期に実行する傾向がある人でさえ、十分に理解されたドメインでのみ実行できることを強調する理由です。
しかし、この点についての注意点にまだ終わりはありません。システムのモジュール性がどれだけ維持されているかは、時間が経ってからしかわかりません。そのため、マイクロサービスがより優れたモジュール性につながるかどうかは、少なくとも数年間存在しているマイクロサービスシステムを見て初めて評価できます。さらに、初期の採用者はより才能がある傾向があるため、平均的なチームによって作成されたマイクロサービスシステムのモジュール性の利点を評価できるようになるまでには、さらに遅延があります。それでも、平均的なチームは平均的なソフトウェアを作成することを認識する必要があるため、結果をトップチームと比較するのではなく、結果として得られるソフトウェアをモノリシックアーキテクチャの下でどのようなものになったかと比較する必要があります。これは、評価するのが難しい反事実です。
私が現時点で頼ることができるのは、このスタイルを使用している私が知っている人たちから聞いた初期の証拠だけです。彼らの判断では、モジュールの保守が著しく容易になっています。
1つのケーススタディは特に興味深いものでした。チームは、マイクロサービスプレミアムをカバーするほど複雑ではないシステムでマイクロサービスを使用するという間違った選択をしていました。プロジェクトはトラブルに陥り、救済する必要があったため、より多くの人がプロジェクトに投入されました。この時点で、マイクロサービスアーキテクチャが役立つようになりました。システムが開発者の急増を吸収することができ、チームはモノリスの場合よりもはるかに簡単に大規模なチーム数を活用できたためです。その結果、プロジェクトはモノリスの場合よりも予想される生産性よりも高い生産性に加速し、チームは追いつくことができました。ソフトウェアの費用はモノリスを使用した場合よりも人件費が高かったため、全体としてはマイナスでしたが、マイクロサービスアーキテクチャは立ち上げをサポートしました。
分散 (デメリット)
そのため、マイクロサービスは分散システムを使用してモジュール性を向上させます。しかし、分散ソフトウェアには、分散されているという事実という大きな欠点があります。分散カードをプレイするとすぐに、多くの複雑さが生じます。マイクロサービスコミュニティは、分散オブジェクト運動ほどこれらのコストについてナイーブではないと思いますが、複雑さは依然として残っています。
これらの最初の1つはパフォーマンスです。今日、プロセス内関数呼び出しがパフォーマンスのホットスポットになるのを見るのは非常に珍しいことですが、リモート呼び出しは遅いです。サービスが6つのリモートサービスを呼び出し、それぞれがさらに6つのリモートサービスを呼び出す場合、これらの応答時間が加算されて、恐ろしい待ち時間の特性になります。
もちろん、この問題を軽減するために多くのことができます。まず、呼び出しの粒度を上げて、呼び出し回数を減らすことができます。これにより、プログラミングモデルが複雑になり、サービス間のインタラクションをどのようにバッチ処理するかを考える必要が生じます。また、協力する各サービスを少なくとも1回は呼び出す必要があるため、これだけでは限界があります。
2番目の軽減策は、非同期を使用することです。6つの非同期呼び出しを並行して行うと、待ち時間の合計ではなく、最も遅い呼び出しと同じくらい遅くなります。これは大きなパフォーマンスの向上につながる可能性がありますが、別の認知コストがかかります。非同期プログラミングは、正しく行うのが難しく、デバッグがはるかに困難です。しかし、私が聞いたほとんどのマイクロサービスの話では、許容可能なパフォーマンスを得るためには非同期が必要です。
速度のすぐ後に信頼性が来ます。プロセス内関数呼び出しは機能すると予想されますが、リモート呼び出しはいつでも失敗する可能性があります。多数のマイクロサービスがある場合、さらに多くの潜在的な障害点があります。賢明な開発者はこれを認識し、障害を考慮して設計します。幸いなことに、非同期コラボレーションに必要な戦術の種類は、障害の処理にもよく適合し、その結果、回復力が向上する可能性があります。しかし、それはあまり補償にはなりません。リモート呼び出しごとに障害の結果を把握するという追加の複雑さがまだあります。
そして、それが上位2つの分散コンピューティングの誤謬です。
この問題にはいくつかの注意点があります。まず、これらの問題の多くは、モノリスが成長するにつれて発生します。真に自己完結型のモノリスはほとんどなく、通常、他のシステム、多くの場合レガシーシステムが連携する必要があります。それらとやり取りするには、ネットワークを介してこれらの同じ問題に遭遇する必要があります。これが、多くの人がリモートシステムとのやり取りを処理するために、より迅速にマイクロサービスに移行する傾向がある理由です。この問題は、経験が役に立つ問題でもあり、より熟練したチームは分散の問題に対処するのに優れています。
しかし、分散は常にコストです。私は常に分散カードをプレイすることに抵抗があり、多くの人が問題を過小評価しているために、分散化に早く進みすぎていると思います。
結果整合性 (デメリット)
少し辛抱が必要なWebサイトをご存知だと思います。何かを更新すると、画面が更新されますが、更新が欠落しています。1、2分待って、更新をクリックすると、そこにあります。
これは非常に厄介な使いやすさの問題であり、ほぼ間違いなく結果整合性の危険が原因です。更新はピンクのノードで受信されましたが、getリクエストは緑のノードで処理されました。緑のノードがピンクから更新を受け取るまで、不整合ウィンドウに閉じ込められます。最終的には整合性が取れますが、それまでは何か問題が発生したのではないかと思っています。
このような不整合は十分に厄介ですが、さらに深刻になる可能性があります。ビジネスロジックは、不整合な情報に基づいて意思決定を行うことになる可能性があり、これが起こると、調査は不整合ウィンドウが閉じた後にはるか後に行われるため、何が間違っていたのかを診断することが非常に困難になる可能性があります。
マイクロサービスは、分散型データ管理を称賛しているため、結果整合性の問題を引き起こします。モノリスを使用すると、単一のトランザクションで多くのものをまとめて更新できます。マイクロサービスでは、複数のリソースを更新する必要があり、分散トランザクションは (正当な理由で) 好ましくありません。そのため、開発者は整合性の問題を認識し、コードが後悔する前に、いつ同期が取れていないかを検出する方法を見つける必要があります。
モノリシックな世界もこれらの問題から自由ではありません。システムが成長するにつれて、パフォーマンスを向上させるためにキャッシュの使用が必要になり、キャッシュの無効化はもう一つの難しい問題です。ほとんどのアプリケーションは、長期にわたるデータベーストランザクションを避けるためにオフラインロックを必要とします。外部システムは、トランザクションマネージャーと連携できない更新を必要とします。ビジネスプロセスは、企業が可用性を重視する傾向があるため(ビジネスプロセスは、CAP定理を本能的に理解していました)、一般的に考えられているよりも不整合に対して寛容です。
したがって、他の分散に関する問題と同様に、モノリスは不整合問題を完全には回避できませんが、特に小さければ、それらの問題の影響ははるかに少なくなります。
独立したデプロイ(長所)
モジュール境界と分散システムの複雑さのトレードオフは、この業界での私のキャリア全体を通じて存在してきました。しかし、この10年で顕著に変化したことの一つは、本番環境へのリリース役割です。20世紀では、本番リリースはほとんど例外なく、苦痛を伴う稀なイベントであり、週末の昼夜シフトを行って、何らかの厄介なソフトウェアを役立つ場所に移動させていました。しかし最近では、熟練したチームは頻繁に本番環境にリリースし、多くの組織が継続的デリバリーを実践しており、1日に何度も本番リリースを行うことができるようになっています。
マイクロサービスは、デブオプスの革命後の最初のアーキテクチャです。
-- ニール・フォード
この変化はソフトウェア業界に大きな影響を与えており、マイクロサービス運動と深く絡み合っています。いくつかのマイクロサービスへの取り組みは、モノリスの一部での小さな変更が全体のデプロイを失敗させる可能性があった、大規模なモノリスのデプロイの困難さによって引き起こされました。マイクロサービスの重要な原則は、サービスがコンポーネントであり、したがって独立してデプロイ可能であるということです。そのため、変更を加える場合は、小さなサービスのみをテストしてデプロイする必要があります。もし失敗しても、システム全体がダウンすることはありません。結局のところ、障害を前提に設計する必要があるため、コンポーネントが完全に失敗した場合でも、他のシステムの部分が正常に機能しないようにすることはできませんが、何らかの形でグレースフルデグラデーションを行う必要があります。
この関係は双方向です。頻繁にデプロイする必要がある多くのマイクロサービスを使用するには、デプロイがきちんと連携していることが不可欠です。そのため、迅速なアプリケーションデプロイとインフラストラクチャの迅速なプロビジョニングがマイクロサービスの前提条件となっています。基本を超えるものについては、継続的デリバリーを行う必要があります。
継続的デリバリーの大きな利点は、アイデアと稼働中のソフトウェア間のサイクルタイムが短縮されることです。これを行う組織は、市場の変化に迅速に対応し、競合他社よりも迅速に新機能を導入できます。
多くの人がマイクロサービスを使用する理由として継続的デリバリーを挙げていますが、大規模なモノリスでも継続的にデリバリーできることを言及しておくことが不可欠です。FacebookとEtsyが最もよく知られている例です。また、マイクロサービスアーキテクチャの試みが独立したデプロイに失敗し、複数のサービスがリリースを慎重に調整する必要がある場合も多くあります[2]。マイクロサービスを使用すると継続的デリバリーがはるかに簡単になると主張する人を多く見かけますが、モジュール性に対する実用的な重要性ほど確信はしていません。ただし、当然のことながら、モジュール性はデリバリー速度と強く相関しています。
運用上の複雑さ(短所)
小さな独立したユニットを迅速にデプロイできることは、開発にとって大きな恩恵ですが、運用にさらなる負担をかけます。なぜなら、6つ程度のアプリケーションが何百もの小さなマイクロサービスに変わるからです。多くの組織は、急速に変化するツールの群れを処理することの難しさが非常に困難であることに気づくでしょう。
これは、継続的デリバリーの重要な役割を強化します。継続的デリバリーはモノリスにとって価値のあるスキルであり、努力する価値は常にありますが、本格的なマイクロサービスの設定には不可欠になります。継続的デリバリーが促進する自動化とコラボレーションがなければ、多数のサービスを処理する方法はありません。運用上の複雑さは、これらのサービスの管理と監視に対する要求の増加によっても増加します。繰り返しますが、モノリシックアプリケーションにとって役立つ成熟度が、マイクロサービスが混在している場合には必要になります。
マイクロサービスの支持者は、各サービスが小さいため、理解しやすいと指摘することを好みます。しかし、危険なのは、複雑さが解消されるのではなく、サービス間の相互接続に移動されるだけであるということです。これは、サービスにまたがる動作をデバッグする難しさなど、運用上の複雑さの増加として表面化する可能性があります。サービス境界を適切に選択することで、この問題は軽減されますが、境界を間違った場所に設定すると、状況ははるかに悪化します。
この運用上の複雑さを処理するには、新しいスキルとツールのホストが必要になります。最も重要なのはスキルです。ツールはまだ未成熟ですが、ツールが改善されても、マイクロサービス環境ではスキルの低いレベルに対するハードルが高くなると直感的に感じています。
しかし、これらの運用上の複雑さを処理する上で最も難しい部分は、より良いスキルとツールが必要になることではありません。これらすべてを効果的に行うには、DevOpsカルチャー、つまり開発者、運用担当者、およびソフトウェア配信に関与する他のすべての人々の間のより大きなコラボレーションも導入する必要があります。文化変革は、特に大規模で古い組織では困難です。このスキルアップと文化変革を行わないと、モノリシックアプリケーションは妨げられますが、マイクロサービスアプリケーションはトラウマを負うことになります。
テクノロジーの多様性(長所)
各マイクロサービスは独立してデプロイ可能なユニットであるため、その中でテクノロジーの選択にかなりの自由度があります。マイクロサービスは、異なる言語で記述したり、異なるライブラリを使用したり、異なるデータストアを使用したりできます。これにより、チームは仕事に適したツールを選択できます。一部の言語やライブラリは、特定の種類の問題に適しています。
技術の多様性の議論は、多くの場合、仕事に最適なツールに焦点を当てていますが、マイクロサービスの最大の利点は、多くの場合、より平凡なバージョニングの問題です。モノリスでは、ライブラリの単一のバージョンしか使用できず、それが問題のあるアップグレードにつながることがよくあります。システムの特定の部分では、新しい機能を使用するためにアップグレードが必要になる場合がありますが、アップグレードによってシステムの別の部分が壊れるため、アップグレードできません。ライブラリのバージョン管理の問題に対処することは、コードベースが大きくなるにつれて指数関数的に難しくなる問題の1つです。
ここには、テクノロジーの多様性が非常に多いため、開発組織が圧倒される可能性があるという危険性があります。私が知っているほとんどの組織は、限定された一連のテクノロジーを推奨しています。この推奨は、サービスが共通の環境の小さなポートフォリオに固執しやすくする監視などの一般的なツールを提供することによってサポートされています。
実験をサポートすることの価値を過小評価しないでください。モノリシックシステムでは、言語やフレームワークに関する初期の決定を覆すのは困難です。10年ほど経つと、そのような決定によってチームが扱いにくいテクノロジーに縛られる可能性があります。マイクロサービスを使用すると、チームは新しいツールを試したり、優れたテクノロジーが関連するようになった場合に、一度に1つのサービスずつシステムを徐々に移行したりできます。
二次的な要因
上記を検討すべき主なトレードオフとして考えています。以下に、それほど重要ではないと思われる、さらにいくつかの項目を示します。
マイクロサービスの支持者は、サービスはスケーリングが容易であるとよく言います。なぜなら、1つのサービスに大きな負荷がかかる場合は、アプリケーション全体ではなく、そのサービスだけをスケーリングできるからです。しかし、アプリケーション全体をコピーすることで行うクッキーカッタースケーリングと比較して、この選択的なスケーリングを行う方が実際に効率的であると確信させてくれたまともな経験レポートを思い出すのに苦労しています。
マイクロサービスを使用すると、機密データを分離し、そのデータにさらに注意深いセキュリティを追加できます。さらに、マイクロサービス間のすべてのトラフィックが保護されることを保証することで、マイクロサービスアプローチにより、侵入を悪用することが難しくなる可能性があります。セキュリティの問題が重要度を増すにつれて、これはマイクロサービスを使用する際の主要な考慮事項になる可能性があります。そうではなくても、主にモノリシックなシステムが機密データを処理するために個別のサービスを作成するのは珍しいことではありません。
マイクロサービスの批判者は、マイクロサービスアプリケーションのテストはモノリスよりも難しいと述べています。これは、分散アプリケーションの複雑さが大きくなったことの一部である、確かに困難なことですが、マイクロサービスを使用したテストへの優れたアプローチがあります。ここで最も重要なことは、テストを真剣に受け止める規律を持つことです。それに比べて、モノリスのテストとマイクロサービスのテストの違いは二次的なものです。
まとめ
あらゆるアーキテクチャスタイルに関する一般的な投稿は、一般的なアドバイスの限界に悩まされています。したがって、このような投稿を読むことは、あなたに決定を下すことはできませんが、そのような記事は、考慮に入れる必要があるさまざまな要素を確実に考慮するのに役立ちます。ここでの各コストとメリットは、システムごとに異なる重み付けを行い、コストとメリットを切り替えることもあります(強力なモジュール境界はより複雑なシステムでは優れていますが、単純なシステムではハンディキャップになります)。下す決定は、コンテキストにそのような基準を適用し、システムにとって最も重要な要素と、それらが特定のコンテキストにどのように影響するかを評価することにかかっています。さらに、マイクロサービスアーキテクチャの経験は比較的限られています。通常、アーキテクチャの決定を判断できるのは、システムが成熟し、開発開始から何年も経ってからどのように機能するかを学んだ後です。長期にわたるマイクロサービスアーキテクチャに関する逸話はまだ多くありません。
モノリスとマイクロサービスは、単純な二項選択ではありません。どちらも曖昧な定義であり、多くのシステムが曖昧な境界領域にあることを意味します。また、どちらのカテゴリにも当てはまらない他のシステムもあります。私を含め、ほとんどの人は、より一般的なスタイルと対比することが理にかなっているため、モノリスとは対照的にマイクロサービスについて話しますが、どちらのカテゴリにも快適に収まらないシステムがあることを覚えておく必要があります。私はモノリスとマイクロサービスをアーキテクチャの空間の2つの領域として考えています。それらは議論に値する興味深い特性を持っているため、名前を付ける価値がありますが、賢明な設計者はそれらをアーキテクチャ空間の包括的なパーティションとして扱うことはありません。
そうは言っても、広く受け入れられている一般的な要約ポイントは、マイクロサービスプレミアムがあるということです。マイクロサービスは、より複雑なシステムでのみ補うことができる生産性にコストを課します。したがって、モノリシックアーキテクチャでシステムの複雑さを管理できる場合は、マイクロサービスを使用すべきではありません。
しかし、マイクロサービスに関する議論の量によって、ソフトウェアプロジェクトの成功と失敗を左右するより重要な問題を忘れてはなりません。チームのメンバーの質、相互の協力度、ドメインの専門家とのコミュニケーションの程度など、ソフトな要因は、マイクロサービスを使用するかどうかの問題よりも大きな影響を与えます。純粋に技術的なレベルでは、クリーンなコード、優れたテスト、そして進化するアーキテクチャへの注意などの点に焦点を当てる方が重要です。
脚注
1: 「モノリス」という言葉を、常にモジュール構造が貧弱であることを暗示する侮辱とみなす人もいます。マイクロサービスの世界のほとんどの人はそうではなく、「モノリス」を単一のユニットとして構築されたアプリケーションとして純粋に定義します。確かにマイクロサービス推進派は、ほとんどのモノリスが最終的に「泥の塊」になってしまうと考えていますが、構造化されたモノリスを構築することが不可能だと主張する人はいないでしょう。
2: サービスを独立してデプロイできることは、マイクロサービスの定義の一部です。したがって、デプロイの調整が必要なサービス群は、マイクロサービスアーキテクチャではないと言うのが妥当です。また、マイクロサービスアーキテクチャを試みる多くのチームが、最終的にサービスデプロイの調整を余儀なくされて問題に陥るというのも、また妥当なことです。
さらに詳しく知るには
Sam Newmanは、自身の著書の第1章(マイクロサービスシステムの構築に関する詳細な情報源)で、マイクロサービスの利点について述べています。
Benjamin WoottonのHigh Scaleabilityへの投稿「マイクロサービス - ただ飯ではない!」は、マイクロサービスを使用することの欠点をまとめた初期のものであり、最も優れたものの1つです。
謝辞
Brian Mason、Chris Ford、Rebecca Parsons、Rob Miles、Scott Robinson、Stefan Tilkov、Steven Lowe、そしてUnmesh Joshiが、この記事の草稿について私と議論しました。