kakakakakku blog

Weekly Tech Blog: Keep on Learning!

モノリス分割はこうやる!「How to break a Monolith into Microservices」を読んだ

研修中に「マイクロサービス」の解説をしていると,たまに「モノリス分割」に関する質問が出てディスカッションをすることがある.当然ながら万能な分割アプローチはないけど,例えば DDD (Domain-driven design) などのアプローチを選択するなど,選択肢はいろいろある.そして最近「モノリス分割」に役立つアプローチを紹介した martinfowler.com の記事「How to break a Monolith into Microservices」を読んだ.

具体的には以下の「計8種類」のアプローチが紹介されている.原著を翻訳するのではなく,あくまで個人的なメモとしてまとめる.なお,日本語も個人的に載せているため,参考程度にしてもらればと!

  1. Warm Up with a Simple and Fairly Decoupled Capability(シンプルかつ分離された機能で準備する)
  2. Minimize Dependency Back to the Monolith(依存関係を最小限に抑えてモノリスに戻す)
  3. Split Sticky Capabilities Early(厄介な機能を早めに分割する)
  4. Decouple Vertically and Release the Data Early(垂直分割でデータを早めに分割する)
  5. Decouple What is Important to the Business and Changes Frequently(ビジネス的に重要で頻繁に変更される機能を分割する)
  6. Decouple Capability and not Code(コードではなく機能を分割する)
  7. Go Macro First, then Micro(まずマクロ,次にマイクロ)
  8. Migrate in Atomic Evolutionary Steps(小さい進化的なステップで移行する)

martinfowler.com

前提

原著は「デリバリーチーム(開発者 / 設計者 / 技術マネージャー)」に対して「モノリス分割に役立つアプローチ」を紹介することを目的にしている.なお,解説を具体的にイメージできるように「オンライン小売アプリケーション (multitier online retail application)」がテーマになっている.そして,マイクロサービスの基礎は書籍「マイクロサービスアーキテクチャ」などを読んで理解していることが前提になる.

マイクロサービスアーキテクチャ

マイクロサービスアーキテクチャ

  • 作者:Sam Newman
  • 発売日: 2016/02/26
  • メディア: 単行本(ソフトカバー)

1. Warm Up with a Simple and Fairly Decoupled Capability(シンプルかつ分離された機能で準備する)

マイクロサービスを実践するためには,デプロイパイプラインを構築したり,分散アプリケーションをモニタリングしたり,最低限の運用準備が必要になる.そこで,第一歩として「モノリスから分離された機能 (capabilities that are fairly decoupled from the monolith)」から着手していく案はどうか?と書いてある.モノリスから分離されていれば,デプロイパイプラインの検証をするなど,影響を少なくできる.またチームメンバーのスキルアップにも繋がり,マイクロサービスの運用を実践できるメリットがある.「オンライン小売アプリケーション」で言えば「エンドユーザー認証サービス」「顧客プロファイルサービス」が例として挙げられている.

やはり,実際に経験することは重要だし,明確に「チームメンバーのスキルアップ」の必要性まで言及されているのは素晴らしい!と同時に「エンドユーザー認証サービス」は第一歩にしては影響が大きすぎるのでは?とも思った.あくまで例ということで!

2. Minimize Dependency Back to the Monolith(依存関係を最小限に抑えてモノリスに戻す)

マイクロサービスのメリットとして「リリースサイクルが独立していること」が挙げられる.しかし,マイクロサービスがモノリスに依存している場合は,モノリスのリリースサイクルに依存し,メリットが失われる可能性がある.例えば「チェックアウト機能」「購入機能」「プロモーション機能」があり,この順番で実行される場合に,1番依存が少ないと言える「プロモーション機能」からマイクロサービスに分割していくと書いてある(原著に載っている図を見るとわかりやすい).もしマイクロサービスからモノリスに依存をしてしまう場合は「腐敗防止層 (Anti-Corruption Layer)」経由でアクセスすれば,モノリスの内部実装を漏れ出さないようにできる.「腐敗防止層」に関しては以下の記事でも紹介されている.

martinfowler.com

3. Split Sticky Capabilities Early(厄介な機能を早めに分割する)

今度はモノリスの中で具体的なドメイン概念として確立されてなく,多くの機能に依存している機能を特定して分割していく.このような機能を早めに分割しないと将来的に苦労することになると書いてある.「オンライン小売アプリケーション」で言えば「セッション機能(ユーザー情報 / アクセス履歴 / ウィッシュリストなど)」が例として挙げられている.ポイントは,単純に「セッションサービス」として分割するのではなく,ドメインを意識して「プロファイルサービス」「ウィッシュリストサービス」などに段階的に分割していく.具体的なテクニックとしては Structure101 を使って,依存度を確認すると書いてあるため,Class 構造まで考慮して,ドメインを特定すると良さそう.

structure101.com

4. Decouple Vertically and Release the Data Early(垂直分割でデータを早めに分割する)

次に「データストア」に着目する.モノリス分割を進めたとしても「データストア」に依存してしまうと,本質的には独立しているとは言えず,マイクロサービスの原則も満たせなくなる.そこで「UI / Backend / Data」という水平分割ではなく「Service A (UI / Backend / Data)」「Service B (UI / Backend / Data)」のように垂直分割をしていく.

原著とは関係ないけど「データストア」を分割するときに「共有データ (Shared Data)」の取り扱いが難しいと思う.個人的に以下の「Managing Data in Microservices」というスライドが参考になり,今まで何度も読んでいる(YouTube もある).Synchronous LookupAsync event + local cache など.合わせて読んでもらえると良いかなと!

www.slideshare.net

5. Decouple What is Important to the Business and Changes Frequently(ビジネス的に重要で頻繁に変更される機能を分割する)

闇雲に着手するのではなく,モノリス分割をする「コスト」と得られるメリットと比較しながら継続的に評価していく.もしモノリス分割の目的が「既存機能への変更を加速させること」なら,頻繁に変更されている機能を特定する必要がある.Git リポジトリのコミットを確認したり,プロダクトマネージャーにヒアリングをして,今後頻繁に変更される可能性のある機能を特定することもできる.

「オンライン小売アプリケーション」で言えば「パーソナライゼーション機能」はユーザーに最高の体験を提供するために頻繁に変更が行われるため,例として挙げられている.具体的なテクニックとしては CodeScene を使って,ビジネスと技術を可視化すると書いてある.

codescene.com

6. Decouple Capability and not Code(コードではなく機能を分割する)

モノリス分割をするときに,戦略は大きく「コードを抽出する」「機能を書き換える」に分けられる.コードを抽出する場合,既存の実装をそのまま再利用することも多く,それは「IKEA 効果(自分で組み立てたから愛着が湧くこと)」によるバイアスが含まれていると書いてある.このようなバイアスがあると,モノリス分割の努力を妨げる可能性がある.そこで,機能を書き換えることにより,レガシープロセスや歴史的な仕様を見直すことができ,結果的にシンプルなコードになる.「IKEA 効果」という言葉は今まで知らなかった!

en.wikipedia.org

7. Go Macro First, then Micro(まずマクロ,次にマイクロ)

モノリス分割をするときに「境界」を特定することは「芸術 (art)」でもあり「科学 (science)」でもある.DDD (Domain-driven design) でよく知られた「境界付けられたコンテキスト (Bounded Context)」を見つけることに取り組むべきと書いてある.サービス全体(マクロ)を俯瞰しながら,徐々にサービス個々(マイクロ)に進んでいく.「オンライン小売アプリケーション」で言えば「カート機能」「チェックアウト機能」「購入サービス(カート機能とチェックアウト機能を含む)」として大きくサービス化して,段階的に「カートサービス」「チェックアウトサービス」に移行していくことができる.

martinfowler.com

8. Migrate in Atomic Evolutionary Steps(小さい進化的なステップで移行する)

モノリス分割は長期化するプロジェクトであり,マクロな条件に変化があると再計画が必要になり,資金不足になることもある.継続的にアプローチをするために小さく進化的なステップで移行するべきと書いてある.また「進化的アーキテクチャ」に載っている「適応度関数」を意識するべきという話も載っていた.正直「進化的アーキテクチャ」は1度読んだけど,うまく理解できずに挫折した.「8. Migrate in Atomic Evolutionary Steps」の内容は少し読みにくかった.

進化的アーキテクチャ ―絶え間ない変化を支える

進化的アーキテクチャ ―絶え間ない変化を支える

具体的な例としては「1. Warm Up with a Simple and Fairly Decoupled Capability」にも出てきた「エンドユーザー認証サービス」で,レガシーな認証機能から OAuth 2.0 に移行する例が挙げられている.OAuth 2.0 をデプロイした直後の並行期間はむしろ「機能への変更を加速させること」という目的からは離れてしまうけど,その後 OAuth 2.0 に完全に切り替えて,レガシーな認証機能の実装を削除するなど,小さく移行していく.原著では直接言及されていなかったけど「ストラングラーフィグアプリケーションパターン」も関連している.

martinfowler.com

まとめ

「モノリス分割」に役立つアプローチを紹介した martinfowler.com の記事「How to break a Monolith into Microservices」を読んだ.まだまだ抽象度が高い部分もあるけど,具体的な「計8種類」のアプローチが紹介されているのは参考になった.「モノリス分割」に興味があれば1度読んでみると良いのではないでしょうか!