アーキテクチャ●●●○○

モノリス

Monolith ・ ものりす

全機能をひとつのアプリとして作り、ひとつの単位でデプロイする構成。単純さが最大の武器。

✦ 30秒で試す — 航海一枚岩のまま、変更の波を1か所で止められるか試し直す範囲と、本番に出す範囲は?予想してみる

概要

モノリス(monolith、一枚岩)とは、ユーザー管理も商品検索も決済も通知も、システムの全機能をひとつのアプリケーションとして構築する構成です。コードベースはひとつ、ビルドの成果物もひとつ、デプロイの単位もひとつ。サーバ上ではひとつのプロセスとして動き、機能同士は同じメモリ空間の中で関数呼び出しによって連携します。

「アーキテクチャの一種」というより、素直にアプリケーションを作るとまずこうなる、という自然な形です。Ruby on Rails や Django、Laravel といった定番のWebフレームワークで作られたアプリケーションの多くはモノリスであり、世の中で動いているシステムの大半は今もこの形をしています。

この言葉が意識されるようになったのは、対になるマイクロサービスという考え方が広まってからです。分割された構成と比べる文脈で「分割されていない側」に名前が必要になった、という経緯を押さえると、この語彙の立ち位置が理解しやすくなります。

なぜ生まれたか

厳密には、モノリスは「生まれた」ものではなく、もともとの当たり前の姿です。問うべきは「なぜ当たり前だった形に、わざわざ名前が付いたのか」です。

2000年代、急成長した巨大サービスは、数百人規模の開発組織でひとつのコードベースを触ることの限界に直面しました。誰かの変更が全体のデプロイを止め、一部の機能のためにシステム全体をスケーリングしなければならない。Amazon は2000年代前半から機能ごとのサービスへの分割を進め、Netflix は2009年頃からクラウドへの移行とあわせて分割を進めました。こうした実践が2000年代後半から2010年代にかけてマイクロサービスとして語られるようになると、その比較対象として「モノリス」という呼び名が広まり、一時は「遅れた設計」の代名詞のように扱われました。

しかしその後、分散化の複雑さに苦しむ事例が積み重なり、「小さなチームにはモノリスのほうが合理的」という揺り戻しが起きます。現在では、モノリスは克服すべき過去ではなく、明確な利点を持つ選択肢のひとつとして再評価されています。問題はモノリスかどうかではなく、中身が整理されているかどうかだ、という理解に落ち着いてきたのです。

詳細

単純さがもたらす具体的な強さ

モノリスの利点は、開発のあらゆる工程が単純になることです。機能をまたぐ処理は関数呼び出しで書け、ネットワーク越しの通信のような「届かない・遅い」という失敗を考えなくて済みます。複数のテーブルにまたがる更新も、ひとつのデータベースのトランザクションで確実に整合させられます。デバッグではスタックトレースが処理の全体を教えてくれ、開発環境はアプリをひとつ起動すれば整い、テストも全体を通しで実行できます。デプロイはひとつの成果物を配置するだけです。この「認知しやすさ」は、人数の少ないチームでは決定的な生産性の差になります。

マイクロサービスと構成を並べると、この単純さの正体が見えます。モノリスではデプロイの単位もデータベースもひとつですが、分割した途端、機能間の連携はすべてネットワーク越しになります。

モノリス単一アプリ注文機能在庫機能通知機能機能間は関数呼び出しで連携単一DBマイクロサービスネットワーク越しのAPI注文サービス在庫サービス通知サービス注文DB在庫DB通知DB各サービスが自分のDBを所有するデプロイの単位はサービスごと
同じ機能群の二つの形 — モノリスは一体でDBもひとつ、マイクロサービスは小さなサービスの群れが各自のDBを持ちAPIで連携する

モノリスでもスケールはできる

「モノリスはスケールしない」というのは誤解です。同じアプリケーションを複数台に複製し、ロードバランサで分散すれば水平スケーリングは成立します。制約は粒度にあります。負荷が高いのが検索機能だけでも、アプリ全体を複製するしかなく、機能単位での増強はできません。とはいえ実際には、この粒度の粗さが問題になる規模のサービスは多くありません。データベースが先に詰まることのほうがよほど多く、それはサービスに分割しても消えない問題です。

本当の敵は「密結合」

モノリスが破綻するとき、原因はモノリスであること自体ではなく、内部の構造の崩壊です。機能間の境界が曖昧になり、ある機能が別の機能のテーブルを直接読み、内部の関数を直接呼び、呼び出しが輪になっていく。するとどこを触っても別のどこかが壊れます。Brian Foote と Joseph Yoder は1997年の論文で、この「構造らしい構造のない、つぎはぎの巨大なシステム」を泥団子(Big Ball of Mud)と名付けました。これはコードベースが単一かどうかとは別の問題で、結合度と凝集度の問題です。放置された泥団子は技術的負債の典型でもあります。

その対策として注目されているのが「モジュラーモノリス」です。内部を業務のまとまりごとのモジュールに分け、モジュール間の依存を明示的なAPI(公開インターフェース)に限定します。デプロイの単位はひとつのまま、コードの境界だけをサービス分割並みに厳格に保つ、という考え方です。境界を破る依存は、依存関係を検査するツールでCI/CDのパイプラインに組み込んで機械的に止めるのが実務の定石です。

泥団子会員注文在庫決済輪他人のテーブル・内部関数を直接触る1か所の変更が輪をたどって全体へ届くモジュラーモノリス会員注文在庫決済依存は相手の公開API(金の窓口)へ一方向だけ内部の変更はそのモジュールで止まる
泥団子とモジュラーモノリス — どちらもデプロイの単位はひとつ。違うのは依存の向きと細さ

どちらの形でもデプロイの単位はアプリ全体ですが、変更の波及範囲はまるで違います。下の部品で、モジュールを1つ押して「変更」し、その変更がどこまで届くかを確かめてください。泥団子からモジュラーモノリスに切り替えると、同じ変更が1つのモジュールの中で止まります。

⚡ 体験: 1か所の変更は、どこまで届くか
内部の構造
モノリス — デプロイの単位はこの外枠ひとつ会員注文決済商品在庫通知
変更したモジュール—再テストが要るモジュール—デプロイの単位アプリ全体

モジュールを1つ押して、その内部を変更してください。変更が依存の矢印を逆向きにたどって、どこまで届くかが光ります。

限界のサインと移行の定石

モノリスの限界が近いサインは、技術よりも組織に現れます。チームが増えてデプロイの調整が会議になる、リリース頻度が落ちる、ビルドとテストに時間がかかりすぎる——こうした痛みが出た段階で、痛んでいる境界からサービスを切り出すのが現代の定石です。Martin Fowler の「MonolithFirst(まずモノリスで作れ)」という指針が有名で、最初からマイクロサービスで始めると、まだ正しい境界が分からないうちに分割してしまい、後から境界を引き直す羽目になりがちだと指摘されています。業務の境界は、動くモノリスを運用して初めて見えてくるものだからです。境界を見つける物差しとしては、ドメイン駆動設計の「境界づけられたコンテキスト」がよく使われます。

切り出し方にも定石があります。一度にすべてを書き直すのではなく、モノリスの手前に振り分けの層(リバースプロキシや APIゲートウェイ)を置き、切り出した機能への要求だけを新しいサービスへ回していく。これを繰り返して古いモノリスを少しずつ細らせる方法は、Fowler が2004年に名付けたストラングラー・フィグ(絞め殺しの木)パターンとして知られています。いつでも元に戻せ、途中で止めても動くシステムが残るのが利点です。

実務での位置づけ

新規プロダクト、少人数のチーム、要件がまだ流動的なドメインでは、モノリスがほぼ常に正解です。逆に、数十チームが独立に動く必要のある大組織や、機能ごとに負荷特性・技術要件が極端に異なるシステムでは、分割の複雑さを支払う価値が出てきます。その中間には、モジュラーモノリスで境界を固めながら様子を見る、という現実的な道があります。「モノリスかマイクロサービスか」は技術の優劣ではなく、組織の規模と成熟度に対する適合の問題である——これがこの語彙を実務で使うときの核心です。

試問

1つのアプリ(モノリス)の中に、会員・注文・決済・商品・在庫・通知の6つのモジュールがあり、矢印は「どれがどれに依存しているか」です。モジュールを押すとその変更が依存をさかのぼって届き、再テストが要るモジュールが光ります。上のボタンで内部の構造(泥団子 / モジュラーモノリス)と、モジュラーモノリスでは変更の種類を選べます。

✦ 命題挑戦中

1つのアプリのまま、在庫の公開APIの形を変えても、再テストが要るモジュールを在庫を含めて2つ以内に収めよ

  • 在庫の公開APIの形を変える
  • 再テストが要るモジュールを2つ以内に収める(いま —)
⚡ 体験: 1か所の変更は、どこまで届くか
内部の構造
モノリス — デプロイの単位はこの外枠ひとつ会員注文決済商品在庫通知
変更したモジュール—再テストが要るモジュール—デプロイの単位アプリ全体

モジュールを1つ押して、その内部を変更してください。変更が依存の矢印を逆向きにたどって、どこまで届くかが光ります。