MSA(マイクロサービス)とモノリスの違いを今さら整理する
まとめ
- MSA = アプリを小さな独立サービス群に分割する設計、対義語はモノリス(1 つの大きなアプリ)
- 各サービスは独立デプロイ・独立 DB・言語選択自由
- 障害局所化・チーム分割しやすさが利点、運用の複雑化が欠点
- 「Rails は MSA に向かない」と言われるのは、1 アプリで全部やる前提で作られているから
モノリスとは
普段の Web アプリ開発で一番多いやつ。1 つのアプリの中にユーザー機能・決済・通知・管理画面を全部詰めて作る。Rails や Django で素直に作ると、まずこの形になる。
[モノリス]
┌─────────────────────────────────┐
│ 1 つのアプリ │
│ ├ ユーザー機能 │
│ ├ 決済機能 │
│ ├ 通知機能 │
│ └ 管理機能 │
│ → 1 つの DB / 1 つのデプロイ │
└─────────────────────────────────┘これの何が嬉しいかというと、とにかく作るのが速い。ローカル起動も 1 コマンド、デバッグも 1 プロセスで完結する。機能をまたいで関数呼び出しでつなげられるから、トランザクションも素直に張れる。少人数で立ち上げる初期フェーズには圧倒的に向いてる。
MSA とは
これを機能ごとに別アプリへ切り出すのが MSA。
[MSA]
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ User │ │ Payment│ │Notify │ │ Admin │
│ Service│ │ Service│ │ Service│ │ Service│
│ + DB │ │ + DB │ │ + DB │ │ + DB │
└────────┘ └────────┘ └────────┘ └────────┘
↕ ↕ ↕ ↕
HTTP / gRPC / メッセージキューで通信各サービスは独立して動く別アプリ。HTTP や gRPC、メッセージキュー越しに会話する。
MSA の良いところ
- 独立デプロイできる。User Service だけ直して出す、ができる
- 言語・DB を選べる。User は Go、Payment は Java、みたいな構成も理屈上は組める
- 障害が局所化しやすい。Notify が落ちても User の画面は生きてる
- チーム分割が綺麗にいく。1 チーム 1 サービスにすればコンフリクトが減る
痛いところ
- 通信が全部ネットワーク越し。遅いし失敗もする。リトライ・タイムアウト・サーキットブレーカーが必須になる
- トランザクションが分散する。サービスをまたいだ「失敗したら全部戻す」が普通にはできず、Saga パターン等の補償処理が必要
- 認証・認可・ログ・トレースを横断で設計しないといけない
- ローカル開発が重い。10 サービス同時起動みたいになる
- 少人数だとオーバーキル。3 人で 10 サービスは持てない
Rails が MSA に向かないと言われる理由
Rails は「1 アプリで全部やる」設計。autoload で全クラスを起動時にロードし、Active* 系(ActiveRecord / ActiveJob / ActionMailer 等)が同じプロセスに乗る前提で噛み合っている。Rack ミドルウェアスタックや initializer 群もアプリ起動コストとして固定で乗る。
小さなサービスを 10 個 20 個並べる世界だと、1 サービスあたり数百 MB のメモリと起動数秒というオーバーヘッドが効いてくる。サービスの粒度が細かいほど割に合わなくなる。
ただし「MSA で Rails を使ってはいけない」わけではない。1 サービスが業務ドメイン単位(数十 endpoint 規模)なら Rails でも十分回るし、Shopify や GitHub のように Rails の Majestic Monolith を巨大スケールで運用する事例もある。本当に細粒度(数 endpoint × 大量)の世界に行くなら、Sinatra / Roda / Hanami や Go の方が素直、というだけの話。
どう選ぶか
- まずモノリスで作る。困ってから割る。最初から MSA を狙うと大体こける
- 困りごとの形が見えてから割る。「デプロイの調整コストが重い」「特定機能だけスケール条件が違う」「チームの境界が明確」みたいな具体の痛みが出てから動く
- 割る順は外側から。決済や通知のように、外部システム連携が明確で疎結合にしやすい場所から切り出す
個人的には、MSA は「使えるカード」として持っておくくらいで、最初から振りかぶる必要はないと思ってる。モノリスで困った時に、必要な部分だけ切り出すくらいで十分間に合う。