KOBITブログ

マイクロサービスの論文を完全日本語翻訳してみた。(1万5667字)

この記事は約 33分 で読めます。

internet

こんにちは。クリエイターズネクストの窪田です。今日は話題になっているマイクロサービスについて記載したいと思います。

マイクロサービスとはJames Lewis氏がこちらで提唱し、話題になった考え方です。最近、至るところで話題になっていますが、実際の原文を読んだ方は少ないのではないでしょうか。その要点を丁寧に解説したブログは多く存在しましたが、完全に翻訳しているブログは見たことがなかったので、今回はその翻訳にチャレンジしてみました。

マイクロサービスとは?

「マイクロサービス」 – さまざまなソフトウェアのアーキテクチャーがひしめき合う世界にまた新たな用語が現れた。普通ならたいして気にも留めずに聞き流してしまうところだが、この言葉にはソフトウェア・システムのスタイルの一つとして何か強く訴えかける響きがある。ここ何年か、多くのプロジェクトでこのスタイルが実際に用いられてきたようだが、その結果は総じて評判が良く、今後これが企業向けアプリケーションを開発する際の標準的スタイルになっていくだろう、と言う仲間も多くいる。しかしながら残念なことに、このマイクロサービスとはいったい何でどう役に立つのか、情報が極めて少ないのが現状だ。

簡単にいえば、マイクロサービスというアーキテクチャー上のスタイルとは、ある一つのアプリケーションを一連の小さなサービスの集まりとする開発手法であり、そのそれぞれのサービスはそれぞれのプロセスを持って独立して走りながら、HTTPリソースAPIなどの軽量なメカニズムを用いて互いに通信しあうのだ。これらのサービスはそれぞれが実務の処理能力を持っており、また、各サービスの装置類への配分は十分に自動化されていてそれぞれ独立に配分が決められるのだ。それぞれのサービスは異なるプログラム言語で書かれ異なるデータ・ストレージ技術を利用していても良く、それらの集中管理はごく最低限に抑えられている。

マイクロサービスというスタイルを説明するには、モノリシック型のスタイルと比較するのがいいだろう。つまり、単体のユニットととして作られる 「モノリシック」 (一枚岩) 型のアプリケーションとの比較である。企業向けアプリケーションはふつう大きく3つの部分に分けられる。すなわち、クライアント側ユーザーインターフェース (ユーザーのマシン上のブラウザで走るHTMLのページやJAVAスクリプトから成る)、データベース (一つの共通の、普通はリレーショナル・データベース管理システムに収められた数多くのテーブルから成る)、それにサーバー側アプリケーションの3つである。このサーバー側アプリケーションは、HTTPリクエストを処理し、ドメイン・ロジックを実行し、データベースからデータを検索しまた更新し、またブラウザーに送られるHTML画面を選び出して追加する。このサーバー側アプリケーションはモノリシック型であり、すなわち、単独で論理的に実行可能な形式を持っている。システムに何らかの変更を加える場合は必ず、このサーバー側アプリケーションの新バージョンを開発し利用することになる。

サーバーはそのシステムとしての性質上、モノリシック型で開発するのが自然である。あるリクエストを処理するためのロジックはすべて単一のプロセス内で実行され、開発に使用する言語の基本性能を使いこなして、アプリケーションをクラス別、機能別、ネームスペース別に分けて開発することができる。注意深く作業すれば、開発者のラップトップ上にあるアプリケーションを実行しテストできるし、配備パイプラインを利用して変更点を適切にテストし確認しながら製品に実装することができる。また負荷分散装置の背後に多くのインスタンスを走らせて、このモノリシック型システムをホリゾンタルに拡張することもできる。

モノリシック型アプリケーションはなかなか優れたものだが、とりわけ多くのアプリケーションがクラウド上で配備されるようになってからは、不満を感じることが多くなってきた。変更作業はたがいに繋がりを持っている、つまり、アプリケーションのごく小さな部分に変更を加える場合でも、モノリシック型の全体に手を加えて配備しなおさなければならないのだ。時間が経てば良好なモジュラー構造を保ち続けることも難しくなり、ある一つのモジュールだけに関係するような変更であっても、変更をそのモジュールだけに留めることが難しくなってくる。拡張する場合でも、アプリケーションの必要な部分だけではなく全体を拡張しなければならず、返って大きなリソースが必要になってしまう。

sketch
図1: モノリシックとマイクロサービス

こうした不満から出てきたのが、アプリケーションを一連のサービスとして作り上げるマイクロサービスというアーキテクチャーのスタイルである。個々のサービスは他とは独立に配備できるし拡張できるうえに、それぞれが一つのモジュールとして明白な境界を持っており、たとえば異なるサービスを異なるプログラム言語で書いてもかまわない。さらに、サービスごとに管理者が異なっていても良いのだ。

かと言ってこのマイクロサービスのスタイルは、その根本は少なくともUNIXの設計原理にまで遡ることができるのだから、決して新しい訳でも革新的という訳でもない。それでも、これまでこのマイクロサービスというアーキテクチャーの利用を考えた人が少なかったのは確かだし、これを利用するほうが多くの場合ソフトウェア開発に有利なこともはっきりしている。

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

このマイクロサービスのアーキテクチャーに正式な定義があるわけではないが、この名にふさわしいアーキテクチャーが持つ一般的な性質を明らかにすることはできる。もちろん、共通の性質の概要を示すといっても、すべてのマイクロサービスがそのすべての性質を持つというのではなく、多くのマイクロサービスが持つと思われる性質をできる限り多く示す、という意味である。この文を書いている者は全員がこの緩やかに結びついたコミュニティーの現役メンバーなので、私たちの意図は、私たちが仕事を通じて見たものや私たちに関わりのあるチームの努力に基づいて記述することである。特に、私たちはマイクロサービスに相当する何らかの定義を与えたい訳ではない。

サービス別のコンポーネント化

私たちはソフトウェア業界にいるのだから、この物理的な世界でさまざまな要素が結びついて物ができているのと同じようにして、要素部品を集め繋ぎあわせてシステムを作り上げたいというのが、一つの望みである。ここ20年ほどの間、ほとんどの言語プラットフォームの一部である共通ライブラリーに関して長足の進歩がなされ、今ではその大きな一覧表ができるほどである。

コンポーネントについて考えた場合、一つのコンポーネントを作る物は何かを定義しようとすると、たちまち困難に陥る。私たちの定義によれば、コンポーネントとは、それ自体で他とは無関係に置き換えや改良ができるような、ひとまとまりのソフトウェアのことである。

マイクロサービス・アーキテクチャーもライブラリーを用いるが、そこで使われるソフトウェアをコンポーネント化する主な方法は、サービス単位で分割することである。ここでライブラリーとは、一つのプログラムに関係づけられ、メモリー上に置かれたファンクション・コールで呼び出されるようなコンポーネント、と定義されるが、一方、サービスとは、たとえばウェブサービス・リクエストやリモートプロシージャコールなどのメカニズムを通じてやり取りをするアウトオブプロセス型コンポーネントを指す。

サービスを (ライブラリーではなく) コンポーネントとして用いる一つの大きな理由は、サービスであれば独立して配備ができるからである。あなたが一つのプロセスに複数のライブラリーを用いるようなアプリケーションを持つならば、そのどれかのコンポーネント一つに変更を加える場合でも、アプリケーション全体を配備し直さなければならない。でももしそのアプリケーションが複数のサービスに分解できるならば、そのサービスのどれか一つに対する変更は多くの場合、そのサービスのみの再配備で収めることができる。そうはならない場合もあって、たとえばサービス・インターフェースに関わるような変更の場合は広範囲の調整が必要になるが、マイクロサービス・アーキテクチャーをうまく作りあげれば、影響の及ぶ範囲を小さくして、ひとまとまりのサービス境界や展開メカニズムをサービスコントラクトに定めることができる。

サービスをコンポーネントとして用いるもう一つの重要なポイントは、コンポーネント間のインターフェースがより明確になることだ。多くの言語には、明白な公式インターフェースをうまく定義できるようなメカニズムが備わっていない。あるコンポーネントを包むカプセルをクライアントが壊すことがないように文書による指針が示されるのみで、その結果、コンポーネント間を必要以上に固く結合させてしまうことになる。サービスであればリモートコール・メカニズムを明示的に用いてこのような過剰な結合を避けやすくできる。

このようなサービスの用い方には、負の側面もある。リモートコールはインプロセス・コールよりも費用がかかるし、そのためリモートAPIは粒度の粗いままにせざるを得ず、その結果しばしば使い勝手が悪くなるのだ。コンポーネント間の責任分担を変更する必要が生じた場合も、プロセス境界を超えるとなると実現が難しくなる。

ちょっと見では、サービスはランタイムのプロセスのために使えそうだが、それは第一印象にすぎない。一つのサービスは通常は複数のプロセスからできるが、これは、たとえばそのサービスでしか用いられないアプリケーション・プロセスとデータベースの組み合わせのように、普通は同時に開発され配備されるはずのものなのだ。

実務の処理能力に基づいた組織化

大きなアプリケーションをいくつかの部分に分けて開発する場合、管理者は、UI担当、サーバー側ロジック担当、データベース担当、という具合にテクノロジーレイヤー別にこれを分けようとしがちだ。このようにして担当チームが分断されると、ほんの小さな変更さえも全チームに影響を与え、時間もかかるし予算承認も必要になってしまう。頭のいいチームなら妥協点を見つけ、どちらかましな方を支持するだろう。つまり、そのロジックをそのチームが扱うアプリケーションに埋め込んでしまうのだ。どこでもいいから、と言ってもよい。これは、コンウェイの法則が生かされる一例だ。

ある (広義の) システムを設計する組織は常に、その組織内部のコミュニケーションの構造をそのまま反映した構造のデザインを開発するものだ。
- メルヴィン・コンウェイ 1967年

conways-law

 

図2: コンウェイの法則の実現

マイクロサービスのアプローチで行う分割はこれとは異なり、実務の処理能力に基づいていくつかのサービスへと分ける。これらのサービスにより、それぞれの実務、たとえばユーザーインターフェースや固定記憶、外部との共同作業などに対応するソフトウェアに広範囲にスタックを実装することになる。その結果、開発チームは機能横断的になり、ユーザー体験やデータベースやプロジェクト管理などを含む、開発に必要なあらゆる範囲のスキルが要求される。

実務の処理能力に基づいてその組織を決めた会社の一例が www.comparethemarket.com である。機能横断的なチームがそれぞれの製品の開発と運営に責任を持ち、それぞれの製品はメッセージ・バスを通じて通信しあう数多くの単独サービスに分割される。

大きなモノリシック型アプリケーションもまた、通常、実務の処理能力に従ってモジュール化できるが、これは一般的ではない。確かに、私たちは一つの大きなチームに対し、一つのモノリシック型アプリケーションを実務別に分割してください、と言うことがある。ここでの大きな問題は、その実務の別はあまりに多くの背景事情を反映してそうなっているという点だ。もしこのモノリシック型システムが多くのモジュラー境界を越えて広がっているならば、チームのメンバーひとりひとりにとってそれを短期メモリーの中にうまく落とし込むことは難しいだろう。さらに、その多くのモジュラーが備えるべき原理原則も非常に数が多くなる。サービスコンポーネントをを用いてもう少しすっきりと分割することができれば、このチーム間の境界も明確化できる。

プロジェクトではなくて製品

アプリケーション開発の努力は多くの場合、一つのプロジェクトモデルを使っているようだ。その時点において完成形と考えられるソフトウェアをいくつか提供するのがその目的だ。そうして出来上がったソフトウェアはメンテナンス担当チームに引き渡され、開発チームは解散する。

マイクロサービスの支持者たちはこのモデルを使いたがらず、開発チームがその製品を寿命がある間は担当し続けるべきだ、という考え方を好む。こうした考え方で良く知られているのが、アマゾンの 「作った者が実行せよ」 (“you build, you run it”) というスローガンであり、現場で稼働するソフトウェアに関し開発チームにすべての責任を負わせるものだ。したがって開発者は、稼働中のソフトウェアの動作状況に日々接し、またユーザーとも緊密に情報交換をして、サポート業務の少なくとも一翼を担わなくてはならないのだ。

製品に対するメンタリティにも、実務の処理能力との結びつきがある。ソフトウェアを、さっさと終わらせるべきひとまとまりの職務と見るのではなく、どうしたらユーザー側の実務の処理能力の向上をこのソフトウェアを通じてサポートできるかと問いかけるような、現在進行中の関係が存在する。

このようなアプローチがモノリシック型アプリケーションの開発でも取れないわけはないのだが、粒度が小さいサービスの方が、サービスの開発者とそのユーザーとの間の個人的な関係を築きやすいのだろう。

賢いエンドポイントと愚かなパイプ

異なるストラクチャーの間にコミュニケーションの構造を築く場合、コミュニケーションのメカニズム自体をきわめて知的に作りこんだと強調する製品や開発方法を多く見かける。その好例がエンタープライズ・サービス・バス (ESB) であり、ESB製品にはメッセージのルーティング、振り付け、形式変換、会社規則の適用などのための洗練された機能が盛り込まれているという。

マイクロサービスのコミュニティは別のアプローチを好む。いわば、賢いエンドポイント・愚かなパイプ型だ。マイクロサービスで構築されるアプリケーションが目標とするのは、可能な限り分割してそれぞれをしっかりまとめることだ。それぞれが自分自身のドメインロジックを持ち、古典的なUnixの意味でのフィルターのように振る舞って、リクエストを受け、適切にロジックを適用し、応答を返すのだ。つまり、WS-ChoreographyとかBPELとか中央に位置するツールのオーケストレーションといった複雑なプロトコルを使う代わりに単純なRESTishプロトコルを用いてコエログラフ (サービスの振り付け) をするのだ。

最もよく利用されるプロトコルは、リソースAPIを用いたHTTPリクエスト-レスポンスと、ライトウェイト・メッセージングである。前者を非常にうまく言い表した言葉がある。

ウェブの一部になれ、ウェブの背後に隠れるな。
– イアン・ロビンソン

マイクロサービスの開発チームが利用する原理とプロトコルは、ワールドワイドウェブ (およびUnixが相当規模で) の基礎となっている原理とプロトコルである。何を利用したかは、開発者側でも運営者側でも難なく隠すことができる。

一般に使われる2つ目のアプローチは、ライトウェイト・メッセージ・バス上のメッセージングである。一般的にはここで使われるのは処理能力の低いインフラストラクチャー (メッセージ用ルーターにしか使えないほどの処理能力) であり、たとえばRabbitMQやZeroMQなどの信頼性のある非同期構造を提供する以外に使い道のないような簡単な実装である。高性能を発揮するのはエンドポイントの側であり、多くのサービスの間でメッセージを生成し消費する。

モノリシック型では、コンポーネントはインプロセスで実行され、コンポーネント間のコミュニケーションはメソッド・インボケーションまたはファンクションコールで行われる。このモノリシック型をマイクロサービスに変更する際の最大の問題点は、このコミュニケーションのパターンをどのように変えるかにある。インメモリーのメソッド・コールをRPCにそのまま変換するだけでは、中途半端なやり取りが増えるばかりでうまく機能しない。そうではなくて、粒度が粗いアプローチをする粒度の細かなコミュニケーションへと変換しなければならない。

管理の分散化

集中管理を進めた結果の一つには、単一テクノロジーのプラットフォーム上での標準化が進む傾向が挙げられる。しかし経験上、このアプローチには制約も多い。これですべての問題点を取り扱える訳ではないしどんなソリューションでも利用できるという訳でもない。私たちはそれよりも、必要な仕事に適したツールを使うほうが良いし、モノリシック型アプリケーションが異なる言語に対してもある程度の利点を持つというもののそれは決して一般的ではないのだから。

モノリシック型のコンポーネントを分けていくつかのサービスにする際には、それぞれのサービスを作り上げる際にさまざまな選択ができる。単一のレポートページを立ち上げるのにNode.jsを使いたいだろうか、ならばそうしよう。ほとんどリアルタイムで動作する素晴らしいコンポーネントにはC++を使おうか、それはいい。一つのコンポーネントのリード動作により適するようにデータベースにちょっと味付けをしたければ、それができるだけのテクノロジーは揃っている。

もちろん、なにかができるからと言って、それをしないといけないわけではない。でも、あなたのシステムをこのように部分的に変更できるとすれば、それはオプションがあるということだ。

マイクロサービスの開発チームは標準とは異なったアプローチも好んで使う。本のどこかに書かれているような決まりの標準を利用するよりも、自分と同じ問題に直面している開発者がいればその人も使うことができるような役に立つツールを作り出すという考え方を気に入っているのだ。そうしたツールは通常は実装した中から取り出してきて広く他のグループにも使ってもらうのであって、オープンソースモデルを社内向けとして排他的に使うのであってはならない。今のところ、コントロールシステムではgitとgithubが事実上の標準仕様として選ばれているので、どの社内でもオープンソースを用いた開発がますます一般的になっている。

Netflixがこうした哲学に従う企業の好例である。実際の役に立ち市場での競争に勝ち抜いてきたコードをライブラリーとして共有しあっているので、社内で同様の問題に出くわした開発者は同様の解決方法を用いることもできるし、また必要ならばまったく異なる解決方法を選ぶこともできるのだ。共有ライブラリーは一般的な問題点について焦点を当てたものが多い。たとえば、データ・ストレージ、プロセス相互間のコミュニケーション、それに以下で議論するインフラストラクチャーの自動化などの問題だ。

マイクロサービスのコミュニティにとって、オーバーヘッドの発生はとりわけ残念だ。とはいえこれは、このコミュニティがサービスコントラクトを軽視しているという話ではない。その逆で、ほとんどがこれを尊重している。ここで言っているのは、サービスコントラクトを別の角度から見ているという意味だ。トレラント・リーダー (Tolerant Reader) とかコンシューマードリブン・コントラクト (Consumer-Driven Contracts) に現れるパターンはマイクロサービスでもしばしば応用される。これらは、サービスコントラクトが個別に発展するのに役立っている。あなたの開発の一部としてコンシューマードリブン・コントラクトを実行するならば安心感が増すし、あなたのサービスが正しく機能しているかどうか素早くフィードバックが得られる。実際、私たちの知っているオーストラリアのチームはコンシューマードリブン・コントラクトを用いて新しいサービスを開発した。シンプルなツール群を使って、あるサービスに対するコントラクトを定義できたのだ。これは自動化されたビルドの一部となったのだが、その時は新しいサービスのコードの開発に取り掛かる前だった。その後から、サービスが、そのコントラクトを満足するように開発されたのだ。これは、新しいソフトウェアを開発する際のYAGNI (必要になるまでは不要) のジレンマを避けるエレガントなやり方だ。こうしたテクニックやツールが揃っていけば、サービスを一時的にも結合する必要がなくなるので、コントラクトによる中央制御の必要性も少なくなる。

恐らく、アマゾンが広めた 「作った者が実行せよ」 の価値観こそ分散管理の真骨頂であろう。開発チームが、開発したソフトウェアについて連日24時間の運用をはじめあらゆる側面に責任を持ち続けるのだ。このレベルでの責任の委譲はもちろん規則でも何でもないが、いまではますます多くの企業が開発チームに責任を集中させようとしている。Netflixはこの価値観を採用したもう一つの代表例である。ページャーに毎朝3時に叩き起こされるとなると、コードの開発時からその品質に細心の注意を払う大きなインセンティブになるだろう。こうした考え方は、従来の集中管理モデルから可能な限り対極にある。

データ管理の分散化

データ管理の分散化は多くの異なる方法で行われる。最も抽象的な表現をすれば、これは、世界についての概念モデルがシステムごとに異なることを意味している。これは大きな企業の全体に導入する際にはつきものの問題である。顧客に対してセールスが抱く見解とサポートが抱く見解は当然異なるのだ。だからセールス側の見解に従えば顧客と呼ばれる者も、サポート側の見解に従うと顧客の範疇ではないかもしれない。それぞれに異なる属性を持っていたり、(さらに悪いことに) 語義が微妙に違うものが同じ属性を持っていたりするのだ。

同じ問題はアプリケーション間でも生じるし、またアプリケーションの中でも生じる。アプリケーションがいくつかのコンポーネントに分けられる場合ならなおさらだ。この理解に役立つ例は、コンテキスト境界 (Bounded Context) でのドメイン・ドリブン・デザイン (DDD) という概念だ。このDDDがある複雑なドメインをいくつかのコンテキスト境界に分割してそれぞれの間の関係性を導き出す。このプロセスは、モノリシック型とマイクロサービス・アーキテクチャーのどちらにも役に立つが、サービスとコンテキスト境界には自然な相関関係があるのだから分かりやすいし、実務の処理能力の節で論じたように、分割を正当化できる。

概念モデルに関連する様々な決定を分散管理するのと同様に、マイクロサービスはデータストレージに関するさまざまな決定も分散管理する。モノリシック型アプリケーションが永続的データに対する単一の論理データベースを求めるのに対し、多くの企業は一定範囲のアプリケーションに渡る単一データベースを好む。これは、ライセンス形態に基づいた販売モデルを進めるベンダー側の言うことを聞いた結果だろう。マイクロサービスでは、同じデータベース技術を用いた異なるインスタンスであれ、まったく異なるデータベース・システムであれ、それぞれのサービスはそれ自身のデータベースの管理に任せる方を好む。これは、ポリグロット・パーシスタンスと呼ばれるアプローチだ。モノリシック型でもこのポリグロット・パーシスタンスのアプローチは使えるが、マイクロサービスでより頻繁に用いられるようである。

多数のマイクロサービスにまたがるデータに対する責任を分散管理する場合、アップデートも管理することになる。アップデートを取り扱う一般的な方法はこれまで、複数のリソースのアップデートに際して首尾一貫性を保証できるようなトランザクションを用いるというものだった。このアプローチはモノリシック型で多用されてきた。

このようにしてトランザクションを利用すれば、首尾一貫性を保つ上では役に立つが、複数サービスを含んでいる場合には厄介な連結の作業が数多く発生する。分散トランザクションは実装が難しいことで知られており、それゆえマイクロサービスのアーキテクチャーでは種々のサービス間でトランザクション無しの協調が際立った特徴となる。この場合、首尾一貫性が保たれるにせよそれは最終的にそうなるのであり、問題点は運用を進める中で安定化が進むことがはっきりと知られている。

このようにして首尾一貫性が失われた状態をうまく管理するほうを選ぶと、多くの開発チームにとっては新たな困難が生じる。とは言え、それは企業活動の通常の姿でもある。どの企業も市場の要求に素早く対応するために普段からいくらかでも矛盾のある状況に対処しているし、また間違いの処理のためにはある種の逆課程も利用している。そうして間違いを修復するためのコストが、ビジネス機会を失いながら優れた首尾一貫性を保ち続ける場合のコストを下回る限り、その差引勘定は合っている。

インフラストラクチャーの自動化

インフラストラクチャー自動化のテクニックはここ数年の間に大きく進展した。クラウド、とりわけAWSの勃興が、マイクロサービスの構築と配備ならびに運用時の複雑さを低減したからだ。

マイクロサービスの手法で作られた製品やサービスのの開発チームの多くは、コンティニュアス・デリバリー (CD, Contiinuous Delovery) やその元になったコンティニュアス・インテグレーション (Continuous Integration) を用いた開発の十分な経験がある。このようなソフトウェアの開発方法になれたチームは、インフラストラクチャー自動化のテクニックを非常にうまく使いこなす。これに関連して、開発パイプラインを以下に図示した。

コンティニュアス・デリバリーは本稿の主題ではないので、ここではいくつかのポイントだけをまとめておく。私たちは開発しているソフトウェアが所定の動作をするというできる限りの自信を得たいので、テストを自動化して何回も繰り返す。だから所定の動作をしているソフトウェアをパイプラインの中へと 「格上げする」 ことは、新しい環境のそれぞれに対する配備の自動化を進めることになる。

モノリシック型アプリケーションは開発されてテストされた後、このような環境の中へと適切に送り込まれる。そしてひとたびあなたがモノリシック型の開発の道筋の自動化に投資したなら、その後はどれだけ多くのアプリケーションを配備することになっても怯まなくて済む。大事な点は、このCDの狙いの一つが配備の作業を退屈なほど楽にすることなので、新しいアプリケーションがいくつあろうと、その配備のための作業が退屈である限り構いはしないのだ。

開発チームがインフラストラクチャーの自動化を大きく進めているもう一つの分野が、マイクロサービスの本稼働を進める工程である。たった今、モノリシック型であろうとマイクロサービスであろうと、配備工程が簡単である限り大きな違いはないと述べたばかりだが、運営する立場から見るとこの2つには大きな違いがある。

障害発生を見越した設計

サービスをコンポーネントとして使う場合には、アプリケーションはサービスに障害が起こっても支障のないように設計する必要がある。どのサービスコールであれサプライヤー側で準備ができなければ障害となるので、クライアント側はこれをできるだけ寛大に対処する必要がある。これはモノリシック型デザインに比べると、複雑な対処方法を追加しなければならないのだから不都合だ。その結果、マイクロサービスの開発チームは、サービスの障害がユーザー経験にどのように影響するかを常に考慮し続けなければならない。Netflixのシミアン・アーミーは、サービスやデータセンターにさえもわざと障害を誘発させて、アプリケーションの障害への耐性や監視についてのテストを稼働時間中に行っている。

この種の実働中の自動化テストにより、運用担当グループは次の週末を待たずに問題点を知ることができる。でもこれは、モノリシック型アーキテクチャーのスタイルが洗練されたモニター用セットアップに対応する能力がないなどと言っているのではない。経験上、あまり一般的ではないだけだ。

サービスはいつでも障害を引き起こす感応性があるのだから、障害の発生をいち早く知ること、そして可能ならサービスを自動的に修復することが大切となる。マイクロサービス・アプリケーションでは、アーキテクチャー関連の要素 (データベースが毎秒受け取るリクエスト数) とビジネスに関連した諸測定 (たとえば毎分受け取るオーダー数) の両方をチェックしており、アプリケーションの実時間モニターを非常に大切に考えている。セマンティックを監視すれば何か調子が悪い場合の早期警報システムができるので、開発チームの支援を得て子細な調査を行う引き金にできる。

これはマイクロサービス・アーキテクチャーには極めて重要である。というのも、マイクロサービスではコレオグラフィーやイベントのコラボレーションを好んで用いるので、突発的な事態が発生しやすい。そうして思いがけない幸運を手にすることもあるだろうが、実際には良くないことが起こるものだ。監視を続け、良くない突発事象の発生を即座に知って対処できることが極めて重要である。

モノリシック型もマイクロサービスと同じくらい透明性を高めて作ることができるし、実際そうしなければならない。異なる点はと言えば、別プロセスで走っているサービスがいつ切り離されるかをあなたは絶対に知らなければならない、という点だ。同じプロセスのライブラリーを使う場合ならば、この種の透明性はそれほど役に立たない。

マイクロサービスのチームは、高性能の監視機能を見たいだろうし、上昇/下降の状態を示すダッシュボードをはじめさまざまな運用上ならびにビジネス関連の測定など個々のサービスに対するログの設定を見たいと思うだろう。サーキットブレーカーの詳細な状態、現在のスループットやレイテンシーなども実地ではしばしば見る必要が生じる。

革新的なデザイン

マイクロサービスを実行している人たちは、たいてい革新的な設計手法の経験者であり、サービスの分解を一つの先進的なツール、すなわち、変更が必要になった時に開発者が遅滞なく十分な管理下で作業を進めるためのツールだと考える人たちだ。変更を管理するからと言って、必ずしも変更の作業自体が減るわけではない。正しい態度で適切なツールを使って作業を進めれば、管理の行き届いた変更を何度でも素早くソフトウェアに施すことができるのだ。

一つのソフトウェアをいくつかのコンポーネントに分けるときは、どのように分けるか、どのような原則に基づいてアプリケーションを分割すればいいのだろうか、という問題がつきものだ。コンポーネントが備えるべき重要なポイントは、単独で取り換えることができること、単独で更新できること であり、つまり、仲間に何らの負担をかけずにそのコンポーネントだけに手を加えたいのだ。実際、多くのマイクロサービスのグループではさらに、時が経って古くなったサービスについては更新するよりもむしろ廃棄がいいと言っている。

ザ・ガーディアン紙のウェブサイトは、モノリシック型デザインで作られながらマイクロサービスの方へと形を変えてきたアプリケーションのいい例だ。モノリシック型は依然としてこのウェブサイトの基本をなすが、新しい機能を付加する際には、このモノリシック型が持つAPIを利用してマイクロサービスの手法で開発している。このアプローチは、たとえばスポーツのイベントの特集ページなどの、一時的という特徴を持つ機能に対してとりわけ好都合である。ウェブサイトにはそうして急ごしらえで作られたページが即座に並べられ、そのイベントが終わるとすぐに取り外されるのだ。金融機関でも同様のアプローチが取られている。マーケットに新たな機会を提供するためのサービスが付け加えられ、それが数か月か数週間もたたないうちに廃棄されるのだ。

このように置き換え可能性を重宝するのは、変更のパターンからモジュラー化のやり方を決めるというモジュラーデザインの一般原則からすれば、特殊例である。あなたは、同じモジュールにあって変更の際に同時に取り換えられてしまういくつかの事柄を、できればそのままにしておきたい。システム中でめったに変更されずに使い続けられている部分品は、今使用中のたくさんの容器から別のサービスへ移されなければならない。もし2つのサービスを何回も一緒に変更しているなら、それらは一つにまとめた方がいいということだ。

コンポーネントをサービスの中に付加すれば、より粒度の細かな計画を立てるチャンスとなる。モノリシック型ではどのような変更でもアプリケーションを丸ごと、全体を作り直して配備しなければならない。これに対してマイクロサービスなら、修正を加えたサービスだけを再配備すればよい。これでリリースまでの作業がすばやく簡単にできる。この場合の難点は、一つのサービスに加えた変更が原因で多くの利用者を失ってしまわないかと心配しなければならない点だ。従来の統合化されたアプローチではバージョン管理という方法でこの問題に対処しようとするが、マイクロサービスの世界ではバージョンによる管理は最後の手段である。バージョンが増えすぎる事態は、サプライヤー側での変更に対してできる限りの耐性を持つようにサービスを設計することによって避けることができる。

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

本稿の趣旨は、マイクロサービスという概念とその原理の骨格を説明することである。ここまで整理し説明してきて、私たちははっきりと、マイクロサービスというアーキテクチャーやスタイルがとても重要な概念であり、企業向けアプリケーションに向けて真面目に考える価値があると確信した。いままで私たちはいくつものシステムをこのスタイルで開発してきたし、このアプローチを気に入って利用している多くの仲間も知っている。

私たちの知る限りこのアーキテクチャーのスタイルでいくらかでも先駆的な仕事をしたのは、たとえばAmazon、Netflix、ザ・ガーディアン紙、英国政府デジタルサービス、realestate.com.au、Forwardそれにcomparethemarket.comなどである。2013年はどのカンファレンスに出席しても、多くの会社がマイクロサービスと呼ぶにふさわしい事柄に向かって動き始めている実例に溢れていた。Travis CIもその一つだ。さらに、私たちがマイクロサービスと呼んでいるのと同じものに別の名を付けて、すでに活動を始めている多くの会社がある。(多くはSOAと呼ばれるものだが、私たちがすでに述べた通り、SOAにはいくつかの矛盾する形式がある。)

このような肯定的な事例はあるのだが、私たちはまだ、マイクロサービスがソフトウェア・アーキテクチャーの将来の方向性を示しているかどうか、確信を持っていない。モノリシック型と比べればこれまでの経験上前向きではあるが、最終判断を下すのに十分な時間はまだ経っていないことは確かだ。

アーキテクチャーについて何かの決断をして、その結果が本当はっきりするまでには何年もの時間がかかるものだ。モジュール化を強く望む優秀な開発チームがモノリシック型のアーキテクチャーを開発して、それがここ何年かで崩壊してしまったようなプロジェクトを、私たちはいくつも見てきた。多くの人々が、マイクロサービスではそのような崩壊は起こらないだろう、と信じている。サービス境界ははっきりと分かっているしそれは丈夫でいくらでもパッチを当てられるから、という訳だ。それでも私たちは、十分な数のシステムを十分な年月にわたって見た後でなければ、マイクロサービスがどのように成熟していくかなど判断はできない。

マイクロサービスという技術は対して成熟しない、との考え方にも一理がある。コンポーネント化をどのように進めようと、ソフトウェアの成功はそれがいかに多くのコンポーネントとうまく適合するかにかかっている。コンポーネント境界をどこに置くべきか、正確に見つけ出すのは難しい。デザインが進化すれば、正しく境界を定めることのむずかしさがますますはっきりするし、リファクタリングの重要性もはっきりしてくる。でも、あなたのコンポーネントが遠隔でコミュニケーションができるサービスであったなら、プロセスの内部にライブラリーを持っている場合に比較して、リファクタリングは極めて難しいものになる。サービス境界を越えてのコードの移動は難しいし、インターフェースに何か変更が加わるたびに参加者全員の間での調整作業が必要になるし、レイヤーやバックグラウンドの互換性も確保しなければならないし、テストもさらに複雑になる。

もう一つの問題は、もしコンポーネントが分かりやすく作られていなかったなら、あなたの全作業は、あるコンポーネントの内部からコンポーネント間の結びつきまでに渡って複雑なものになってしまう。しかも、複雑さが増すばかりではなく明快さが失われ、管理が難しくなる。もしあなたが調べるのが小さくてシンプルなコンポーネントの内部であって、しかもサービス間に厄介な結びつきが無いのであれば、状況ははるかに良いと誰もが思うだろう。

最後に、開発チームのスキルも問題になる。新しいテクニックはスキルのあるチームによって採用されることが多い。しかし、より高いスキルを持つチームにとってより効果的なテクニックが、スキルの低いチームに対しても有効に働くとは必ずしも言えない。これまでスキルの劣るチームがややこしいモノリシック型アーキテクチャーを開発してきた例をいくつも見てきたが、マイクロサービスでもこのような混乱が起こるかどうかはこれから時間をかけて見ていかなければならない。へたくそなチームは常にへたくそなシステムを作り出すとして、マイクロサービスに変えた場合にはたして混乱が減るのか事態を悪くするのか、占うことはできない。

私たちが耳にした一つの理にかなった説明は、最初にマイクロサービスから開発を初めてはいけない、というものだ。そうではなく、モノリシック型から始め、そのモジュラー化を保ち、そのモノリシック型に何か問題点が生じたら初めて、マイクロサービスに分ければいい、というのだ。(しかしこのアドバイスは完璧ではない。良くできたプロセス内インターフェースは決して良いアサービス間インターフェースではないのだから。)

だから、本稿は注意付きの楽天主義で書かれている。ここまで、マイクロサービスというスタイルが、歩いていくにふさわしい道だと感じてもらえるよう、丁寧に説明をしてきた。ひどい結末に終わることは恐らくないだろうが、ソフトウェア開発に付きまとう困難の一つは、つねに自分の手元にあるだけの不完全な情報に基づいて決断をしなければならない、という点なのだ。


さあ、KOBITをスタートしよう。