マイクロサービスの危険性と効果的な導入について
マイクロサービスは「システムの変更速度を高める」ための戦略です。ただし、目的のために様々な犠牲を強いる劇薬で、使い方を誤れば長く続く痛みに苦しむことになります。一方で、的確に利用すれば大きな効果を発揮します。改めて、マイクロサービスが何を目的に、どんな手法をとるのか、理解しておきましょう。
“SHEFFIELD_06” by Heather Poore is licensed under CC BY-NC-ND 2.0
影響調査、リグレッションテスト、リリース調整...
システムの変更速度は「ある機能をリリースするとき、他機能との調整がある」ことで遅くなります。機能そのものを修正するコストというのは必ずかかります。その上でシステムの変更速度、つまり、変更結果をリリースするのが遅くなる理由は以下のような機能間調整です。
- ある機能を変更するのに、他機能への影響調査が必要になり、影響があれば追加修正が必要になる
- ある機能の変更による予期せぬ影響を避けるため、全機能リグレッションテストが必要になる
- 複数機能を変更する場合、もっとも時間がかかるものにリリースを合わせる必要がある
機能間調整が必要な理由は、機能同士が複雑に依存している、つまり密結合になっているからです。システムを1つの塊として設計され、実装されていると、一部の変更が全体に影響しうる状態となります。これをモノリス(一枚岩)と呼びます。
モノリスは無駄のないシステム構成を可能にします。例えば機能同士でロジックを共有する場合、共有レベルの階層化が容易です。すべてはメモリ内の処理のためクラス分割やメソッドコールにはほぼ制約がありません。また、型付き言語であればIDEがコード間の矛盾を検知してくれます。
とはいえ、ネットワーク経由のAPIコールやデータベース上のデータの共有までは整合性を確認するのは困難です。そのため、モノリスが巨大化してくると機能間の依存が複雑怪奇になり、その影響調査や調整が困難になるのです。
機能を疎結合化する
もし、機能間調整が不要になり、ある機能を直したら他機能との調整なしに、すぐリリースできればシステムの変更速度を速めることができるようになります。 このためにはシステム内で機能同士が互いに依存しない状態、つまり疎結合にしなくてはなりません。これを実現するシステム構成がマイクロサービスです。
マイクロサービスを最初に紹介した記事「microservices」ではいくつかの特徴があげられていますが、それを疎結合という観点で抜き出すと以下のようになります。
- 機能のインスタンスが分かれている(サービスとして分割)
- 機能間の連携はWebAPIになっている(HTTP(S)プロトコル+URI)
- 機能間でデータ(DB)を共有していない
- 機能のリリースは無停止で行える(リリース調整を不要にする)
- かつ、連携先サービスがダウンしている可能性を考慮した実装をする(サーキットブレーカー)
- 機能の技術要素は機能特性に合わせて個別に選択されている
- 機能単位でチームが分割している
インスタンスも別、データベースも別、リリースも別、コードも別、チームも別。つなげるときはAPIだけ。つまり、いままで1つの塊としてシステムで作ってきたものを、より小さな複数のシステムに分割せよ、ということです。機能間のやり取りがAPIに限定されていれば機能の修正による他機能への影響範囲は特定可能で、かつ、限定的にしていくことができます。
このようにマイクロサービスとは、従来の「他システム間連携」が「システム内の機能間連携」というスケールに適用されたもの、と考えることができます。このスケールの変化によってシステム内のサーバ台数が大きく増えるわけですが、そこは「クラウドによるインフラ仮想化」「DevOpsやNoOpsによるインフラ自動化」と言った技術群が支えるわけです。素晴らしい。
機能間の不整合を許容する
とはいえ「よし、マイクロサービスだ」とならないのは副作用があまりにも大きいからです。「これまでシステム内のオンメモリで連携していた処理をシステム間の連携のようにする」というのは大きな変化です。
最大の副作用は「機能間で不整合が発生する可能性が高くなる」ことです。いわゆる他システム間連携ではデータの共有タイミングがずれることで受け渡したデータに不整合が発生しえます。マイクロサービスでは、これと同じことがシステム内の機能間連携でも発生しえるのです。これがマイクロサービスの劇薬たるゆえんです。
マイクロサービスでは、たとえ機能間で不整合が発生する可能性が増えたとしても、機能を疎結合化し、システム全体としての変化速度をあげたほうがメリットがある、という考え方が前提です。
ウェブサービスに代表される変化を強く求められるシステムでは「大きなプロジェクトでシステムを開発し、その完成品を保守、改修していく」といったモデルではなく「システムを継続的に開発し、作り直し続ける」というモデルに変える必要があります。システムを完成まで無駄なく作り込むことよりも、たとえ、無駄や非効率な面があっても作り直しやすくしたほうがいいわけです。
マイクロサービスの導入
では、実際の現場では、どのようにマイクロサービスを導入すべきでしょうか。まず、理解すべきは「変化を強く求められる部分は機能間を疎結合にすべきだ」という基本概念です。その上で、機能間の疎結合を実現する手法がマイクロサービスという名前のもとに色々と用意されている、ということです。
たとえばキュー。非同期メッセージングは機能間の依存性を下げる効果的な手法です。メッセージの形さえ共有しておけば性能、可用性などの依存性を下げられます。
あるいは分散メモリキャッシュ。機能間の依存性を下げるにせよ、ユーザーのセッション情報などは共有する必要があります。こうしたのものは共有メモリ上に展開します。
またはリアルタイムストリーム処理。複数ノードからのログをリアルタイムに集約し続け、何かのトリガーがあればイベントを発火させるといったイベント駆動設計が可能になります。
こうした技術は古くからあるものです。ただ、個別システムで使うには保守性やコストで難しいものでした。現代ではフルマネージドなサービスを利用したり、オープンソース製品を使ったり、手軽に使い始めることができるようになっています。
よって、マイクロサービスはあらゆるシステムで導入可能です。ただし、全面的にマイクロサービスである必要はありません。システム全体を俯瞰したうえで、適切な箇所にマイクロサービスの手法を使えば、変化の速度をあげ、システムの価値を高めることができるでしょう。
そこで、私が推奨するのは「マイクロサービス化」という考え方です。マイクロサービス化とは既存システムに対して段階的にマイクロサービス的方式を導入することで再構築を行い、変化速度を徐々にあげていく手法です。
前述の通り、マイクロサービスはシステムの一部分から段階的に適用していくことができます。多くの、特にエンタープライズな現場では既存システムがあるものです。それを一括再構築するなどということを考えるべきではありません。マイクロサービスは変化を許容するための仕組みです。であれば、段階的にマイクロサービス的方式を取り入れてシステムの変化速度をあげていくのです。キュー、分散メモリキャッシュ、リアルタイムストリーム処理などは代表的な要素です。
最後に宣伝です。弊社では、こうしたマイクロサービス化に向けた支援サービスを提供しています。現状システム分析を元に、段階的にシステムを再構築していく方針づくりを技術面とプロセス面から支援します。ご興味があれば、ぜひご連絡ください。