【読書】モノリスからマイクロサービスへ

5 min read読了の目安(約5200字

オライリー社の「モノリスからマイクロサービスへ モノリスを進化させる実践以降ガイド」を読んだのでメモとして。

https://www.oreilly.co.jp/books/9784873119311/

一通り読んだ感想として、マイクロサービスアーキテクチャのメリット・デメリット、そしてタイトルにもあるようにいかにしてモノリスからマイクロサービスへと移行するかについて、簡単な例とともに様々な移行パターンが掲載されており、著者の方の豊富な経験と洞察が伺えました。

また、タイトルこそマイクロサービスへの移行を勧めているように見えますが、モノリスとマイクロサービスのそれぞれの特性を整理した上で、モノリスの有用性やむしろモノリスが適した状況にきちんと触れている点にも非常に好感が持てました。

章構成は以下のようになっており、A4版で240ページほどでした。

  1. 必要十分なマイクロサービス
  2. 移行を計画する
  3. モノリスを分割する
  4. データベースを分割する
  5. 成長の痛み
  6. 終わりに

書籍の対象読者としては、(私も含めて)マイクロサービスの経験があまりない方も想定されています。一方でドメイン駆動開発(DDD)に関する知識があると、理解がスムーズな箇所があります。私は事前に「Clean Architecture」と「ドメイン駆動開発入門」という本を読んだことがあり、本書の理解の助けになりました。書籍内では王道である「エリック・エヴァンスのドメイン駆動設計」を参考書籍にあげています。

https://asciidwango.jp/post/176293765750/clean-architecture

https://www.shoeisha.co.jp/book/detail/9784798150727

https://www.shoeisha.co.jp/book/detail/9784798126708

「3章 モノリスを分割する」や「4章 データベースを分割する」は、実際に業務で携わったことがある人はより身近に感じられるのではないかと思います。個人的には業務レベルでデータベースに触れる機会がなかったため4章はやや消化不良感はありましたが、全く内容が分からないほどではなかったと思います。以降は特に重要に感じた点をいくつか振り返ります。

1章:必要十分なマイクロサービス

1章では、マイクロサービスの利点と問題、モノリスの課題と利点、ドメイン駆動開発とマイクロサービスとの関連性などについて触れられています。

マイクロサービスとは「独立してデプロイ可能なサービス」として紹介されています。これを採用することで、各サービスが並行して開発できるようになる、サービスごとに柔軟な技術選定が可能になるなどのメリットをあげています。一方でサービス間で情報をやり取りするため、レイテンシーの増加やパケット喪失などといった問題が起きやすくなるとしています。これらの問題にはモノリスの時には考えずに済んだものもあり、こうしたトレードオフに向き合うことの重要性を強調しています。

2章:移行を計画する

2章では(技術的というよりも)組織レベルで、どのような軸でマイクロサービスの導入を決めるか、また導入する際にはどのように移行作業を計画すれば良いかを紹介しています。

1章に引き続きですが、マイクロサービスを導入することそのものがゴールではないことを強調しています。マイクロサービスを選ぶ理由としては、

  • チームの自立性の向上
  • 市場投入までの時間の短縮
  • サービスごとの柔軟なスケーリング

などを挙げています。一方で以下のようなケースではマイクロサービスが適していないと述べています。

  • ドメインが不明瞭な場合
  • スタートアップ
  • もっともな理由を持たない場合

特にスタートアップ企業とマイクロサービスとの関連性は興味深いと感じました。NetflixやAirbnbなどといった企業がマイクロサービスアーキテクチャに移行したのは、その進化の後半でサービスのスケールアップが重要であったからと述べています。このことからも、マイクロサービスの導入を検討する際には、何を目的とするのか慎重に見極める必要があるとわかります。

すでに顧客がいる状態のモノリスからマイクロサービスに移行する際には、段階的に取り組むことの重要性を強調しています。実行計画の段階では、ドメイン駆動設計によって既存のモノリシックシステムを論理的に分解し、分解しやすさと分解による利益を考慮した上でマイクロサービスへと切り出していくことを勧めています。また開発にあたっては、移行が想定どおり進んでいるかを検証するための定期的な振り返りや、定量・定性評価が必要だとも書かれています。

3,4章ではモノリスからマイクロサービスへの移行パターンがさらに具体的に紹介されますが、段階的に移行することの重要性は繰り返し触れられます。この根底には移行における間違いの発生を受け入れた上で、できるだけ小さな間違いを目指すべきという意図があるとしています。

2章の半分ほどは技術的というよりも、組織やチームにおいてどうマイクロサービスへの移行を計画するかという内容でした。業務としてマイクロサービスを検討する際には、技術的要素と並んで重要であることが伺えます。

3章:モノリスを分割する

3章では既存のモノリスをどのようにリファクタリングするかについて、いくつかの移行パターンが丁寧に紹介されています。

ストラングラーパターン

移行パターンの一つとして、ストラングラーパターンが紹介されています。ストラングラーパターンは特に、外部の呼び出しを受け取る上流のサービスを移行するのに適しています。呼び出しをリダイレクトするだけで移行前後のサービスを切り替えることができるため、不具合が発生した場合での簡単に元のサービスに切り替えることができます。下の図では給与計算サービスをマイクロサービスとして切り出しています。


ストラングラーパターンによる機能の抽出

抽象化によるブランチ

ストラングラーパターンは簡単でありながら様々な場面で応用が効くアプローチです。一方で抽出したい機能が既存システムの下流に存在する(例えば図のユーザー通知サービス)場合には、既存システム自体を変更する必要があります。「抽象化によるブランチ」はこうした場合に適した移行パターンとして紹介されています。サービスの抽象を作成し、その実装の中身をマイクロサービスとして切り出すことで下流の機能を切り出すことができます。


抽象化によるブランチによる機能の抽出

上図は抽象化によるブランチのある段階であり、書籍ではさらに詳しく移行の段階を紹介しています。

これらの他に、ユーザーインターフェイスを移行するための「UI合成」、新しく実装したサービスの信頼性を検証するための「同時実行」、モノリスの挙動に応じて別の動作をトリガーするための「デコレーティングコラボレーター」など、様々な移行パターンが紹介されています。

4章:データベースを分割する

3章ではモノリスの機能をマイクロサービスへ移行する方法を紹介していたのに対して、4章ではモノリスなデータベースを移行する方法を紹介しています。データベースの分割を行う際には、移行中のデータ同期や、トランザクションの整合性、テーブル結合やレイテンシーなどといった課題が発生します。

そもそも基礎となるスキーマを分割するのが困難な場合のパターンも紹介されています。「データベースビュー」はビューによってそれぞれのマイクロサービスに必要な情報のみを公開します。「データベースをラップするサービス」では薄いラッパーサービスを構築することで、データベースへの依存関係をサービスへの依存関係に移動します。これらの方法は、根本的に既存のデータベースが分割されるわけではないことに注意する必要があります。

「集約を公開するモノリス」と「データ所有権の変更」はそれぞれ、マイクロサービスが必要とするデータの所有権をモノリス側におく場合とマイクロサービス側におく場合の管理パターンです。

データ同期

既存のデータベースからデータを移行する方法としては、「アプリケーションでのデータ同期」と「トレーサー書き込み」などを紹介しています。

「アプリケーションでのデータ同期」では、最初に一括でデータをコピーし、二つのデータベースに対して書き込み、読み取りを切り替えていくことで、データを同期しながら新しいデータベースへ移行します。「トレーサー書き込み」は「アプリケーションでのデータ同期」の一種ですが、サービスインターフェイスを通してデータの同期を行います。

データベースとコードのどちらを先に分割するか

著者はデータベースとコードのどちらを先に分割するかについても言及しています。状況によるとした上で、移行に際してパフォーマンスやデータの一貫性への潜在的な影響が考えられる場合はスキーマの分割を先に行い、それ以外ではコード分割の分割を先に行うのが良さそうと述べています。

マイクロサービスによるトランザクション

データベースを分割する際に起こり得る問題として、トランザクションについても触れています。一つのトランザクションに複数のマイクロサービスが関わる場合には、ACIDトランザクションにおけるAtomicity(原子性:トランザクション内の操作が全て成功するか、全て失敗するかのどちらかであるという性質)に問題が起きやすいとしています。

サーガパターンは、トランザクションにおいてリソースが長時間ロックを回避するための方法です。トランザクションを構成する各操作はマイクロサービスに結びつけられます。操作全体に対するロールバックは、補償トランザクションを実行することで行います。

サーガの実装としては、ロジックの管理サービスを設けるオーケストレーションベースの方法と、イベントの発行と受信からなるコレオグラフィベースの方法を紹介しています。この二つはサーガの進行状況の追跡や実装の結合具合に違いがあり、関与するチームの数に応じて使い分けるのが良いとしています。

また書面への記載はありませんが、以下のexampleではGCPのサービスを組み合わせて、コレオグラフィベースのサーガを実装しています。

https://github.com/GoogleCloudPlatform/transactional-microservice-examples

5章:成長の痛み

5章では、マイクロサービスアーキテクチャを導入していく途中で起こり得るいくつかの問題について、その兆候や対処法に触れています。また管理・運用するサービスの数と、関係するチームが増えるにつれて発生しやすい問題の傾向も変わるとしています。

  • 2〜10個のサービス:破壊的変更、レポーティング
  • 10〜50個のサービス:所有権のスケール、開発者体験、あまりにも多くのものを実行している
  • 50個以上のサービス:全体最適と局所最適、孤児サービス

サービスの数が中規模な場合の、「あまりにも多くのものを実行している」とは、サービス数の増加に伴いデプロイ、設計、管理などが増え、スケーリングが難しくなることを指しています。この問題に有効なツールとしてはKubernetesを挙げていますが、一方で素のKubernetesは開発者に優しくないとも述べています。パブリッククラウドを利用している場合には、インフラ管理など運用上の手間を抑えられる方法として、FaaSやサーバーレス技術の利用を勧めています。

感想

最初にも述べたとおり、総じて著者の豊富な経験が詰まった良書だと感じました。それぞれのパターンにおいて、モノリスからマイクロサービスへ「移行」する過程が豊富な図とともに解説されています。同時に使いどころや適していないシーンにも触れられており、実践を意識した内容であると言えます。また特定のツールに結びついた話が少ないという意味でも、多くの状況に対して汎用な洞察になっていると感じました。