1章: 必要十分なマイクロサービス
マイクロサービスの特徴
- 独立デプロイ可能性
- ビジネスドメインに基づくモデル化
- データのカプセル化
マイクロサービスのメリット
- 各サービスを並行して開発することによる効率化
- 各サービスごとに最適な技術スタックを用いることができる
しかしこうしたメリットは簡単に手に入るものではなく、目的に応じて適切なモノリスの分割戦略を取る必要がある
マイクロサービスのデメリット
- サービス間通信のレイテンシー、ネットワーク障害
- データの不整合の発生
- ログ追跡の複雑化
こうした問題はいずれも完全な解決が難しい
そのためモノリスで開発運用していて何も問題がないのであれば安易にマイクロサービスに手を出すとかえって開発効率を悪化させることとなる
著者はマイクロサービスの普及に努めているが、決してマイクロサービスはモノリスに勝るといった考えではない
マイクロサービスがもてはやされて久しいが、マイクロサービスは確実にシステムの全体設計を複雑化させるということを忘れてはならない
例えば、モノリスにおいてはトランザクションを張るだけで解決できる問題も、マイクロサービスにおいてはサービス間のデータ整合性を担保できる仕組みが必要になる
モノリスは本当に悪か?
モジュラーモノリスのように、単一のDBを使用しているが、コードが十分にモジュール化されていれば並行した開発が可能になる
少なくとも先に挙げたような厄介な問題は回避できる
ただし、コードレベルでは分解されているが、DBレベルでの分解は行われていないため、将来DBを分解したくなった場合に困難を伴う
(どの道モノリスのDBを分解するのは困難だが)
事業規模、サービス規模によってはモジュラーモノリスが最適解となることは大いにあり得るし、Shopifyのような有名企業での運用事例もある
以上のように、モノリスだから劣った設計とは言えないが、分散モノリスにだけは陥らないように留意する必要がある
分散モノリスとは複数のサービスから成り立っているが、何らかの理由でシステム全体が一緒にデプロイされなければならないアーキテクチャだ
情報隠蔽やビジネス機能の凝集が十分に行われておらず、サービスを跨いで変更が波及しサービス間が密結合しており、当然ながら独立デプロイなど行える状態ではない
こうなってしまうとマイクロサービスとモノリス双方の欠点を持ち、そしてどちらの利点も十分に持つことになる
2章: 移行を計画する
マイクロサービスの目的
マイクロサービスを導入するにあたっての3つの重要な質問
- 達成したいことは何か?
- マイクロサービスの他に代替案はなかったか?
- どうすれば移行がうまくいってるか分かるだろうか?
マイクロサービスを選択する理由として以下が挙げられている
- チームの自立性向上
- 迅速なリリース
- スケーリング
- 堅牢性
- 開発作業の競合回避
- 新しい技術の導入
重要なのはこれらの事項が他の手段でも達成できないか検討を重ねることである
もっと簡易な代替案が見つかることもあるだろう
また、ドメイン領域が曖昧だったり、スタートアップのようなプロダクトに変更が頻繁に入るような場合はそもそもマイクロサービスを運用するのに向かないだろう
段階的移行
マイクロサービスへの移行はモノリスを少しずつ解体し、段階的に移行することが強く勧められている
たしかに移行作業が一発で上手くいくことはそうそうないだろう
往々にして本番環境にデプロイした後にログ追跡、レイテンシー、参照整合性等の問題に気づくものだ
人間は失敗するものであり、その失敗の大きさを減らす方法が必要である
段階的に移行していけば修正コストが安く済み、本番稼働のフィードバックもずっと得やすくなる
どこから始めればよいか?
システムには切り出しやすい機能と切り出しにくい機能がある
それを判別するためにドメインの依存関係をモデル化し、依存関係が少ないドメインから切り出していくのが効果的だろう
3章: モノリスを分割する
モノリスを変更すべきかどうか
多くの場合はモノリスのコードはビジネスドメインに基づいて整理されておらず、マイクロサービスへ切り出す際はリファクタリングが必要になる
それが済めば、マイクロサービスへの移行に着手する前に、先に挙げたモジュラーモノリスで問題が解決できないか検討してみるとよい
著者によれば、モジュラーモノリスで問題のほとんどを解決できたという話を複数のチームから聞いたことがあるようだ
移行パターン
移行パターンにはいくつか存在し、以下のような代表的なパターンが存在する
- ストラングラーアプリケーション
- UI合成
- 抽象化によるブランチ
- 同時実行
- デコレーティングコラボレーター
- 変更データキャプチャ
各詳細は割愛するが、一般的にはストラングラーアプリケーションもしくは同時実行、あるいは両方を組み合わせることが多いように思う
ストラングラーアプリケーションのメリットは、モノリスに既存機能をそのまま残しておくことでマイクロサービスのデプロイ後すぐに変更が反映されることがなくなり、なおかつ問題があればロールバックが容易に行えることである
同時実行パターンも使用すれば切り出した機能が意図通りに動いているか確かめることができる
複数の作業者間で変更箇所がコンフリクトする場合は抽象化によるブランチが有効だろう
変更データキャプチャはDBと強く依存するためあまり使いたくない
4章: データベースを分割する
マイクロサービスへの移行に際して最も大きな課題はDBの分割だろう
本書の最も大きなテーマとも言える
共有データベースの課題
-
情報隠蔽ができず、スキーマのどの部分を安全に変更できるか理解しにくくなる
→ スキーマの変更が起こらないならば問題ないのか? -
どのサービスがデータを管理するのか不明瞭になる
どちらかと言うとこちらの方が問題になりやすく思う
複数のサービスが同じテーブルにINSERT、UPDATE、DELETEを行う場合、そのロジックが点在することでデータの不整合のリスクが高まる
マイクロサービスにおいて共有DBが適しているのは読み取り専用の静的な参照テーブルや、そもそも複数のサービスから参照されるのが前提で設計され直接公開している場合だけと述べられているが、実際問題DBを分割するのは大いに困難が伴うだろう
そういった場合の対処パターンとして以下のようなものが挙げられている
- データベースビュー
- データベースをラップするサービス
- サービスのインターフェイスとしてのデータベース
いずれのパターンも情報隠蔽、データの所有権の明瞭化が期待できるパターンだが、ビュー、インターフェースとしてのデータベースは特定のDBに依存することになり、柔軟性にも欠ける
その点、データベースをラップするサービスは、背後のDBを隠すことができ、アプリケーションのコードによってより柔軟にデータを用意できる点で優位にあるかと思われる
DBの分割とコードの分割はどちらを先にすべきか?
結局は状況によるとしか言えないが、大抵の場合はコードを先に分割する方が上手くいくように思われる
ストラングラーパターンや同時実行のようなパターンを利用すればコードの分割の難易度も軽減されるだろう
その後、DBを分割し、トレーサー書き込みパターンを使ってデータを移行するのがよいだろう
トランザクション
マイクロサービスにおける大きな問題であるトランザクションについては2フェーズコミットとサーガが対応策として挙げられている
2フェーズコミットはシステムをさらに複雑化させる恐れがあるため、ごく短いトランザクションの場合を除いて、基本的にはサーガの利用が推奨されている
2フェーズコミットの場合、単一ノードの障害でトランザクションのコミットが停止してしまい可用性が低下するからだ
ノードが追加されればされるほど単一障害点が増えてしまうことになる
各ノードを冗長化すれば問題が回避できるかもしれないが、2フェーズコミットの設定がさらに複雑化するため、やはりサーガの利用を検討すべきに思う
5章: 成長の痛み
マイクロサービスを採用すると複数の要因が絡み合った様々な問題に直面することになる
とりわけ初期には破壊的変更、レポーティングといった問題が起こりやすい
破壊的変更に対してはサービス間のインターフェースを壊さない仕組みの導入、レポーティングに対しては専用のDBやサービスを設けることで初期から対応していくべきだ
成長段階を問わず、ロギング、堅牢性と回復性といった問題も発生する
ロギングに対してはマイクロサービス向けのログ集約サービスの利用、堅牢性と回復性に対してはk8sやクラウドのコンテナマネジメントサービスの利用が有効だろう
まとめ
本書においてマイクロサービスへの移行戦略を学ぶことができた
具体的なコードとDBの分割パターンや、移行後に発生する問題とその対応策が紹介されており有益な書籍であった
弊社においてはマイクロサービス化の主な動機は複数のサービス間で重複した処理の共通化であるが、今思うとそもそもDBが複数のサービス間で共有されていることがそもそもの問題であると言える
情報が隠蔽できておらずデータの所有権が曖昧であるため、複数のサービスからCRUD処理が行われロジックが点在する結果となっている
DBの分割の労力は非常に大きいため、本書でも書かれているようにモジュラーモノリスが最適解となるかもしれない
ただ、すでにマイクロサービス化されたコンテナを複数デプロイしているが、それらは切り出し元のモノリスと一緒にデプロイしており、マイクロサービスのメリットである独立したデプロイは不可能な状態となっている
これは本書でアンチパターンとして紹介されている分散モノリスに近い状態である
しかしながら、DBを分割しておらず、コードもある程度モジュール化されているため、モジュラーモノリスにも近い状態となっている
次にデプロイするマイクロサービスについては独立デプロイできるように設計し、段階的にあるべきマイクロサービスの形に近づけていこうと思う