自由課題

学んだり、考えたり、試したりしたこと。

James Lewis/Martin Fowlerの"Microservices"日本語訳

はじめに

本記事はMartin Fowler氏のBlog記事を日本語訳したものです。 なお、訳は2014/11/09時点のもので、オリジナル記事中のコラムは訳せていません。コラムの訳に関しては、暇や反応を見ながらぼちぼちやろうと思います。

訳に対する指摘・ご意見などありましたらtwitter(@kimito_k)でお願いします。

補足
Martin Fowler氏に連絡をとったところ、主著者はJames Lewisであるとのことでしたのでタイトルを変更しました。(2014/11/13)

Microservices

"マイクロサービスアーキテクチャ"という専門用語は、ソフトウェアアプリケーションを独立して配置可能なサービスの組み合わせ(suite)として設計する特定の方法を指すものとして、ここ数年で急速に認知されています。このアーキテクチャスタイルに対する正確な定義はありませんが、ビジネス遂行能力に関わる組織、自動化されたデプロイメント、エンドポイントの知性(intelligence)、そしてプログラミング言語とデータの分散制御に関する明確に共通な特性が存在します。

"マイクロサービス" - ソフトウェアアーキテクチャの混雑した大通りに加えられたさらに新しい単語です。このようなものごとは一瞥して見過ごすのが私たちの自然な反応ですが、このちょっとした用語は私たちがどんどん魅力的であることを発見しているソフトウェアシステムのスタイルを記述しているものなのです。ここ何年かでこのスタイルのプロジェクトをたくさん見てきましたが、その結果は今のところとても良好であり、私の同僚の多くにとってエンタープライズアプリケーションを構築するためのデフォルトのスタイルになりつつあります。残念なことに、マイクロサービスがどんなものであるかということや、どうしたらよいかということに関する概要を示す情報は多くありません。

簡単にいうと、マイクロサービスアーキテクチャスタイル*1は単一のアプリケーションを小さなサービス群の組み合わせとして構築する手法であり、個々のサービスは自身のプロセス上で動作し、たびたびHTTPのリソースAPIなど軽量の機構により通信を行います。サービスはビジネス遂行能力に合わせて構築され、完全に自動化された機構により可能です。最小限の中央集権的な管理はありますが、それぞれのサービスは異なるプログラミング言語により記述され、異なるデータストレージ技術が用いられています。

マイクロサービスに関する説明をするにあたり、モノリシック(一枚岩)スタイルとの比較することは効果的です: モノリシックアプリケーションは単一のユニットとして構築されます。エンタープライズアプリケーションはしばしば3つの主要な部分から構成されます: クライアントサイドのUI(HTMLページとユーザ端末上のブラウザで実行されるjavascript)、データベース(共通に用いられ、通常リレーショナルであるデータベース管理システムに挿入された多数のテーブルから構成される)、及びサーバサイドのアプリケーションです。サーバサイドアプリケーションはHTTPリクエストを取り扱い、ドメインロジックを実行し、データベースから更新されたデータを抽出し、ブラウザに向けてHTMLによるビューを作成、送出します。このサーバサイドアプリケーションはモノリス - 単一の論理的な実行可能ファイル*2です。システムに対するどんな変更もサーバサイドアプリケーションの新しいバージョンの構築・デプロイに関連します。

このようなモノリシックなサーバはこのようなシステムを構築する方法として自然なものです。リクエストを取り扱うロジックは全て単一のプロセスで処理され、アプリケーションをクラス、関数、名前空間に分割し、使用している言語の機能を利用します。いくつかの注意点に気をつけて、アプリケーションは開発者のラップトップ上で実行・テストし、ソフトウェアに関する変更がテストされ、プロダクション環境にデプロイされることを保証するためにデプロイメントパイプラインを使用することができます。モノリスはロードバランサの背後で多数のインスタンス上で実行することによりスケールすることができます。

モノリシックアプリケーションでもうまく運用することができますが、徐々に関係者をイライラさせることになるでしょう - クラウド上にアプリケーションがどんどんデプロイし続けられる場合は特に。変更サイクルは一連託生です - アプリケーションの小さな部分に対する変更はモノリス全てのリビルドとデプロイを必要とします。時を経るにつれてモジュール構造を良好に保つのは難しくなり、あるモジュールに対する変更をモジュール内に限定することは難しくなります。スケールすることは、リソースをより必要とする部分だけでなくアプリケーション全体のスケールを必要とします。

Figure 1: Monoliths and Microservices

これらのイライラはマイクロサービスアーキテクチャスタイルに導きます: アプリケーションを複数のサービスの組み合わせとして構築することです。サービスが独立してデプロイ可能でスケーラブルであるという事実と同様、それぞれのサービスは異なるプログラミング言語により記述された異なるサービスであるのにも関わらず強固なモジュール境界を提供します。

私たちはマイクロサービススタイルが目新しいものであるとか革新的なものであるというつもりはなく、少なくともUnixの設計思想を根本に置き直すということが言いたいのです。しかし、私たちは十分な人々がマイクロサービスについて考慮していないと考えており、多くのソフトウェア開発者がマイクロサービスを用いることにより幸せになってくれることを願っています。

マイクロサービスアーキテクチャーの特性

これがマイクロサービスアーキテクチャースタイルの形式的な定義であるということはできませんが、マイクロサービスに対する共通の特性を記述してみることはできます。共通の特性の概要を定義するのと同時に、全てのマイクロサービスが全ての特性を持っているわけではないことを述べなければなりませんが、ほとんどのマイクロサービスアーキテクチャがほとんどの特性を示すであろうと予想しています。筆者である私たちはこのいくぶんゆるいコミュニティの活動的なメンバーではありますが、私たちの意図は自信の仕事で見たこと、知り合いのチームの同様の努力を記載してみることです。私たちは特に従うべき何かの定義を規定しているわけではありません。

サービスを通じたコンポーネント

ソフトウェア業界に関わる限り、コンポーネントを継ぎ合わせてシステムを構築したい欲求は存在します。これは自然界に存在する事象とまったく同じ原理です。ここ10〜20年ほど、たいていの言語環境の共通ライブラリの多くの部分が目を見張る進歩をするのを見てきました。

コンポーネントに関して議論するとき、何がコンポーネントを形成するかという難しい定義に行き当たります。私たちの定義は、コンポーネントは独立して交換・アップグレード可能なソフトウェアのユニットである、というものです。

マイクロサービスはライブラリを使用するでしょうが、サービス自身をコンポーネント化する第一の方法はサービスを複数のサービスに分解することです。プログラムにリンクされ、インメモリの関数コールを使用して呼び出されるコンポーネントライブラリと定義します。これはサービスWebサービスリクエスト、またはRPCのような機構により通信するプロセス外のコンポーネントであることとは対照的です。(この定義は多くのOOプログラム*3におけるサービスオブジェクトの概念とは異なるものです。)

(ライブラリではなく)サービスをコンポーネントとして用いる主要な理由の1つはサービスが独立してデプロイ可能であるということです。もし単一のプロセス内の複数のライブラリによりアプリケーションを構成したアプリケーションの場合、あるコンポーネントの変更がアプリケーション全体の再デプロイを必要とします。しかし、もしアプリケーションが複数のサービスに分解されていた場合、多数のサービスがそれぞれ変更される場合でも、各サービスの再デプロイが必要とされるだけです。これは絶対的なものではなく、ある変更はある構成におけるサービスI/Fを変更することになるかもしれませんが、よいマイクロサービスアーキテクチャの目的は、凝集性のあるサービス境界を通じた変更を最小化し、サービス契約を満たしながら進化することです。

他にコンポーネントをサービスとして使用した場合の結果として、コンポーネントインターフェイスがより明示的になる点が挙げられます。ほとんどの言語は明示的な公開インターフェイスを定義するための効果的な機構を持っていません。クライアントがコンポーネントカプセル化を破壊するのを防止するのにしばしばドキュメントや規律に頼らざるを得ず、コンポーネント間の結合度を過度に高める結果をもたらします。サービスは明示的なリモート呼び出し機構を用いることで結合度の上昇を回避することを容易にします。

このようなサービスを用いることによる負の側面も確かにあります。リモート呼び出しはプロセス内の呼び出しよりコストが高いため、リモートAPIは粒度を荒くする必要があります。これはしばしば使いづらいものになります。もしコンポーネント間の責務の割り当てを変更する必要がある場合、プロセス境界をまたぐ時にはこのような振る舞いの変更はより大変なものになるでしょう。

最初の近似として、サービスを実行時のプロセスにマッピングできそうだと気づくことがありますが、あくまでそれは最初の近似です。サービスは、アプリケーションプロセスとサービスからのみ用いられるデータベースのような、常に一緒にデプロイされる複数のプロセスから構成されることがあります。

ビジネス遂行能力に関わり組織が整理されること

巨大なアプリケーションを部分の集合に分割する場合に見られるのが、マネジメントがしばしば技術的なレイヤに焦点を当て、UIチーム、サーバサイドロジックチームそしてデータベースチーム、のような編成とすることです。チームがこのような考えかたに沿って分かれるとき、単純な変更でさえも時間や予算の承認に時間を要するチーム横断のプロジェクトとなることがあります。賢いチームはこのようなことを最適化し、よりましな方法を支持します - 必要とするどちらのアプリケーションにもロジックを押し込めるのです。言い換えると、ロジックをどこにでも埋め込み(Logic everywhere)ます。これはConwayの法則*4に従って行動した例です。

(一般的に定義される)システムを設計するどんな組織も、この組織のコミュニケーション構造の複製となる構造を持つ設計を生み出す。
-- Melvyn Conway, 1967

Conwayの法則の実際

組織の分割に対するマイクロサービスのアプローチは異なっており、ビジネス遂行能力に基づいて整理されたサービスに分割します。このようなサービスはビジネス領域に対応してソフトウェアのスタック実装の広範囲を収めることになります。UI、永続化ストレージ、そして任意の外部連携などです。その結果、チームは機能横断(cross-functional)型であり、開発のために必要な全ての範囲のスキルを含むことになります - ユーザ体験、データベース、そしてプロジェクト管理などです。

チームの境界で補強されたサービス境界

このような方法で組織されたある企業として www.comparethemarket.com が挙げられます。機能横断型のチームは各プロダクトを構築・運用する責務を持ち、各プロダクトはメッセージバスを通じて通信を行う複数の独立したサービスに分割されています。

一般的なことではないかも知れませんが、巨大なモノリシックアプリケーションもビジネス遂行能力に応じてモジュール化することができます。確かに、私たちはモノリシックアプリケーションを構築する巨大なチームを営業品目に沿って分割するように促しています。私たちが注目している主な議題はあまりに多くの文脈(context)に応じて組織を構築する傾向がある、ということです。もしモノリスが多数のモジュール境界をまたぐ場合、チームの個々のメンバの短期記憶にこの境界をなじませるのが難しくなる可能性があります。加えて、このモジュール境界を強制するためは大変な量の規律が必要であるということを経験してきました。必然的で、より明示的なサービスコンポーネントによる分割は明確なチーム境界を維持することを容易にします。

プロジェクトではなくプロダクト

私たちが見てきた大部分のアプリケーション開発の活動はプロジェクトモデルを使用しています: その目的はその後完成されると考えられるソフトウェアのある断片をデリバリすることにある、というものです。完成後、ソフトウェアは運用組織に引き渡され、ソフトウェアを構築したプロジェクトチームは解散します。

マイクロサービスの支持者はこのモデルを避ける傾向にあり、代わりにチームは製品のライフサイクル全体の責任を持つという概念を好みます。このような共通の発想はAmazonの概念である、"あなたが作ったものはあなたが実行する(you build, you run it)" というものであり、開発チームがソフトウェア製品の全面的な責任を負うということです。この概念は、サポートの重責を最低でも部分的に追わせることで、開発者が製品のソフトウェアの振る舞いと日々接点を持ち、そしてユーザとの接点を増やしていくようにさせます。

プロダクトを意識した心理は、ビジネス遂行能力への関連に結びついたものです。ソフトウェアを完成させるべき機能の集合として捉えるよりも、どうやってソフトウェアがユーザのビジネス遂行能力を高めることができるかということが問われる、進行中の関係が存在すると考えたほうがよいのです。

同じアプローチがモノリシックアプリケーションに採用できない理由はないのですが、細粒度のサービスはサービス開発者とユーザの間の個人的な関係を築きやすくすることが可能です。

賢い(smart)エンドポイントと土管

異なるプロセス間の通信構造を構築するとき、通信機構そのものにかなりの賢さを持たせる多くの製品やアプローチを見てきました。この良い例としてEnterprise Service Bus(ESB)があります。ESB製品はしばしばメッセージルーティング、コレオグラフィー、変換、そしてビジネスルールの適用のための洗練された機能を含んでいます。

マイクロサービスのコミュニティは代替のアプローチを支持します: 賢いエンドポイントと土管です。マイクロサービスから構築されるアプリケーションは可能な限り疎結合で凝集性を高くすることを目標とします - アプリケーションはドメインロジックを持ち、古典的なUnixの作法におけるフィルタ以上のものとして動作します - リクエストを受信し、適切なロジックを適用し、レスポンスを生成します。これらはWS-ChoreographyもしくはBPELもしくは中央集権的なツールによるオーケストレーションのような複雑なプロトコルではなく、シンプルなREST風プロトコルによって自治制御され(choreographed)ます。

もっとも共通に使用される2つのプロトコルは、リソースAPIを用いたHTTPのリクエスト-レスポンスと、軽量なメッセージ通信*5です。前者の最良の表現は

Webそのものであれ、Webの裏に隠れるな
-- Ian Robinson

マイクロサービスを扱うチームはworld wide web(と大きな拡張のもととなったUnix)を基礎にした原則とプロトコルを使用します。しばしば使用されるリソースは一部の開発者や運用要員のほんのちょっとの努力によりキャッシュすることができます。

共通の用いられる第二のアプローチは軽量なメッセージバス越しにメッセージ通信を行うことです。選択されるインフラは典型的にはダム(メッセージのルータとしてのみ動作するダム)です - RabbitMQもしくはZeroMQのような単純な実装は、信頼性のある非同期のファブリック以上のことは行いません - 賢さ(the smarts)はまさにメッセージの生成・消費を行うエンドポイントに存在します; つまり、サービスの中です。

モノリス内には、コンポーネントはプロセス内で実行され、コンポーネント間の通信はメソッド呼び出しもしくは関数コールのどちらによっても行われます。モノリスをマイクロサービスに変更する際に最も注目すべき点は、通信機構の変更です。インメモリのメソッド呼び出しからRPCへの安易な変換を採用してしまうと、あまりうまく機能しないおしゃべり(chatty)な通信となってしまいます。代わりに細粒度の通信を粗粒度のアプローチに置き換える必要があるでしょう。

分散統治

中央集権的な統治の結果の1つは単一の技術プラットフォームを標準とする傾向です。このアプローチは活動の抑制を招くことが経験からわかっています - 全ての問題が釘ではなく、全ての解決方法がハンマーではないのです。私たちは仕事を行うための正しいツールを使用することを好みます。モノリシックアプリケーションが、ある程度まで異なる言語を使用できる利点を得ることができるとしても、それは当たり前のことではありません。

モノリスコンポーネントを取り出してサービスに分割する際、これらの各々を構築する時には選択肢があります。単純なレポートページを構築するためにNode.jsを使いたいですか? やってみましょう。 特別にすばらしいほとんどリアルタイムな性能を持つコンポーネントを作るためのC++ですか? いいですね。あるコンポーネントのデータ読み出しの振る舞いに適した、違った雰囲気のデータベースに取り替える? 再構築するためのまさに適した技術があります。

もちろん、何かできるからと言って、それをしなければならないということではありません - しかしこのようにシステムを分割するということは、選択肢があるということを意味しているのです。

マイクロサービスを構築するチームは標準規格とは異なるアプローチを好むこともあります。論文のどこかに書き下され定義された標準の集合を用いるより、チームが直面した問題と同様の問題を他の開発者が解決できるような役に立つツールの作成をする発想を好みます。これらのツールは通常実装から生み出され、もっと広いグループで共有され、ときどき排他的な内部オープンソースモデルではない形式となります。gitとgithubが事実上標準のバージョンコントロールシステムの選択となった現在、組織内オープンソースの慣習はどんどん広まっています。

Netflixはこのような理念に従う組織の良い例です。役に立つものを共有し、中でも実戦で鍛えられたライブラリは他の開発者が同様の問題を同様な方法で解決することを促し、さらに必要な場合に別のアプローチを選択するための門戸を開いておくようにしています。共有ライブラリはデータストレージ、プロセス内通信、そして後に詳述するようにインフラ自動化のような共通の問題に焦点を当てる傾向にあります。

マイクロサービスのコミュニティにとっては、オーバーヘッドは特別気になることではありません。コミュニティがサービス契約に重きを置かない、ということが言いたいのではありません。まったく逆で、非常に重視する傾向にあります。単に、コミュニティはそれらの契約を管理するためにまったく別の方法について考えているだけです。Torelant ReaderConsumer-Driven Contractsのようなパターンはマイクロサービスにしばしば適用されています。これらはサービス契約が独自に進化することを支援します。開発の一環として消費者駆動契約を実行することは自信を増進し、サービスが機能しているかどうかのフィードバックを迅速に提供します。実際私は消費者駆動契約により新しいサービスをの構築を進めているあるオーストラリアのチームを知っています。彼らはサービスの契約を定義するシンプルなツールを用いています。このツールは新しいサービスのコーディングを行う前でさえ自動ビルドの一部となっています。サービスはその時契約を満足している点のみ開発されます- 新しいソフトウェアを構築するときに'YAGNI'*6のジレンマを回避するための洗練されたアプローチです。これらの技法ツールの活用は彼らのまわりで育まれ、サービス間の一時的結合を減少させることにより中央集権的な契約管理の必要性を制限しています。

おそらく分散統治の最高点は、Amaozonによって広められた、構築して実行するという理念です。チームは1週間に7日、24時間運用することを含め、ソフトウェアを構築したソフトウェアの全ての側面について責任を持ちます。このレベルの責任の移譲は普通のことでは決してありませんが、開発チームに対する責任を持たせる企業がどんどん増えるのを目にしています。Netflixもこの理念*7を取り入れた組織です。毎晩午前3時にポケットベルに起こされることは、コーディングを行う時に品質のことを考える強力な動機となります。これらの発想は実現が可能になるにつれて伝統的な中央集権的な統治モデルから離れることになります。

分散データ管理

データ管理の分散はいくつもの異なる方法が存在します。もっとも抽象的なレベルでは、システム間が異なる世界の概念的なモデルを意味します。このことは巨大な企業にわたって統合するときに共通の論点であり、顧客の販売観点はサポート観点とは異なります。販売観点の顧客と呼ばれる何かはサポート観点では全く出てこないでしょう。異なる属性を持ちうる、そしてもっと悪いことに微妙に異なる意味を持つ共通の属性のものごとがあります。

この論点はアプリケーションの間で共通ですが、アプリケーションの内部でも発生しうるもので、アプリケーションが別々のコンポーネントに分割されている時は特に顕著です。この問題を検討するときに有効な方法として、ドメイン指向設計(訳注: Domain-Driven Design、DDDと略されます)におけるドメイン境界があります。DDDは複雑なドメイン複数ドメイン境界に分割し、これらの関係を設計します。このプロセスはモノリシックとマイクロサービスの両方のアーキテクチャに有効ですが、サービスとコンテキスト境界の間には、これらを明確化することを助ける自然な関係があり、この章で述べるようにビジネス遂行能力がこれらの分離を強化します。

概念モデルについて分散する決定と同様に、マイクロサービスはデータストレージを分散させます。モノリシックアプリケーションが単一の論理データベースをデータの永続化のために用いることを好むのに対し、企業はいろいろなアプリケーションにわたり単一のデータベースを用いることを好みます - これらの決定の多くはライセンスに関連したベンダーの商用モデルに駆動されています。マイクロサービスは各サービスがおのおの所有するデータベースを管理するようにし、異なるインスタンスが同じデータベース技術でも全く異なるデータベースシステムでも構いません - これはPolyglot Persistenceと呼ばれます。モノリスにおいてもPolyglot Persistenceは使用できますが、マイクロサービスではより頻繁に見られます。

Polyglot Persistence

マイクロサービスを横断したデータのために分散された責務は、データの更新の管理に対する影響を示唆します。更新に対処する共通のアプローチは、複数のリソースを更新するときに一貫性を保証するためにトランザクションを用いることです。このアプローチはモノリスの内部でしばしば用いられます。

このようなトランザクションの使用は一貫性の維持を補助しますが、相当な一時的結合を強制し、この結合は複数のサービスを横断した難しい課題です。分散トランザクションは御存知の通り実装が難しく、結果としてマイクロサービスアーキテクチャサービス間のトランザクションを使わない協調を重要視します。この協調方法は一貫性は結果整合性のみがあればよく、問題は補償する操作により取り扱われるという明確な認識によります。

このような方法による一貫性の管理を選択することは多くの開発チームにとっては新しい挑戦ですが、これはビジネスの習慣にしばしば合致しています。しばしば実務では要求に対して素早く反応するために矛盾を処理します。この時、誤りに対処するためにある種の逆処理を行います。このトレードオフは、誤りを修正するコストが、より良い一貫性のもとでビジネスを失うコストより少ない限りは価値があります。

インフラ自動化

インフラ自動化技術はここ数年でめざましく進化しています - クラウドと特にAWSの進化はマイクロサービスの構築、デプロイ、運用の複雑度を減少させます。

マイクロサービスで構築された製品やサービスの多くは継続的デリバリ及びその先鞭となる継続的インテグレーションの豊富な経験を持つチームにより構築されています。この方法によりソフトウェアを構築しているチームはインフラ自動化技術の広範囲に使用しています。これは下記に示すビルドパイプラインにより図示されます。

Figure 5: basic build pipeline

本記事は継続的デリバリの記事ではないため、ここでは主要な2つの特徴のみについて触れます。私たちはソフトウェアが動作するという自信を可能な限り多く欲しいので、たくさんの自動化されたテストを実行します。動作しているソフトウェアがパイプラインを"上昇して"進行することは各々の新しい環境へのデプロイを自動化していることを意味しています。

モノリシックアプリケーションを構築・テストし、これらの環境を完遂することはまあ運良く行えるでしょう。いったんモノリスに対する製品へのパスを自動化することに精力をつぎこむと、アプリケーションをさらにデプロイすることはそんなに恐ろしいことではないことがわかります。継続的デリバリの目的の1つはデプロイを退屈にすることを忘れないで下さい。従ってアプリケーションが1つから3つになろうが、退屈である限りは問題ではありません*8

広範囲のインフラ自動化を使用したチームについて注目すべき点のもう一つは、製品においてマイクロサービスを管理するタイミングです。デプロイメントが退屈である限りモノリスとマイクロサービスの間に大した差がないという上記の主張とは対照的に、これらそれぞれの運用に関する状況はびっくりするほど異なります。

Figure 6: Module deployment often differs

障害のための設計

コンポーネントととしてサービスを使用する結果として、アプリケーションは各々のサービスの障害に耐えられるように設計される必要があります。任意のサービス呼び出しは供給側が稼働していないのが原因で失敗する可能性があり、クライアントはできるだけうまくこの状況に対応する必要があります。これはモノリシックな設計に比べて不利な点で、対応するために付加的な複雑さを導入する必要があります。その結果、マイクロサービスを採用するチームはサービスがユーザ体験に与える影響について絶えず検討します。NetflixのSimian Armyは、アプリケーションの耐久性と監視についてテストするために、勤務時間内にサービスやデータセンタさえに対しても障害を誘発させます。

製品に対するこの種の自動テストは、通常1週間の休暇の直前に起こるようなある種の恐怖による震えを、ほとんどの運用グループにもたらすのに十分なものでしょう。モノリシックアーキテクチャスタイルは洗練された監視の設定を行うのに十分であるとは言えません - 少なくとも私たちの経験では。

サービスはいつでも失敗する可能性があるため、素早く障害を検知し、可能であれば自動的にサービスを復旧することがすることが重要です。マイクロサービスアプリケーションはアプリケーションのリアルタイムな監視に重点を置いており、アーキテクチャの要素(データベースが受けた一秒あたりのリクエスト数)とビジネス上の関連する(一秒あたりに受信した注文数のような)メトリクスの両方を確認します。意味の監視を行うことで、開発チームが追跡・研究すべき何か悪いことを早期に警告するシステムを提供することができます。

マイクロサービスにとって、サービスのコレオグラフィーに対する好みやイベントのコラボレーションが不意の振る舞いに影響するため監視は特に重要です。多くの賢人が偶然の発生の価値を賞賛する一方で、不意の振る舞いは時によくない事態になりえるのは事実です。監視を行うことは、よくない不意の振る舞いを察知し、素早く修正できるようにするために必要不可欠です。

モノリスはマイクロサービスと同じくらい高い透明性で構築することができます - 実際、そうであるべきです。その違いは、異なるプロセスで実行されているサービスが切断された時に完全に把握することが必要であるということです。同じプロセス内のライブラリがある場合、この種の透明性は有効である見込みが少ないでしょう。

マイクロサービスを採用するチームは、サービスの死活状態と各種の運用とビジネスの関連するメトリクスを表示するダッシュボードのような、個々のサービスのために洗練された監視とログの設定を見られるようにしているでしょう。circuit breakerの状態、現在のスループットと遅延に関する詳細は現場でしばしば遭遇するメトリクスの例です。

進化的な設計

マイクロサービスの実践者は、通常進化的設計の経験をバックグラウンドに持ち、サービス分解を変化を減速させずに制御するためのさらに進んだツールであると考えています。変更の制御は必ずしも変更を減速するという意味ではありません - 正しい態度とツールによってソフトウェアを、頻繁、高速、そしてよく制御できるようになります。

ソフトウェアをコンポーネントに分解しようとするときはいつでも、どう断片に分割するかという決断に直面します - アプリケーションをスライスする場合の原則は何でしょうか? コンポーネントのキーとなる属性は独立した交換と更新ができるという概念*9です - つまり、関連モジュールに影響を与えずにコンポーネントを書き換えられるポイントを探す必要がある、ということです。確かに多くのマイクロサービスのグループは、長期的には多くのサービスが進化するよりスクラップにされることを明確に予想し、この概念を重視します。

GurdianのWebサイトはモノリスとして設計・構築され、マイクロサービスの方向に進化したアプリケーションの良い例です。モノリスは今もWebサイトのコアに存在していますが、新しい機能はモノリスAPIを用いたマイクロサービスとして構築されることが選択されます。このアプローチは本質的には一時的な機能、例えば特別ページやスポーツイベントのようなものに対しては特に便利です。このようなWebサイトの部分は高速に開発できる言語を利用して構成し、イベントが終了したらすぐに破棄するということが素早く行えます。同様のアプローチは金融機関でも見られ、マーケットの機会をとらえて新しいサービスを立ち上げ、数週間から数カ月後に廃棄されます。

交換性の重視はモジュール方式設計のより一般的な原則の特別な場合であり、この方式の設計は変更のパターン*10を通じてモジュール化を駆動するものです。変更は同時に同じモジュールに行われるのが望ましいものでしょう。めったに変更されないシステムの部分は、現在変更をたくさん行っている部分とは異なるサービスにするべきです。もし2つのサービスを同時に変更することが何度もあれば、それはそれらのサービスを1つにすべきサインです。

コンポーネントをサービスにはめ込むことは、より粒度の細かいリリース計画を行う機会を付け加えます。モノリスの場合、どんな変更もフルビルドとアプリケーション全体のデプロイメントを必要とします。マイクロサービスの場合は一方、変更したサービスのみを再デプロイすればよいだけです。このことはリリースプロセスを単純・高速にすることができます。欠点はあるサービスに対する変更がサービスを利用している他のサービスを壊していないかどうかを心配する必要があることです。従来の統合アプローチはバージョニングを用いてこの問題に対処しようとします。しかし、マイクロサービスの世界では、最後の手段としてのみバージョニングを用いることを選択します。サービスを提供側で可能な限り変更に耐えうるように設計することで、多くのバージョニングを回避することができます。

マイクロサービスは未来か?

この記事を書いた主な目的は、マイクロサービスの大枠のアイデアと原則を説明することです。記事を書く時間をとることで、私たちはマイクロサービスのアーキテクチャスタイルが重要なアイデアであるという考えをはっきり抱いてます - エンタープライズアプリケーションのための真剣な熟考に値するものの1つであるということです。私たちは最近このスタイルを用いていくつかのシステムを構築し、このアプローチを使用し好んでいる他の人々のことを知りました。

私たちが知っているAmazon、Netflix、The Gardian、英国政府の電子サービス、ealestate.com.au、Forwardとcomparethemarket.comを含む人々がこのアーキテクチャスタイルを何らかの方法で開拓しています。2013年の様々な会議はマイクロサービスに分類されそうな何かに移行しようとしている企業の例でいっぱいでした - これにはTravis CIを含みます。加えて、私たちがマイクロサービスに分類するであろう手法を長く行ってきた組織もたくさんありますが、マイクロサービスという名前は用いていないところもあります。(しばしばこれはSOAと呼称されます - しかし、既に述べたようにSOAは多くの対立する形式を持っています*11 )

これらの肯定的な経験にも関わらず、私たちはマイクロサービスこそがソフトウェアアーキテクチャの未来の方向性であるということに確信をもって議論しているわけではありません。現在の私たちの経験からいってモノリシックアプリケーションに比べて好ましいですが、自信を持って完全に判定を下すには時間がまだ経過していません。

しばしばアーキテクチャ決定の本当の結果は、構築してから数年経った後に実証されるものです。モジュール化の強い欲求がある良いチームが、年を経て衰退するモノリシックアーキテクチャを構築した複数のプロジェクトを見てきました。多くの人々が、サービス境界が明確であり、そこかしこにつぎはぎするのが難しいため、そのような衰退はマイクロサービスにより少なくなるのではないかと考えています。しかし十分な時を経た十分な数のシステムをまだ見ていないので、私たちはどうマイクロサービスアーキテクチャが成熟するか本当に判断することはできません。

マイクロサービスが不十分に成熟するのではないか、と誰かが考える理由は確かにあります。どんなコンポーネント化に対する努力でも、成功するかどうかはどうソフトウェアをコンポーネントに適合させるかにかかっています。コンポーネント境界をどこに線引きするべきかを正確に理解することは大変です。進化的設計は正しい境界を得ることの難しさを認識し、従ってリファクタリングしやすいということに重点を置きます。しかし、コンポーネントがリモート通信を行うサービスである時、リファクタリングはプロセス内のライブラリより大変なものとなります。サービス境界をまたいでコードを移動させるのは難しく、どんなインターフェイスの変更も関係者の間の調整が必要となり、後方互換性のためのレイヤが付加される必要があり、テストは複雑にならざるを得ません。

他の課題として、もしコンポーネントが整然と構成されない場合、コンポーネント内部の複雑性をコンポーネント間の接続の複雑性に移行することになります。これは単に複雑性が周りに移動したというだけでなく、そこが複雑性が明示的でなく制御が難しい場所だということです。コンポーネント内部が小さく単純になり一見良くなったように見えますが、サービス間のずさんな接続を見落としてしまいがちです。

最後に、チームスキルの要素があります。新技術はよりスキルが高いチームに適合する傾向があります。しかし、よりスキルが高いチームに効果的な技術が、よりスキルが低いチームで必ずしもうまく働くとは限らないでしょう。私たちはよりスキルが低いチームがひどいモノリシックアーキテクチャを構築した例を多数見てきましたが、この種のひどさがマイクロサービスに発生したときに何が起こるかは時が経ってみないとわかりません。貧弱なチームは常に貧弱なシステムを作ります - マイクロサービスがこのケースでひどい状況を緩和したり価値を創出するのかどうかを告げるのはとても難しいです。

私たちが聞いた1つの納得できる議論は、必ずしもマイクロサービスアーキテクチャからスタートしなければならないわけではない、というものです。モノリスから始める代わりに、モジュール化を保ち、一旦モノリスが問題になったらマイクロサービスに分割するのです。(良いプロセス内のインターフェイスは通常良いサービスインターフェイスでないため、このアドバイスが理想的というわけではありませんが)

そんなわけで、私たちは慎重な楽観主義を持ってこの記事を書いています。今までのところ、私たちはマイクロサービスを十分に観察し、これを踏み固めて道にする価値があるものであるという感触を得ています。これが終着点だと確信を持って言い放つことはできません。しかし、現在手に持っている完璧とは言いがたい情報をもとに決断を行うしかない、ということはソフトウェア開発の挑戦の1つでしょう。

組織パターン

組織パターン

エリック・エヴァンスのドメイン駆動設計

エリック・エヴァンスのドメイン駆動設計

実践ドメイン駆動設計

実践ドメイン駆動設計

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

*1:"マイクロサービス"という用語は2011年の5月にベネチア近郊で行われたソフトウェアアーキテクトのワークショップで議論され、参加者の多くが最近研究している共通のアーキテクチャスタイルを指す用語でした。2012年5月、同じグループは"マイクロサービス"をもっとも適した名前とすることに決定しました。Jamesは2012年3月にクラフクで行われた33rd Degree(訳注: 会議の名前)でこれらのアイデアのいくつかをケーススタディとしてMicroservices - Java, the Unix Wayの中で発表し、Fred Georgeもほぼ同じタイミングで発表を行いました。NetflixのAdrian Cockcroftはこのアプローチを"細粒度のSOA"と記述してWebスケールにおけるスタイルを開拓しており、他のメンバーであるJoe Walnes, Dan North, Evan Botcher and Graham Tackleyについても触れられています。

*2:モノリスという単語は、ときどきUnixのコミュニティので使用されていたものです。The Art of Unix Programmingでは大きすぎるシステムを指す用語として出現しています。

*3:私たちを含む多くのオブジェクト思考設計者は、サービスオブジェクトという単語をドメイン駆動設計の感覚、すなわちエンティティに関連付けられていない重要な処理を行うオブジェクト、という意味で使用します。これは私たちが本記事で使用している"サービス"と異なる概念です。不運にも、このサービスという単語は両方の意味を持っており、この多義語と暮らしていかなければなりません。

*4:Melvyn Conwayのwebサイト(ここ)でオリジナルの論文を見つけることができます。

*5:非常に大きい規模においては、組織はしばしばバイナリプロトコルに移行します - 例えばProtocol Buffersです。これらを使用したシステムはまだ賢いエンドポイントと土管の特性を示します - そしてスケールと透明性(訳注: おそらくデバッグのしやすさなど)をトレードオフします。ほとんどのweb資産と企業の疑いなくほとんど大部分はこのトレードオフを取る必要はありません - 透明性が大きく勝ります。

*6:"YAGNI"もしくは"You Aren't Going To Need It(必要になるまでやるな)"はXPの原則であり、あなたがそれを必要とするまで機能を追加しないようにするという忠告です。

*7:Adrian Cockcroftは2011年11月に開催されたFlowconの素晴らしいプレゼンの中で特別に"開発者のセルフサービス"と"開発者は自分の書いたものを実行する"について言及しました。

*8:ここで私たちは少し不誠実なことをしました。明らかに、よりたくさんのサービスを、より複雑なトポロジでデプロイすることは単一のモノリスをデプロイするより困難です。幸運なことにパターンを適用することにより複雑度を減少させることができます - ツールに投資することはそれでも必要ですが。

*9:実際、Dan Northはこのスタイルをマイクロサービスというより交換可能コンポーネントアーキテクチャとして言及しています。これはマイクロサービスの特性のサブセットの話題であると思われるので、私たちは後者のマイクロサービスという表現を採用します。

*10:Kent BeckはこれをImplementation Patternsの中で彼の設計原則の1つとして協調しました。

*11:そして、SOAはこの歴史の根源であるとはほとんど言うことができません。SOAという用語が今世紀初頭に出現したとき、私は人々が"私たちは長年これを実践していた"と口にしたことを忘れません。このスタイルは、その根源を、最初期のエンタープライズコンピューティングにおいてデータファイルを介して通信を行ったCOBOLプログラムの方法に見ることができる、という議論があります。別の言い方をすると、マイクロサービスはErlangのプログラミングモデルと同じものであるが、これをエンタープライズアプリケーションの文脈に適用したものである、と主張することも可能です。