プロローグ — モノリスが悲鳴を上げた日
午前2時17分。ミサキのスマートフォンが激しく鳴り響いた。
PagerDutyのアラートだ。EC_SITE_DOWN — 本番環境が落ちている。
その夜、何が起きたか
ミサキが務める「ShopNova」は、去年まで月間GMV(商品取扱高)が10億円程度の中規模ECサイトだった。しかし今年のTVCM施策が大ヒットし、わずか3ヶ月でGMVは100億円に跳ね上がった。ユーザー数は10倍。アクセス数は20倍。
そしてその夜、セールイベントのピーク時間に、すべてが止まった。
# PagerDuty アラートログ
[02:17:13] CRITICAL: Response time > 30000ms
[02:17:15] CRITICAL: Error rate > 50%
[02:17:18] CRITICAL: DB connection pool exhausted
[02:17:20] CRITICAL: Site DOWN - HTTP 503原因は単純だった。セールページへのアクセス集中が、商品検索クエリの爆発を引き起こし、それがデータベースの接続プールを枯渇させた。そしてデータベースが応答しなくなると、注文処理も、ユーザー認証も、在庫確認も、すべてが同時に止まった。
WARNING
モノリスの最大の弱点:ある機能の障害が、無関係な全機能を巻き込んで停止させる「カスケード障害」が発生しやすい。
ShopNovaのRailsモノリス
ShopNovaのコードベースは5年かけて育てられた Rails アプリだった。最初は美しい構造をしていたが、今や...
# app/controllers/orders_controller.rb(肥大化した例)
class OrdersController < ApplicationController
def create
# 在庫確認
product = Product.find(params[:product_id])
return render json: { error: '在庫なし' }, status: 422 if product.stock < params[:quantity]
# 注文作成
order = Order.create!(
user: current_user,
product: product,
quantity: params[:quantity],
total_price: product.price * params[:quantity]
)
# 在庫減算
product.decrement!(:stock, params[:quantity])
# ポイント付与
current_user.add_points(order.total_price / 100)
# メール送信(同期)
OrderMailer.confirmation(order).deliver_now
# 推薦エンジン更新(同期)
RecommendationEngine.update_purchase_history(current_user, product)
# 検索インデックス更新(同期)
SearchIndexer.update_product(product)
# 分析イベント送信(同期)
AnalyticsService.track('order_created', order)
render json: order, status: :created
end
end1つの create アクションに、在庫管理・注文処理・ポイント管理・メール・推薦・検索・分析が詰め込まれている。これが「モノリス」の現実だ。
5年間で積み重なった問題
翌朝、ミサキはチームを集めて現状を分析した。
問題1: デプロイの恐怖
# デプロイのたびに全機能が止まる
$ git log --oneline | head -5
a3f9c2 Fix typo in product description
b8e1a4 Add recommendation algorithm v3
c2d7f1 Update payment gateway
d9k3m8 Fix user auth bug
e4p2x9 Optimize search query
# 本来なら「商品説明のタイポ修正」だけデプロイしたいのに
# 推薦エンジンのコードも、決済コードも、認証コードも一緒にデプロイされる問題2: 技術的負債の蓄積
# app/models/product.rb — 神モデル(God Object)
class Product < ApplicationRecord
# 500行以上のコード...
has_many :order_items
has_many :reviews
has_many :category_mappings
has_many :search_keywords
has_many :recommendation_signals
has_many :inventory_histories
has_many :price_histories
has_many :promotion_products
# ...まだまだ続く
end問題3: スケールできない
商品検索だけスケールしたくても、モノリス全体をスケールアウトするしかない。
# 本当は検索だけスケールしたい
# しかしモノリスは分割できない
# 現状: アプリサーバーを10台に増やす
# → 注文処理も、認証も、すべてが10台分になる
# → コスト10倍、でも効果は限定的問題4: チームの摩擦
チームが3つのスクワッドに分かれているのに、コードは1つのリポジトリ。
Squad A(商品・検索): product.rb を編集
Squad B(注文・決済): product.rb を編集
Squad C(ユーザー・ポイント): product.rb を編集
→ 毎日コンフリクト地獄
ミサキの決断
「マイクロサービス化を提案します」
翌週の技術戦略会議で、ミサキは経営陣にプレゼンした。
「でも、マイクロサービスって難しいんじゃないの?」とCTOが聞いた。
「難しいです。でも、このまま続けることの方がもっと難しい」
ミサキの答えに、会議室が静まり返った。
この本で学ぶこと
本書は、ミサキと一緒にShopNovaのマイクロサービス移行を追体験する形で、以下を学ぶ。
- マイクロサービスとは何か、なぜ必要か
- サービス境界の正しい見つけ方(DDD)
- Rails でのサービス間通信の実装
- API ゲートウェイとBFFパターン
- 分散データ管理の戦略
- サーガパターンによる分散トランザクション
- イベント駆動アーキテクチャ(SNS/SQS)
- AWS ECS/Fargate でのコンテナデプロイ
- 分散トレーシングによる可観測性
- マイクロサービスのテスト戦略
INFO
マイクロサービスは万能薬ではない。この旅の終わりに、ミサキは「いつマイクロサービスを選び、いつ選ばないか」という重要な知恵も手に入れる。
ShopNovaのシステム全体像
移行前と移行後のアーキテクチャを最初に示しておこう。
移行前(モノリス):
移行後(マイクロサービス)の目標:
長い旅になる。でも、ミサキは一人じゃない。あなたも一緒に。
さあ、始めよう。