マイクロサービスは「複数のデザインパターンの集合体」
入門編で解説したようなマイクロサービスを構成し、その利点を実現するためには、ひとつひとつのシステム構成要素に対する細かなデザインパターン[1]の適用が必要となります。言い換えると、マイクロサービスを適用したシステムとは、「複数のデザインパターンの集合体」です。本記事では、具体的にどのようなデザインパターンが存在し、どのような狙いで適用されるのかを見ていきます。読むことで、どのような設計をすればマイクロサービスが実現できるかがイメージしやすくなるでしょう。
加えて、各クラウドベンダーが提供している機能(マイクロサービス向けのものが多くあります)が何を意図したサービスなのかが理解でき、適切な機能の選定もしやすくなります。さらに、これらの言わば「枝葉」に対する説明を見てから、改めて入門編で説明した概要という幹に立ち戻ることで、マイクロサービスというアーキテクチャの理念をより深く理解することができます。
[1] デザインパターン:システム開発における典型的な課題の解決や、よく求められる要件への対応策を実現するのに適した、設計の「型」のこと。
関連するデザインパターンはたくさんありますが、ここでは代表的なものを抜粋した上で、イメージしやすいように入門編で解説した5つの利点(独立性、保守性、拡張性、可用性、再利用性)ごとに分類して整理しました(複数の利点にかかるデザインパターンは、解説に適したものに分類しています)。ひとつひとつ見ていきましょう。
(1)独立性を高めるデザインパターン
マイクロサービス導入による現行機能への影響を抑える:Strangler(絞め殺し)とTolerant Reader(寛容な読み手)
マイクロサービス適用の代表的なシーンの1つは、既存のモノリスからの置き換えです。マイクロサービスは個々のサービス(ビジネスロジック)が独立した状態になります。よって置き換えは、サービスの単位でモノリスから少しずつ機能を切り出し、段階的にリリースすることが可能です。むしろその方が望ましいとされます。なぜなら、ビッグバン型[2]での刷新は、そのリスク(開発規模の肥大化、人的リソースや予算の確保の高難度化、マネジメントの複雑化など)が大きいためです。
[2] ビッグバン型:一気に全体を置き換えること
Stranglerパターンでは、モノリスの前にファサード[3]と呼ばれる機能を配置します。ファサードは、切り出した新サービスで処理すべきものと、旧来のモノリスで処理すべきものを振り分けます。開発を進めて少しずつ新サービスを増やす(既存機能を置き換える)たびに、モノリスに振り分けるリクエストが減少していき、最終的にモノリスは完全に不要となります(モノリスを絞め殺し=Stranglerにする)。この新旧への振り分けを実行するのは、呼び出されるサービスの裏側。そのため呼び出し側は、どのリクエストが新サービスによって処理されたのか、そしてモノリスがいつ排除されたのか、どちらも意識することはありません。
[3] ファサード:「建物の正面」を意味するリクエスト受付用のプログラム
また、このStranglerパターンを適用する際に、Tolerant Readerパターンも併用すると効果的です。直訳すれば「寛容な読み手」となりますが、簡単に言えば、呼び出す側(Reader)が、呼び出される側の変更をできるだけ「柔軟に受け止められる」作りにしておく、という考え方です。次のような具体例で見るのが理解しやすいでしょう。
モノリスの個別機能を新サービスに切り出した際、同時にそこからの返却値を整理し、レイアウトを変更したいと考えたとします。図2の①の例では、もともとあったXMLのレイアウトに「user」という新たなタグを追加しました。旧レイアウトとの違いは、階層構造に変更が入った点のみで、ターゲットの要素自体は変わっていません。
この返却値に対し、図の②の例のように、呼び出す側が階層構造まで見る厳密な読み取り方をしていると、レイアウト変更の影響を受けてしまい修正が必要となります。しかし、図の③の例のように、呼び出す側がXPath Language[4]で項目のみを指定している作りであれば、機能修正は必要ありません。呼び出す側がこのように「寛容」であれば、呼び出される側は独立性が高まり、設計における自由度が向上します。
[4] XPath Language(XPath、エックスパス):XMLに準拠した文書の特定の部分を指定して取得できる言語のこと。絶対パス指定による要素の取得以外にも、一部のパスを省略して取得するなど、柔軟な指定が可能。
業務ロジックとその他の周辺処理を分離させ、言語選択の柔軟性を高める:Sidecar(サイドカー)とPolyglot Programming(多言語プログラミング)
マイクロサービスはそれぞれのサービスが独立し、一般にテキストデータを投げ合うことでつながります。そのため、個々のサービスが内部でどのような技術(構成や言語など)で作成されるかは自由です。一方で、思い思いに作成されたサービスたちは、主処理である業務ロジックだけでなく、さまざまな周辺処理(ログ出力や設定情報など)までそれぞれの技術にあわせた個別実装が必要になってしまいます。
この課題を解決するのがSidecarパターンです。バイクに取り付けるサイドカーのように、主処理であるアプリケーションに別のコンポーネントを付属させる構造とします。このパターンを適用することにより、各サービスは共通的な周辺処理をそのコンポーネントに任せられます。その結果、開発者は主処理の実装だけに専念できるようになります。
上記によって実現しやすくなるのがPolyglot Programmingです。従来は、システム全体で1種類の汎用プログラミング言語[5]と、SQLのようなデータストア用のドメイン固有言語[6]、という構成が定番でした。しかしそれでは、最大公約数的な言語選択しかできず、個々のサービスにとって最適とは言えません。多様な(=Polyglot)言語選択により、業務特性や要件、メンバーのスキルセットにあわせた最適化を行うことができる。それがPolyglot Programmingの考え方です。
[5] 汎用プログラミング言語:特定の用途に限定されない言語。JavaやCなどのいわゆる一般的なアプリケーション開発言語はこれにあたる
[6] ドメイン固有言語:特定の用途向けの言語。代表的なものはRDB向けの言語であるSQLなど