マイクロサービスとは何か — 定義と原則
「マイクロサービスって、要するに小さいサービスに分けることですよね?」
会議が終わったあと、新人エンジニアのケンジがミサキに聞いた。
「半分正解。でも『小さい』ことより『独立している』ことの方が重要なんだよね」
マイクロサービスの定義
マイクロサービスアーキテクチャとは、1つのアプリケーションを、独立してデプロイ可能な小さなサービスの集合として構築するスタイルだ。
各サービスは:
- 独自のプロセスで動作する(別のサーバー、別のコンテナ)
- 軽量な通信メカニズム(HTTP/gRPC/メッセージキュー)で連携する
- ビジネス機能に沿って設計される(技術レイヤーではなく)
- 独立してデプロイ・スケール・障害からの回復ができる
モノリスとの根本的な違い
デプロイの独立性
これがマイクロサービスで最も重要な特性だ。
# モノリスのデプロイ
$ git push origin main
# → アプリ全体が再起動
# → 商品機能の修正でも、注文機能のコードも再デプロイされる
# → ダウンタイムリスクが全機能に影響
# マイクロサービスのデプロイ
$ git push product-service main
# → 商品サービスだけが再デプロイ
# → 注文サービスは影響なく動作し続ける
# → ダウンタイムリスクは商品機能のみ障害の分離
# モノリスでの障害伝播(疑似コード)
class SearchService
def search(query)
# 検索DBが重くなると...
results = SlowSearchDB.query(query) # タイムアウト30秒
# → このリクエストを処理するスレッドが30秒間ブロック
# → スレッドプールが枯渇
# → 注文処理のリクエストも捌けなくなる
# → サイト全体が停止
end
end# マイクロサービスでの障害分離
# 検索サービスが落ちても...
class OrdersController < ApplicationController
def create
# サーキットブレーカーが検索サービスの障害を検知
# → 注文処理は独立して継続
order = OrderService.create(params)
render json: order, status: :created
end
endスケールの独立性
# ECS サービス定義 — 機能ごとに独立したスケール設定
# 検索サービス: セールで検索が集中するのでスケールアウト
search-service:
desired_count: 20
cpu: 1024
memory: 2048
# 注文サービス: 通常のスケール
order-service:
desired_count: 5
cpu: 512
memory: 1024
# ユーザーサービス: 軽量
user-service:
desired_count: 3
cpu: 256
memory: 512マイクロサービスの4つの原則
原則1: 単一責任(Single Responsibility)
各サービスは1つのビジネスドメインに集中する。
# 悪い例: 責任が混在したサービス
class ProductAndOrderAndUserService
def create_order(user_id, product_id, quantity)
user = fetch_user(user_id) # ユーザーの責任
product = fetch_product(product_id) # 商品の責任
order = create_order_record(...) # 注文の責任
send_email(user, order) # 通知の責任
end
end
# 良い例: 責任が明確
class OrderService
def create_order(user_id, product_id, quantity)
# 注文の作成だけに集中
# ユーザー情報はUser Serviceから取得(API経由)
# 商品情報はProduct Serviceから取得(API経由)
# 通知はNotification Serviceに委譲(イベント経由)
order = Order.create!(...)
publish_event('order_created', order)
order
end
end原則2: 独立デプロイ(Independent Deployability)
サービスAの変更がサービスBの再デプロイを要求しない。
# 悪い例: 密結合した設定
# order-service は product-service の内部実装に依存
order_service:
environment:
PRODUCT_DB_HOST: product-postgres
PRODUCT_DB_PORT: 5432
PRODUCT_TABLE_NAME: products_v2
# 良い例: インターフェースのみに依存
order_service:
environment:
PRODUCT_SERVICE_URL: http://product-service
PRODUCT_SERVICE_VERSION: v1原則3: データの分散所有(Decentralized Data Management)
各サービスは自分のデータを所有し、他サービスのDBに直接アクセスしない。
# 絶対にやってはいけないこと
module OrderService
class Order < ApplicationRecord
# OrderServiceのコードがProductServiceのDBに直接アクセス
def product
ProductServiceDatabase::Product.find(product_id)
end
end
end
# 正しい方法: APIを通じてアクセス
module OrderService
class Order < ApplicationRecord
def product
ProductServiceClient.find(product_id)
end
end
end原則4: 障害に備えた設計(Design for Failure)
依存サービスが落ちることを前提にコードを書く。
# app/services/product_service_client.rb
class ProductServiceClient
def self.find(product_id)
response = HTTP.timeout(2).get("#{BASE_URL}/products/#{product_id}")
JSON.parse(response.body)
rescue HTTP::TimeoutError, HTTP::ConnectionError => e
# サービスが落ちていても graceful degradation
Rails.logger.error("ProductService unavailable: #{e.message}")
{ id: product_id, name: '商品情報取得中', price: 0 } # フォールバック
end
end「マイクロ」のサイズ感
「マイクロ」という名前に惑わされてはいけない。重要なのはコード行数ではなく、ビジネスの境界だ。
INFO
マイクロサービスの適切なサイズ感のヒント:「1つのスクワッド(4〜8人)が所有・開発できる規模」。コード行数でなく、チームの認知負荷で測る。
小さすぎるサービス(ナノサービス)の問題:
UserEmailService ← メール変更だけ
UserPasswordService ← パスワードだけ
UserNameService ← 名前だけ
→ ネットワーク呼び出しが爆発、管理コストが高騰
適切なサービス:
UserService ← ユーザーの全属性、認証、プロフィール
OrderService ← 注文ライフサイクル全体
ProductService ← 商品カタログ、在庫
→ ビジネスの変更が1つのサービス内で完結
モノリシックファーストの原則
WARNING
新規プロジェクトには最初からマイクロサービスを採用しないこと。ドメインの理解が不十分な状態では、誤った境界を引いてしまう。まずモノリスで作り、境界が見えてから分割する。
Martin Fowler が提唱する「モノリシックファースト」のアプローチ:
Phase 1: モノリスで MVP を作る
→ ドメインの理解を深める
→ どこで変更が頻発するかを観察
Phase 2: 明確な境界が見えてきたら分割
→ 変更頻度が異なる領域
→ チームの所有権が分かれる領域
→ スケール要件が異なる領域
Phase 3: 継続的に進化させる
→ サービスはいつでも統合・分割できる
ShopNovaの現状整理
ミサキはチームとともに、ShopNovaのドメインを整理した。
それぞれのドメインは:
| ドメイン | 変更頻度 | スケール要件 | 所有チーム |
|---|---|---|---|
| 商品管理 | 高 | 中 | Squad A |
| 注文処理 | 中 | 高(セール時) | Squad B |
| ユーザー管理 | 低 | 低 | Squad B |
| 検索 | 高 | 超高(セール時) | Squad A |
| 通知 | 低 | 中 | Squad C |
| レコメンド | 高 | 中 | Squad C |
「変更頻度が違う、スケール要件が違う、所有チームが違う — これがサービス境界のヒントだ」とミサキは言った。
次章では、この境界をどう正確に引くかを学ぶ。
まとめ
マイクロサービスの本質は「小さいこと」ではなく「独立していること」だ。
- 独立デプロイ — 他のサービスを止めずに変更できる
- 単一責任 — 1つのビジネスドメインに集中
- 分散データ — 各サービスがデータを所有
- 障害前提 — 依存サービスの障害を前提に設計
そして最も重要な教訓:最初からマイクロサービスを選ばない。ドメインが見えてから分割する。
ミサキはこの原則をホワイトボードに書き留めた。これが彼女たちの羅針盤になる。