サイトアイコンmaita tomoya dev io

スケーリングを見据えた技術選定: モノリスからマイクロサービスへの段階的移行

growth-patterns

スケーリングを見据えた技術選定: モノリスからマイクロサービスへの段階的移行

はじめに

プロダクトの成長に伴い、システムのスケーリングは避けて通れない課題です。しかし、最初からマイクロサービスで設計すべきでもなく、モノリスで限界を迎えてから慌てるのも問題です。本記事では、段階的なスケーリング戦略と、各段階での技術選定の判断基準を解説します。

身近な例えで理解するスケーリング

スケーリングは「お店の拡大」に似ています。

  • フェーズ1(個人経営) = モノリス。1人で全部やる。効率は良いが、キャパシティに限界がある
  • フェーズ2(従業員を雇う) = 垂直スケーリング。より大きなサーバーを使う
  • フェーズ3(支店を出す) = 水平スケーリング。同じ構成のサーバーを増やす
  • フェーズ4(専門店に分割) = マイクロサービス化。機能ごとに独立したサービスに分割
  • フェーズ5(フランチャイズ展開) = グローバル分散。世界中にサービスを展開

スケーリングの段階

段階一覧

段階ユーザー規模アーキテクチャ主な課題
Stage 00-100シンプルモノリス開発速度を最大化
Stage 1100-10,000モノリス + キャッシュDB負荷の軽減
Stage 210,000-100,000モノリス + Read Replica + CDN読み取り性能の向上
Stage 3100,000-1,000,000モジュラーモノリス / サービス分離開始開発チームの拡大
Stage 41,000,000-10,000,000マイクロサービスシステム全体の複雑性管理
Stage 510,000,000+グローバル分散マイクロサービスグローバル展開、データ整合性

Stage 0: シンプルモノリス(0-100ユーザー)

アーキテクチャ

[ユーザー]
    |
    v
[Next.js / Rails / Django]
    |
    v
[PostgreSQL]
    |
    v
[S3 (ファイル保存)]

技術選定のポイント

項目推奨理由
フレームワークNext.js, Rails, Djangoフルスタックで開発が速い
データベースPostgreSQL万能で将来のスケーリングにも対応
ホスティングVercel, Heroku, Railwayゼロ設定デプロイ
ストレージS3互換 (Supabase Storage等)スケーラブル

この段階でやるべきこと

  • コア機能の開発に集中する
  • ユーザーフィードバックを集める
  • パフォーマンスモニタリングの基盤を作る(Sentry、PostHog等)

この段階でやるべきでないこと

  • マイクロサービス化
  • 複数DBの導入
  • Kubernetes
  • カスタムインフラの構築

Stage 1: モノリス + キャッシュ(100-10,000ユーザー)

アーキテクチャ

[ユーザー]
    |
    v
[Next.js / Rails / Django]
    |
    +-- [Redis (キャッシュ)]
    |   |-- セッション管理
    |   |-- 頻繁にアクセスされるデータのキャッシュ
    |   +-- レートリミット
    |
    v
[PostgreSQL]
    |
    v
[S3 + CloudFront (CDN)]

キャッシュ戦略

キャッシュ対象方法TTL
ユーザーセッションRedis Strings24時間
商品一覧/記事一覧Redis Strings (JSON)5分
ユーザープロフィールRedis Hashes1時間
API レスポンスRedis Strings1-5分
静的アセットCDN (CloudFront)1日

キャッシュ導入の効果

[キャッシュなし]
DBクエリ: 1,000回/秒
レスポンスタイム: 200ms

[キャッシュあり(ヒット率80%)]
DBクエリ: 200回/秒(80%削減)
レスポンスタイム: 20ms(90%短縮)

この段階での判断基準

指標閾値対策
DBクエリ数500回/秒以上Redisキャッシュ導入
レスポンスタイム200ms以上クエリ最適化 + キャッシュ
静的アセット配信ページロード3秒以上CDN導入

Stage 2: Read Replica + CDN(10,000-100,000ユーザー)

アーキテクチャ

[ユーザー]
    |
    v
[CloudFront (CDN)]
    |
    v
[ALB (ロードバランサー)]
    |
    +--------+--------+
    |        |        |
[App 1]  [App 2]  [App 3]  (水平スケーリング)
    |        |        |
    +--------+--------+
             |
    +--------+--------+
    |                 |
[Redis           [PostgreSQL
 Cluster]         Primary]
                      |
              +-------+-------+
              |               |
         [Read Replica 1] [Read Replica 2]

読み書き分離

操作接続先
書き込み(INSERT/UPDATE/DELETE)Primaryユーザー登録、投稿作成
読み取り(SELECT)Read Replica一覧表示、検索

注意: レプリケーション遅延

Read Replicaにはミリ秒〜数秒の遅延がある。ユーザーが投稿した直後に「自分の投稿が見えない」という問題が発生し得る。対策として、自分自身のデータはPrimaryから読み取る(Read Your Own Writes)パターンを採用する。

水平スケーリングの条件

アプリケーションを水平スケーリングするには、アプリケーションがステートレスである必要がある。

条件対策
セッションをサーバーに保存しないRedis等の外部ストアを使う
ファイルをローカルに保存しないS3等の外部ストレージを使う
サーバー間で共有が必要なデータRedis、DBを使う

Stage 3: モジュラーモノリス / サービス分離開始(100,000-1,000,000ユーザー)

アーキテクチャ

[ユーザー]
    |
    v
[CloudFront + WAF]
    |
    v
[ALB]
    |
    +-- [API サーバー群 (モジュラーモノリス)]
    |   |
    |   +-- [ユーザーモジュール]
    |   +-- [商品モジュール]
    |   +-- [注文モジュール]
    |   +-- [通知モジュール] --> 分離候補
    |   +-- [検索モジュール] --> 分離候補
    |
    +-- [非同期処理ワーカー]
    |   |
    |   +-- [SQS] --> [Lambda / ECS Task]
    |
    v
[データストア]
    +-- [Aurora PostgreSQL (Primary + Replica x 2)]
    +-- [ElastiCache Redis Cluster]
    +-- [OpenSearch (検索)]
    +-- [S3 + CloudFront]

モジュラーモノリスとは

モジュラーモノリスは、単一のアプリケーション内で機能をモジュールに分割し、モジュール間の依存関係を厳密に管理するアーキテクチャ。

[モノリス vs モジュラーモノリス vs マイクロサービス]

モノリス:
+---------------------------+
| すべてが密結合            |
| ユーザー←→商品←→注文←→通知 |
+---------------------------+

モジュラーモノリス:
+---------------------------+
| [ユーザー] | [商品]       |
|     ↓ API  |    ↓ API     |
| [注文]     | [通知]       |
| モジュール間はAPIで通信    |
+---------------------------+
同一プロセス内だが、モジュール間の境界が明確

マイクロサービス:
[ユーザー]  [商品]  [注文]  [通知]
各サービスが独立したプロセス/コンテナ

サービス分離の判断基準

基準分離すべきサイン
スケーリング要件の違い検索サービスだけCPU負荷が高い
デプロイ頻度の違い通知サービスは頻繁に変更、決済は安定
チームの境界別チームが開発/運用する
技術スタックの違いPython (ML)で書きたいサービスがある
障害の分離通知の障害が本体に影響してはいけない

最初に分離する候補

サービス分離理由
通知サービス非同期処理、障害分離
画像処理サービスCPU負荷が高い、非同期
検索サービス別の技術(OpenSearch)を使用
バッチ処理長時間実行、リソース消費が大きい

Stage 4: マイクロサービス(1,000,000-10,000,000ユーザー)

アーキテクチャ

[ユーザー]
    |
    v
[CloudFront + WAF]
    |
    v
[API Gateway / BFF]
    |
    +-- [ユーザーサービス] --> [Aurora (Users DB)]
    |
    +-- [商品サービス] --> [Aurora (Products DB)]
    |
    +-- [注文サービス] --> [Aurora (Orders DB)]
    |                        |
    |                        +-- [SQS] --> [在庫サービス]
    |
    +-- [検索サービス] --> [OpenSearch]
    |
    +-- [通知サービス] --> [SQS] --> [SES/SNS]
    |
    +-- [分析サービス] --> [Redshift/BigQuery]
    |
    v
[共通基盤]
    +-- [Redis Cluster (キャッシュ)]
    +-- [Kafka (イベントストリーミング)]
    +-- [Jaeger (分散トレーシング)]
    +-- [Prometheus + Grafana (監視)]

マイクロサービスで必要になるインフラ

インフラ用途ツール例
サービスディスカバリサービス間の位置解決AWS Cloud Map, Consul
API GatewayリクエストルーティングAWS API Gateway, Kong
メッセージキュー非同期通信SQS, Kafka
分散トレーシングリクエストの追跡AWS X-Ray, Jaeger
サービスメッシュサービス間通信の管理AWS App Mesh, Istio
設定管理環境設定の一元管理AWS Systems Manager
シークレット管理秘匿情報の管理Secrets Manager, Vault

データベースの分割(Database per Service)

パターン説明トレードオフ
共有DB全サービスが同一DBを使用簡単だがサービス間の結合が強い
DB per Serviceサービスごとに独立したDB独立性が高いが、クロスサービスクエリが困難
Saga パターン分散トランザクション複雑だが整合性を保てる
CQRS書き込みと読み取りを分離高パフォーマンスだが複雑

Stage 5: グローバル分散(10,000,000+ユーザー)

アーキテクチャ

[グローバルユーザー]
    |
    v
[Route 53 (Geo DNS)]
    |
    +-- [東京リージョン]
    |   +-- [CloudFront]
    |   +-- [ECS/EKS クラスター]
    |   +-- [Aurora Global Database (Primary)]
    |   +-- [ElastiCache]
    |
    +-- [北米リージョン (us-east-1)]
    |   +-- [CloudFront]
    |   +-- [ECS/EKS クラスター]
    |   +-- [Aurora Global Database (Replica)]
    |   +-- [ElastiCache]
    |
    +-- [欧州リージョン (eu-west-1)]
        +-- [CloudFront]
        +-- [ECS/EKS クラスター]
        +-- [Aurora Global Database (Replica)]
        +-- [ElastiCache]

グローバル分散の課題

課題対策
データの整合性結果整合性を受け入れる設計
レプリケーション遅延最大1秒程度の遅延を前提に
データのローカライゼーションGDPR等の規制に対応したデータ配置
障害のリージョン間波及リージョン間の依存を最小限に
コストクロスリージョンデータ転送費用

データベースシャーディング

シャーディングとは

データベースのデータを複数のDB(シャード)に分散して格納する技術。1つのDBでは処理しきれないデータ量/リクエスト量に対応する。

シャーディング戦略

戦略説明メリットデメリット
ハッシュベースキーのハッシュ値でシャードを決定均等な分散範囲クエリが困難
レンジベースキーの範囲でシャードを決定範囲クエリが容易ホットスポットのリスク
ジオベース地域でシャードを決定低レイテンシ地域間のデータ共有が困難
テナントベーステナント(顧客)ごとにシャードテナント分離が完全大テナントの偏り

シャーディング導入のタイミング

[シャーディング導入の判断]

以下の全てを試した後に検討する:
1. クエリの最適化(インデックス、クエリ改善)
2. Read Replicaの追加
3. キャッシュの強化
4. 接続プーリングの最適化
5. パーティショニング(テーブル分割)

それでもDBがボトルネックなら → シャーディング検討

CDNとキャッシュ戦略

CDN活用のレベル

レベルキャッシュ対象効果
Level 1静的ファイル(CSS、JS、画像)ページロード高速化
Level 2API レスポンス(短いTTL)サーバー負荷軽減
Level 3HTMLページ(ISR/SSG)オリジンサーバーへのリクエスト大幅削減
Level 4Edge Computingユーザーに最も近い場所で処理

キャッシュ戦略の全体像

[リクエストの流れ]

[ブラウザキャッシュ] (TTL: 5分)
    ↓ miss
[CDN (CloudFront)] (TTL: 1-5分)
    ↓ miss
[アプリケーションキャッシュ (Redis)] (TTL: 5-60分)
    ↓ miss
[データベース]

各段階でのコスト概算

Stageユーザー規模月額インフラコストチーム規模
Stage 00-100$0-201-3人
Stage 1100-10,000$50-2003-5人
Stage 210,000-100,000$300-1,0005-10人
Stage 3100,000-1,000,000$2,000-10,00010-30人
Stage 41,000,000-10,000,000$10,000-100,00030-100人
Stage 510,000,000+$100,000+100人+

スケーリングのアンチパターン

アンチパターン問題対策
早すぎる最適化ユーザーが100人なのにシャーディングユーザーが増えてから対応
早すぎるマイクロサービス化チーム3人でマイクロサービスまずモノリスで始める
垂直スケーリングへの依存サーバーをどんどん大きくする水平スケーリングを前提に設計
キャッシュの乱用全てをキャッシュで解決しようとする根本原因(遅いクエリ等)を修正
技術的負債の放置スケーリング時に一気にツケが来る段階的に負債を返済

判断フローチャート

[スケーリング判断]
    |
    v
[現在のボトルネックは?]
    |
    +-- DBの読み取り
    |   → Redis キャッシュ、Read Replica
    |
    +-- DBの書き込み
    |   → 非同期処理(SQS)、最終的にはシャーディング
    |
    +-- アプリサーバーのCPU/メモリ
    |   → 水平スケーリング(インスタンス追加)
    |
    +-- 静的コンテンツの配信
    |   → CDN(CloudFront)
    |
    +-- 開発チームの生産性
    |   → モジュラーモノリス、サービス分離
    |
    +-- グローバルなレイテンシ
        → マルチリージョン展開

まとめ

スケーリングの鉄則

鉄則詳細
早すぎないユーザーが少ないうちは最適化しない
測定してから最適化推測ではなくデータに基づく
段階的に進めるBig Bangの移行は避ける
シンプルさを保つ複雑さはスケーリングの敵
自動化するスケーリングは自動化前提で設計

各段階の推奨アクション

段階最初にやること
Stage 0→1Redis導入、CDN導入
Stage 1→2Read Replica、水平スケーリング
Stage 2→3モジュラーモノリス化、非同期処理
Stage 3→4ボトルネックとなるサービスから分離
Stage 4→5マルチリージョン展開

大半のプロダクトはStage 2-3で十分。Stage 4以上が必要になるのは、グローバル展開する大規模サービスのみ。過度なスケーリング設計は避け、プロダクトの成長に合わせて段階的に進化させることが最も効率的なアプローチである。


参考リンク