マイクロサービスアーキテクチャのまとめ（メリット/デメリット/用いる技術）

#はじめに

マイクロサービスとは、[ThoughtWorks](https://www.thoughtworks.com/)社のマーチン・ファウラーとジェームス・ルイスが最初に提唱したソフトウェアアーキテクチャです。モノリシックアーキテクチャを、ビジネス機能に沿って複数の小さい「マイクロサービス」に分割し、それらを連携させるアーキテクチャにすることで、迅速なデプロイ、優れた回復性やスケーラビリティといった利点を実現しようとするものです。

今では[Amazon](https://www.amazon.com/)や[Spotify](https://www.spotify.com/)などの世界的テックカンパニーでも導入されるようになってきているため、弊社のサービスにも導入を検討するため、O'REILLYが発行する[『マイクロサービスアーキテクチャ』](https://www.oreilly.co.jp/books/9784873117607/)の書籍を読んだり、様々なマイクロサービスに関するドキュメントを読んだりしてきました。

その調査の中での気付きを自身の情報の整理の目的も兼ねて、記事として残しておこうと思います。
マイクロサービスの本質的な思想を理解することを目的としており、それを実現する技術的な方法までは踏み込んでいませんが、マイクロサービスアーキテクチャを検討・利用している人の助けになれば幸いです。

#マイクロサービスとは？

マイクロサービスは、「疎結合」と「高凝縮性」を特徴とし、サービスの境界をビジネスの境界に合わせ、特定の機能のコードがある場所を明確にします。境界を考える上で、Eric Evansが[『Domain-Driven Design』](https://www.amazon.co.jp/dp/4798121967)で述べた「境界づけられたコンテキスト」という概念がとても参考になります。

* 疎結合：連携するサービスに関して必要最低限のことしか情報を持たない
* 高凝縮性：関連のある動作をする箇所は1つに集中し、関係のない動作は別の場所に配置する

各マイクロサービスは、小規模なチームで管理できる規模とし、「２週間で書き直せるもの」とオーストラリアの[RealEstate](https://www.realestate.com.au/)社のJon Eavesは特徴付けています。
各マイクロサービスは、APIを公開し、それ経由で連携し、密結合のリスクを回避します。

##マイクロサービスのメリット

###技術異質性

ソフトウェアは、顧客に提供した後も変化に適用しなければならず、変化を許容できるように設計しなければなりません。
そして、会社のビジョンを実現するための技術が採用され続けなければなりません。

そのため、各マイクロサービスで最適な異なる技術を使う決断ができるというメリットは、ソフトウェア開発の変化の柔軟性を高めることに繋がります。
また、新たな技術を採用するサービスが複数存在するため、高いリスクをとることなく、新技術を採用することができます。

ただし、異なる技術を選定しても、システム間での通信を行うには、Googleが開発したプロトコルである[gRPC](https://grpc.io/)を利用するなどインターフェイスを統一しておく必要があります。

###回復性（レジリエンス）

障害の発生しているサービスを局所化することで、障害を分離して、他のサービスを継続して稼働させることができます。

ただし、それを実現するためには各サービスの状況を監視し、問題があれば迅速に検知するような仕組みが必要となります。
[Istio](https://istio.io/)や[Envoy](https://www.envoyproxy.io/)、[Linkerd](https://linkerd.io/)などマイクロサービス全体を管理するソフトウェアがその仕組みを構築するのに役立つので、このツールの導入も合わせて検討すべきでしょう。

###スケーリング

大規模なサービスとなると、システムは障害に対処したり、負荷を分散したりするためにスケールしなければなりません。
マイクロサービスでは、スケーリングが必要なサービスだけをスケールし、他のサービスをそのまま動作させ続けることができるため、サービスの可用性を高めることができます。

また、不要なスケーリングをする必要がないため、コストも効率的に制御することができます。

###デプロイの容易性

変更したサービスを独立してデプロイでき、問題が生じても原因を迅速に特定できるので、迅速なロールバックを実現することができます。
また、これにより新機能を顧客に迅速に提供することができます。

ただし、複数のサービスのデプロイ管理は複雑化するため、テストを含めて自動化の技術を採用し、サービスの増加に伴って複雑度が高まりすぎないようにする工夫なしなければならないでしょう。

また、デプロイとリリースを分離するブルーグリーンやカナリアといったリリーステクニックを採用し、リリース失敗のリスクを軽減することも重要です。

###組織面の一致

Melvin Conwayは、論文「How Do Committees Invent?」の中で下記のように述べています。

>システムを設計するあらゆる組織は、必ずその組織のコミュニケーション構造に倣った構造を持つ設計を生み出す。

この記述は「コンウェイの法則」として、組織構造が提供するシステムの性質に強く影響することを示しており、組織と一致しないシステム設計をする危険性を改めて認識させてくれます。

マイクロサービスでは、アーキテクチャをより組織に一致させることができ、1つのサービスに関わる人数を最小化し、チームの大きさと生産性を最適化することができます。

###再利用や交換可能にするための最適化

複数のサービスで共通して利用するような機能については、1つのサービスとして切り出すことで、サービスを複数のサービスに跨って再利用する機会を増やすことができます。

また、サービス全体の書き換えや削除に対する障壁が低く、難なく完全に書き直したり、必要なくなったらサービスを削除したりすることができます。

##マイクロサービスのデメリット

###運用管理の負荷

複数のマイクロサービスに分割するため、管理対象が増加し、運用管理は複雑化する傾向があります。また、障害が発生した際も複数のサービスから原因を特定しなければならないので、障害解析は高難易度化しがちです。
各サービスのメトリクスや障害の状況を監視するための負荷が高まるので、上にも記載した通り、[Istio](https://istio.io/)などのマイクロサービス全体を管理するソフトウェアの導入は検討すべきだろう。

###設計の難易度が高い

サービスを適切に分割することがマイクロサービスアーキテクチャを導入する際の肝となります。適切に分割してサービスの依存性をうまく排除しないと、メリットを享受できなくなってしまいます。しかし、一方でサービスを細分化し過ぎると、その分システム全体が必要以上に複雑化し、運用管理の負荷が高まってしまうので、ビジネスドメインを深く理解した上で適切に分割しなければなりません。

###LatencyやOverheadが増える

1つの機能を実現するために、多くのマイクロサービス同士の連鎖的なAPI通信が発生することになります。このため、Latencyが伸びたり、Overheadが増えたりします。

###学習コストの増大

サービス毎に異なる技術スタックを採用していると、サービス間で人を異動させる際、新たに技術を学習するオーバーヘッドが発生します。ただし、これはビジネスに合わせた異なる技術を採用できるというメリットとのトレードオフなので、それを考慮して採用する技術は意思決定すべきでしょう。

#マイクロサービスのデメリットを解消する方法とは？

###インフラストラクチャー

####コンテナ技術

クラウド環境上で稼動するマイクロサービスの基盤技術として、現在は「コンテナ」が主流になりつつある。コンテナとは、OS上に個々のアプリケーションごとの専用区画を作り出す技術であり、仮想化技術の1つである。現在はLinux由来の[Docker](https://www.docker.com/)が主流になっている。

コンテナをベースとしたマイクロサービスでは、個々のモジュールごとにコンテナを用意し、プロセス間の連携はAPIを介して行う。お互いのコンテナ内部に直接アクセスしたり、中身を変更したりできない。また、機能変更の際は、コンテナ単位で迅速に入れ替えすることができる。

さらに、コンテナは、アプリケーションとそれが依存するライブラリなど、必要最小限のものを入れるだけでよいので、マイクロサービスと非常に相性が良い。

####サービスメッシュ

冗長性確保やスケーリングのために同じマイクロサービスを並行して複数稼動させることも多いが、各マイクロサービスが使用するIPアドレスが動的に変動するため、この場合ロードバランサーのように動的に接続先を管理する仕組みが必要となり、サービスやそのネットワーク接続を管理するシステムを「サービスメッシュ」と呼ぶ。

クラスタインフラ管理機能を提供する[Kubernetes](https://kubernetes.io/)ではシンプルなサービスメッシュ機能が組み込まれている。また、独自のサービスメッシュ機能を提供するクラウドインフラストラクチャもある。[Istio](https://istio.io/)や[Linkerd](https://linkerd.io/)といった、インフラストラクチャに依存せずにサービスメッシュ機能を提供するソフトウェアもある。

これらは独自のプロキシを利用してマイクロサービス間の通信を管理する仕組みになっており、適切な接続の転送に加えて、ロードバランサーやネットワークゲートウェイ、認証、モニタリングなどの機能も備えている。

###コンポーネント間通信技術

マイクロサービスアーキテクチャでは、各マイクロサービスがほかのマイクロサービスと通信して処理を実行する。マイクロサービス同士がやり取りする情報は「メッセージ」と呼ばれる。

####同期的メッセージ処理

[gRPC](https://grpc.io/)はGoogleが開発を進めるRPC実装で、効率的にデータをやり取りできることや、HTTP/2ベースでの双方向通信がサポートされている点などが特徴。

###デプロイとアップデート

クラウド型のインフラストラクチャを利用する場合、ある程度はインフラストラクチャ側でデプロイやアップデートのための機能が提供される。たとえば[Kubernetes](https://kubernetes.io/)では、deploymentという、デプロイのための機能が用意されている。また、多くのクラウドサービスでは自動化のためのAPIなどが提供されている。[Istio](https://istio.io/)や[Linkerd](https://linkerd.io/)といったサービスメッシュ支援ツールにもデプロイのための機能が用意されている。

#まとめ

上記で述べてきた通り、マイクロサービスには大きなメリットがありますが、デメリットとのトレードオフです。
そのため、会社のビジョンや組織戦略を踏まえた上で、どのようなタイミングでどのようにマイクロサービスアーキテクチャを導入していくかをしっかり考えることがとても重要でしょう。