mybook

プロローグ — モノリスが悲鳴を上げた日

午前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

原因は単純だった。セールページへのアクセス集中が、商品検索クエリの爆発を引き起こし、それがデータベースの接続プールを枯渇させた。そしてデータベースが応答しなくなると、注文処理も、ユーザー認証も、在庫確認も、すべてが同時に止まった

Loading diagram...

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
end

1つの 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 を編集
→ 毎日コンフリクト地獄

ミサキの決断

「マイクロサービス化を提案します」

翌週の技術戦略会議で、ミサキは経営陣にプレゼンした。

Loading diagram...

「でも、マイクロサービスって難しいんじゃないの?」とCTOが聞いた。

「難しいです。でも、このまま続けることの方がもっと難しい」

ミサキの答えに、会議室が静まり返った。


この本で学ぶこと

本書は、ミサキと一緒にShopNovaのマイクロサービス移行を追体験する形で、以下を学ぶ。

  • マイクロサービスとは何か、なぜ必要か
  • サービス境界の正しい見つけ方(DDD)
  • Rails でのサービス間通信の実装
  • API ゲートウェイとBFFパターン
  • 分散データ管理の戦略
  • サーガパターンによる分散トランザクション
  • イベント駆動アーキテクチャ(SNS/SQS)
  • AWS ECS/Fargate でのコンテナデプロイ
  • 分散トレーシングによる可観測性
  • マイクロサービスのテスト戦略

INFO

マイクロサービスは万能薬ではない。この旅の終わりに、ミサキは「いつマイクロサービスを選び、いつ選ばないか」という重要な知恵も手に入れる。


ShopNovaのシステム全体像

移行前と移行後のアーキテクチャを最初に示しておこう。

移行前(モノリス):

Loading diagram...

移行後(マイクロサービス)の目標:

Loading diagram...

長い旅になる。でも、ミサキは一人じゃない。あなたも一緒に。

さあ、始めよう。