仕組みから学ぶ Web
発展読了目安 16#マイクロサービス#モノリス#分散システム#境界#コンウェイの法則

モノリスとマイクロサービス — 分けた境界の数だけ、失敗の仕方が増える

速く開発するために8つのサービスに分けたら、項目を1つ足すのに4つのサービスを順番にデプロイするようになった。分けることで得られるのは独立性で、境界を間違えると独立性は得られず、費用だけが残る。

この記事の進み方

What — 分けると、何が変わるか

モノリスは、1つのプロセスとして動き、1回でデプロイするアプリケーションです。マイクロサービスは、機能ごとに別々のプロセスとして動き、別々にデプロイするアプリケーションの集まりです。

分けたとき、コードの中で起きていたことが、ネットワークの上で起きるようになります。

Figure注文を確定して、ポイントを付与する
画面用の中継注文サービス注文の DBポイントサービスポイントの DBPOST /orders注文を保存して COMMITPOST /points(付与)ポイントを保存(遅延中)タイムアウト。付与されたか分からない200 注文完了
1/6
POST /orders利用者が注文ボタンを押した。ここまでは、モノリスでも同じ。

モノリスでは関数の呼び出しと1つのトランザクションだった処理が、ネットワーク越しの呼び出しになる。呼び出しが失敗したとき、どちらが成功したかをまとめて戻す手段が無い。

モノリス
1つのプロセスとして動き、1回でデプロイするアプリケーション。
マイクロサービス
機能ごとに別々に動き、別々にデプロイできる、小さなサービスの集まり。
モジュラーモノリス
1回でデプロイするが、内部をモジュールに分け、モジュール間の依存を強制的に制限したモノリス。
分散モノリス
サービスに分かれているのに、一緒に変更・一緒にデプロイしないと動かない状態。両方の短所を持つ。

分けると得られるもの、払うもの

Compare分け方と、その費用

1つにまとまっているので、変更もトランザクションも1回

1つのリポジトリ・1つのプロセス・1つの DB
機能をまたぐ変更
1回のデプロイ
整合性
1つのトランザクションで守れる
独立したデプロイ
**できない。全員が待ち合わせる**
境界の強さ
**気を付けないと崩れる**
部分的な拡張
運用
得られたもの
  • チームが小さいうちは、最も速い形であることが多い
  • 内部の依存を制限しないと、どこからでも何でも呼べるようになり、変更が全体に波及する
  • 一部だけ負荷が高くても、全体をまとめて増やすしかない

マイクロサービスは、独立して変更・デプロイ・拡張できることを買う代わりに、ネットワークの失敗、分散したデータ、運用の手間を払う。境界を間違えると、払うものだけが残る。

確認 — ここまで読めたか

モノリスでは、注文の保存とポイントの付与を1つのトランザクションで行っていました。サービスに分けて、注文サービスがポイントサービスを HTTP で呼ぶ形にしました。新しく起きうることはどれですか?

まず選ぶ(解答例は a〜d の記号で説明します)

Why — なぜ分けても速くならなかったのか

マイクロサービスで得たいのは、独立して変更し、独立してデプロイできることでした。独立して変えられるのは、変更がそのサービスの中で閉じるときだけです。

冒頭のチームは、境界をデータの名詞(会員、商品、注文、ポイント)で引きました。ところが、機能の追加は名詞に沿って起きません。「注文履歴に獲得ポイントを出す」は、注文とポイントと画面をまたぐ変更です。変更の単位と、サービスの単位がずれていたので、1つの変更が4つのサービスに分かれました。

分ける前:  1つの変更 → 1つのコード → 1回のデプロイ
分けた後:  1つの変更 → 4つのサービス → 4回のデプロイを順番に

分けたことで、待ち合わせは無くならず、形を変えただけでした。同じコードの中での待ち合わせが、サービス間のデプロイの順番待ちになり、さらにネットワークの失敗が加わりました。

組織の形が、境界の形になる

ソフトウェアの構造は、それを作る組織のコミュニケーションの構造に似ると言われます(コンウェイの法則)。

マイクロサービスが本当に速さを生むのは、サービスごとに別のチームがいて、チームどうしの調整を減らしたいときです。チームが独立して決め、独立してデプロイできることが価値になります。

6人の1チームでは、調整のコストはもともと小さく、サービスを分けても減りません。減らすべき調整が無いところに境界を作ると、境界を越える手間だけが増えます

データを共有すると、分けたことにならない

サービスを分けても、同じ DB の同じテーブルを複数のサービスが読み書きしていると、テーブルの形を変えるたびに全サービスを同時に直す必要があります。見た目は分かれていても、テーブルの形という契約で、全サービスが結合したままです。

独立して変えるには、各サービスが自分のデータを持ち、他のサービスには API やイベントを通してだけ見せる必要があります。これは、データの重複と、サービスをまたぐ整合性という新しい問題を引き受けることでもあります。

確認 — ここまで読めたか

8つのサービスに分けましたが、全サービスが1つの DB の同じテーブルを直接読み書きしています。この状態で、会員テーブルの列名を変えるとどうなりますか?

まず選ぶ(解答例は a〜d の記号で説明します)

演習 — まず自分で判断する

解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。

演習 — 設計判断を問う

このチームの開発を速くするために、構成をどう変えますか?

与えられた条件
  • 8人の1チームが、1つのモノリスの EC サイトを開発している
  • テストに40分かかり、デプロイの待ち合わせが1日に何度も起きる
  • コードのどこからでも、どのテーブルでも触れる状態になっている
  • 画像の変換処理だけは負荷の性質が違い、セールのときにサイト全体を遅くする
  • 来年、チームを2つに分ける予定がある
この軸で考える
  • · いまの遅さの原因は、プロセスが1つであることか、境界が無いことか
  • · どの境界なら、変更の単位と一致していると言えるか
  • · 分けるなら、何を根拠に、どこから分けるか
まず選ぶ(解答例は a〜d の記号で説明します)

演習 — 説明できるか

「マイクロサービスに分けたのに、なぜ開発が遅くなったのか」と聞く CTO に、説明してください

与えられた条件
  • 分割を承認したのは CTO で、半年の工数をかけた
  • 相手はシステムの構成には詳しいが、日々の変更の中身は見ていない
  • 元に戻すかどうかではなく、次にどうするかを決めたい

読み終わりましたか?

読了にすると、これを前提とする記事がロードマップで開放されます。