「モノリスからマイクロサービスへ」を読んだ
近頃モノリスをなんとかするための書物を読み漁っていて、今回は「モノリスからマイクロサービスへ」を読んでみた。
どんな本か
2020年12月26日発行。オライリー・ジャパン。著者は、2016年に発行された「マイクロサービスアーキテクチャ」と同じSam Newman氏。既存システムにマイクロサービスアーキテクチャを適用するにあたり、モノリシックなアプリケーションをいかにマイクロサービス化していくかを記した実践ガイド。
所感
モノリスを分解するゴールを目指す人にはこの上なく有益な書籍ではないかと思う。言語や開発環境に依存しておらず、かといって抽象論を述べるだけでもない、抽象と具体のバランスが絶妙な解説で多くの開発現場に刺さりそう。
マイクロサービスをいたずらに推奨する書籍ではないのも良かった。本書はむしろ「落ち着け、本当にマイクロサービスに移行していいのか?」「モノリスにも多くの利点があるが理解しているか?」と繰り返し問いかけてくる。
大きく育ってしまったモノリスをどうしていくかの問いについて、本書は答えを教えてはくれないが、おおよそ具体的な選択肢をいくつか提示してくれた。我々読者はそれぞれのシステムに合った選択肢を自ら選んでいく必要がある。今後モノリス解体に関わるのであれば、同じ目的を共有する人と本書を輪読したいと思った。
あと、実は「マイクロサービスアーキテクチャ」を読んだことがないので、年始休暇が明けたら会社の本棚から拝借する。
要点
いつもの通り自分用の要点を雑にメモしておく。本書を読んでいない人に要点を伝えよう、と思って書いてはいないことを断っておく。
独立デプロイ可能性
あるマイクロサービスの変更は、他のマイクロサービスに影響させずに本番デプロイできる。これを独立デプロイ可能性という。本書2ページ目で一番大事らしい事が書かれていた。
本書から得られるものが1つだけだとしたら、それは「マイクロサービスに独立デプロイ可能性の概念を確実に取り入れよう」ということだ。
独立デプロイ可能性を実現するには、サービス同士が疎結合でなくてはならない。データベースをサービス間で共有することは特に問題に発展しやすい。
マイクロサービスは技術に依存しない
マイクロサービスといえばKubenetesが必須、ではない。
- k8sやDocker、クラウドサービスは必須ではない
- 言語もなんでも良い
- ネットワークを介してサービスが相互に通信できれば良い
- 新しい技術スタックを無理に採用しなくて良い
結合と凝集
結合とは、あるものに対する変更がどれくらい別のものの変更を必要とするか。
凝集とは、関連するコードをどのようにグループ化するか。関係してるものは1カ所にまとまっててくれ的な話。
構造は、凝集度が高く、結合度が低い場合に安定する
マイクロサービス導入に関する3つの問い
目的を明確にし、他の選択肢が無いかを検討し、評価軸を設ける。
- 達成したいことはなにか?
- マイクロサービス以外の案はないか?
- どうすれば移行がうまくいってると判断できるか
マイクロサービスの利点
- チームの自律性が高まる
- 価値の市場投入までの時間が減る
- スケーリングの費用対効果向上
- 堅牢性の改善
- 開発者の人数を増やせる
- 新技術を取り入れやすくなる
マイクロサービスが向かない場合
- ビジネスドメインが不明瞭
- スタートアップのサービス立ち上げ時
- なんとなくマイクロサービスにしたい時
モノリス分割のパターン
ストラングラーパターン
最有力がストラングラーパターン。HTTPでリクエストが飛んでくるなら最も対応しやすい。メリットは、うまくいかない時のロールバックが容易である点。
- 移行対象の特定
- 対象機能の移行
- 機能呼び出しを移行先へリダイレクトする
リダイレクトにはリバースプロキシを挟む方法が有効。
抽象化によるブランチパターン
HTTPではなくモノリス内部からメソッド呼び出し等で呼び出されている機能はリダイレクトが使えない。代わりに、置き換え対象機能の抽象部品(インタフェース、抽象クラス的なもの)を作り、実装を差し替えることで切り替えを図る。
その他
- 同時実行パターン
- 両方の実装を呼び出して結果を比較する
- 新旧を確率で振り分けるのではなく両方呼ぶ
- デコレーティングコラボレーター
- 賢いプロキシ的なやつ
データベース分割
部屋にいる象をなんとかする。(←と書かれててクスッとした)
モノリスをマイクロサービス化するにあたって一番の壁になりやすい。本書の肝はここ。
共有データベースパターン
モノリスなデータベース
- スキーマのどの部分を安全に変更できるかがわからない
- 誰がこのデータを管理してるか不明瞭。ビジネスロジックの凝集度が欠如
- 通貨コードや郵便番号などの参照目的ならOK
データベースビューパターン
外部システムにはビューを見せる。テーブルそのものは見せない。ビューの所有者が誰かを明確にしておく。
データベースのラップサービス
データベースにアクセスするサービスを作り、インタフェースのみを公開する。データが欲しい他サービスは、クエリを発行するのではなくこのサービスのAPIを使う。
データベースへの依存関係をサービスへの依存関係に移動する。
データ同期
分割したデータベースの同期をどのように行うか。だいたい2択。
- アプリケーションでのデータ同期
- トレーサ書き込み
DBとコードをどちらから分割するか
3択。
- DB -> コード
- いきなりスキーマを分けるのではなく、DBアクセスコードをRepositoyの層で分ける
- コード -> DB
- だいたいこれ
- コード分けた段階で行き倒れるリスクがある
- 一緒にやる
- 当たり前だけど非推奨
データベース分割の注意点
- ある列が複数のドメインから更新される場合は注意
- データ所有権を考える必要がある
- 所有者のサービスに更新を任せる
- JOINがサービス呼び出しに置き換わる
- 自由にJOINできなくなる
- 当然クエリ発行回数は増える
- データの整合性の維持
- 参照制約が使えない場合が出る
- 論理削除や削除前チェック機能の選択肢があるが複雑
- トランザクション管理
- 分割してもACIDを維持はできるが、自前実装が必要(特に原子性)
- 2フェーズコミットという選択肢もある、が複雑で非推奨
- そもそもトランザクションの単位であれば分割しないほうが良い
- サーガいいよ
サーガ
原子性を維持するための方式としてサーガがある。
複数サービスを跨ぐ一連の処理において、後方回復、前方回復の手段を自前で実装する。
- 後方回復
- 単純なロールバックではなく巻き戻しの処理を実装する
- 商品登録であれば削除し、受注していれば取り消し処理など
- 処理の順番を見直すことで後方回復をシンプルにする
- 前方回復
- トランザクションを停止位置から再実行させる
- 中断時の情報を記録しておける仕組みにする
サーガの実装方法2種類
- オーケストレーションベース
- Facadeパターンみたいなもの
- オーケストレータが複数サービスを呼び出し
- ロジックがわかりやすい
- オーケストレータに業務ロジックが集中しがち
- コレオグラフィベース
- イベント駆動型
- 各サービスは自処理のトリガになるイベント発生だけを気にする
- 何が起きてるかわかりにくくなる
マイクロサービスの成長痛
コード所有権のスケール
コードの所有権は組織状況に応じてスケールしていく。
- 強い所有権
- 全サービスに所有者(グループ)が決まっている
- 所有者以外はPull Requestなどで申請し採択されないと変更できない
- 弱い所有権
- 所有者は決まっているが、所有者に相談した上で誰でもコードを変更できる
- 共同所有
- 所有者を決めておらず、誰でもコードを変更できる
複数のチームでマイクロサービスを維持している組織の多くは強い所有権を採用している。
契約の破壊的変更
サービス間のAPIは契約。内部向けでも契約。勝手に変えると事故の元。
複数チームでマイクロサービスを扱うと高頻度で破壊的変更が起きる。
APIの変更前によく考えること。
ログ収集と監視
ログ収集と監視はマイクロサービス導入よりも前に手を付けた方が良い。特にログ収集はメリットが大きい。
正直一度読んだだけですべてが頭に入るほど簡単な本ではなかった。「へー、こういうパターンがあるのね」というインデックス構築にはなったので、今後業務を進めていく上で再度読み返すことになりそう。