Day 6: マイクロサービスとAPI設計
今日学ぶこと
- モノリスとマイクロサービスのトレードオフ
- REST、gRPC、GraphQLの比較と使い分け
- API Gatewayパターン
- サービスディスカバリ
- レートリミティングとスロットリング
- 認証(OAuth 2.0、JWT)
- 冪等性(Idempotency)
モノリスとマイクロサービス
モノリスアーキテクチャ
モノリスはすべての機能が1つのアプリケーションにまとまったアーキテクチャです。
flowchart TB
subgraph Monolith["モノリスアプリケーション"]
direction TB
UI["UI Layer"]
BL["Business Logic"]
DA["Data Access"]
end
subgraph DB["データベース"]
Single["単一DB"]
end
UI --> BL --> DA --> Single
style Monolith fill:#3b82f6,color:#fff
style DB fill:#8b5cf6,color:#fff
マイクロサービスアーキテクチャ
マイクロサービスは、機能ごとに独立したサービスとして分離するアーキテクチャです。
flowchart TB
Client["クライアント"]
GW["API Gateway"]
Client --> GW
subgraph Services["マイクロサービス"]
S1["ユーザーサービス"]
S2["注文サービス"]
S3["決済サービス"]
S4["通知サービス"]
end
GW --> S1
GW --> S2
GW --> S3
GW --> S4
subgraph Databases["データベース"]
DB1["Users DB"]
DB2["Orders DB"]
DB3["Payments DB"]
DB4["Notifications DB"]
end
S1 --> DB1
S2 --> DB2
S3 --> DB3
S4 --> DB4
style Services fill:#22c55e,color:#fff
style Databases fill:#8b5cf6,color:#fff
トレードオフ比較
| 観点 | モノリス | マイクロサービス |
|---|---|---|
| 開発速度(初期) | 速い | 遅い(インフラ構築が必要) |
| デプロイ | 全体を一括デプロイ | サービス単位でデプロイ |
| スケーリング | 全体をスケール | 個別にスケール |
| 技術スタック | 統一 | サービスごとに選択可能 |
| 障害の影響範囲 | 全体に波及 | 影響を局所化できる |
| データ整合性 | ACID トランザクション | 結果整合性(Eventual Consistency) |
| 運用の複雑さ | 低い | 高い(監視、ログ集約が必要) |
| チーム編成 | 大きなチーム | 小さな独立チーム |
面接のポイント: 「マイクロサービスが常に正解」ではありません。プロジェクトの規模、チームのスキル、ビジネス要件に応じて判断することが重要です。
API設計:REST vs gRPC vs GraphQL
REST(Representational State Transfer)
RESTは最も広く使われているAPI設計スタイルです。HTTPメソッドを使ってリソースを操作します。
GET /api/users # List users
POST /api/users # Create user
GET /api/users/{id} # Get user
PUT /api/users/{id} # Update user
DELETE /api/users/{id} # Delete user
RESTのベストプラクティス:
- 名詞でリソースを表現(
/users、/orders) - HTTPメソッドで操作を表現
- 適切なHTTPステータスコードを使用
- ページネーション、フィルタリング、ソートをサポート
- バージョニング(
/api/v1/users)
gRPC(Google Remote Procedure Call)
gRPCはProtocol Buffersを使った高性能なRPCフレームワークです。
// user.proto - Protocol Buffers definition
syntax = "proto3";
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc ListUsers (ListUsersRequest) returns (stream User);
}
message GetUserRequest {
string user_id = 1;
}
message User {
string id = 1;
string name = 2;
string email = 3;
}
GraphQL
GraphQLはクライアントが必要なデータだけを指定して取得できるクエリ言語です。
# Client specifies exactly what data it needs
query {
user(id: "123") {
name
email
orders {
id
total
items {
name
price
}
}
}
}
API方式の比較
| 特徴 | REST | gRPC | GraphQL |
|---|---|---|---|
| プロトコル | HTTP/1.1, HTTP/2 | HTTP/2 | HTTP/1.1, HTTP/2 |
| データ形式 | JSON, XML | Protocol Buffers(バイナリ) | JSON |
| 型安全性 | OpenAPI/Swagger | 組み込み(.proto) | スキーマ定義 |
| ストリーミング | WebSocket別途 | 双方向ストリーミング | Subscription |
| パフォーマンス | 中 | 高(バイナリ、HTTP/2) | 中 |
| 学習コスト | 低い | 中〜高 | 中 |
| 適用場面 | 公開API、Web | サービス間通信 | 複雑なデータ取得 |
| Over-fetching | あり得る | なし | なし |
flowchart LR
subgraph External["外部クライアント向け"]
REST["REST API"]
GQL["GraphQL"]
end
subgraph Internal["サービス間通信"]
GRPC["gRPC"]
end
subgraph Async["非同期通信"]
MQ["Message Queue"]
end
style External fill:#3b82f6,color:#fff
style Internal fill:#22c55e,color:#fff
style Async fill:#f59e0b,color:#fff
API Gatewayパターン
API Gatewayはすべてのクライアントリクエストの入口となるサーバーです。
flowchart TB
Web["Webアプリ"]
Mobile["モバイルアプリ"]
Third["サードパーティ"]
subgraph Gateway["API Gateway"]
Auth["認証"]
RL["レートリミティング"]
Route["ルーティング"]
Agg["レスポンス集約"]
Cache["キャッシュ"]
end
Web --> Gateway
Mobile --> Gateway
Third --> Gateway
Gateway --> S1["ユーザーサービス"]
Gateway --> S2["商品サービス"]
Gateway --> S3["注文サービス"]
style Gateway fill:#3b82f6,color:#fff
API Gatewayの主な責務:
| 機能 | 説明 |
|---|---|
| ルーティング | リクエストを適切なサービスに転送 |
| 認証・認可 | トークン検証、権限チェック |
| レートリミティング | APIの過剰利用を防止 |
| ロードバランシング | 複数インスタンスへの負荷分散 |
| キャッシュ | レスポンスのキャッシュ |
| レスポンス集約 | 複数サービスの結果を統合 |
| プロトコル変換 | 外部REST → 内部gRPC |
| ログ・監視 | リクエストの記録と分析 |
代表的な実装:AWS API Gateway、Kong、Nginx、Envoy
サービスディスカバリ
マイクロサービスのインスタンスは動的に増減します。サービスディスカバリは、各サービスの場所(IP、ポート)を管理する仕組みです。
クライアントサイドディスカバリ
sequenceDiagram
participant C as クライアント
participant R as Service Registry
participant S1 as Service A (Instance 1)
participant S2 as Service A (Instance 2)
S1->>R: 登録(IP:PORT)
S2->>R: 登録(IP:PORT)
C->>R: Service Aのインスタンスは?
R->>C: [Instance 1, Instance 2]
C->>S1: 直接リクエスト
サーバーサイドディスカバリ
sequenceDiagram
participant C as クライアント
participant LB as Load Balancer
participant R as Service Registry
participant S1 as Service A (Instance 1)
C->>LB: リクエスト
LB->>R: Service Aのインスタンスは?
R->>LB: [Instance 1, ...]
LB->>S1: リクエスト転送
S1->>LB: レスポンス
LB->>C: レスポンス
| 方式 | メリット | デメリット |
|---|---|---|
| クライアントサイド | レイテンシが低い | クライアントが複雑になる |
| サーバーサイド | クライアントがシンプル | Load Balancerがボトルネックになりうる |
代表的なツール:Consul、etcd、ZooKeeper、Eureka
レートリミティングとスロットリング
APIを過剰な利用やDDoS攻撃から守るための仕組みです。
主なアルゴリズム
| アルゴリズム | 仕組み | 特徴 |
|---|---|---|
| Token Bucket | トークンが一定レートで補充。リクエストごとにトークンを消費 | バースト許容、最も一般的 |
| Leaky Bucket | リクエストをキューに入れ、一定レートで処理 | 出力が均一 |
| Fixed Window | 固定時間窓でカウント | 実装が簡単だが境界問題あり |
| Sliding Window Log | タイムスタンプをログに記録 | 正確だがメモリ消費大 |
| Sliding Window Counter | Fixed + Sliding の組み合わせ | バランスが良い |
flowchart LR
subgraph TB["Token Bucket"]
direction TB
Refill["トークン補充\n(一定レート)"]
Bucket["バケット\n[●●●○○]"]
Refill --> Bucket
end
Request["リクエスト"] --> Bucket
Bucket -->|トークンあり| Allow["許可 ✓"]
Bucket -->|トークンなし| Deny["拒否 429"]
style TB fill:#3b82f6,color:#fff
style Allow fill:#22c55e,color:#fff
style Deny fill:#ef4444,color:#fff
HTTPレスポンスヘッダー例:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640000000
Retry-After: 30
認証:OAuth 2.0とJWT
OAuth 2.0フロー(Authorization Code)
sequenceDiagram
participant U as ユーザー
participant App as アプリケーション
participant Auth as 認証サーバー
participant API as リソースサーバー
U->>App: ログインボタンクリック
App->>Auth: 認可リクエスト(redirect)
Auth->>U: ログイン画面表示
U->>Auth: 認証情報入力
Auth->>App: 認可コード
App->>Auth: 認可コード + Client Secret
Auth->>App: Access Token + Refresh Token
App->>API: Access Token付きリクエスト
API->>App: 保護されたリソース
JWT(JSON Web Token)
JWTは3つのパートで構成されます:
Header.Payload.Signature
// Header
{
"alg": "HS256",
"typ": "JWT"
}
// Payload
{
"sub": "user123",
"name": "Taro",
"role": "admin",
"exp": 1640000000
}
// Signature
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
| 方式 | 特徴 | 適用場面 |
|---|---|---|
| Session-based | サーバー側で状態管理 | 従来のWebアプリ |
| JWT | ステートレス、自己完結 | マイクロサービス、SPA |
| OAuth 2.0 | 第三者認可の標準 | ソーシャルログイン、API認可 |
| API Key | シンプル、固定キー | サーバー間通信 |
冪等性(Idempotency)
冪等性とは、同じ操作を何回実行しても結果が変わらない性質です。ネットワーク障害によるリトライで重要になります。
sequenceDiagram
participant C as クライアント
participant S as サーバー
C->>S: POST /payment (Idempotency-Key: abc123)
Note over S: 決済処理実行
S--xC: レスポンス(ネットワークエラー)
Note over C: タイムアウト → リトライ
C->>S: POST /payment (Idempotency-Key: abc123)
Note over S: 同じキーなので<br/>前の結果を返す
S->>C: 200 OK(前回と同じ結果)
HTTPメソッドの冪等性:
| メソッド | 冪等性 | 安全性 | 説明 |
|---|---|---|---|
| GET | ○ | ○ | リソースの取得 |
| PUT | ○ | ✗ | リソースの置換 |
| DELETE | ○ | ✗ | リソースの削除 |
| POST | ✗ | ✗ | リソースの作成 |
| PATCH | ✗ | ✗ | リソースの部分更新 |
冪等性の実装方法:
- Idempotency Key: クライアントがユニークなキーを送信
- サーバー側チェック: キーをRedis等に保存し、重複チェック
- 結果キャッシュ: 処理結果を一定期間保存して返す
実践:ライドシェアサービスのAPI設計
面接での設計例を見てみましょう。
主要なAPI
# Rider APIs
POST /api/v1/rides # Request a ride
GET /api/v1/rides/{rideId} # Get ride details
PUT /api/v1/rides/{rideId}/cancel # Cancel ride
GET /api/v1/rides/{rideId}/track # Track ride (WebSocket)
# Driver APIs
PUT /api/v1/drivers/{id}/location # Update location
PUT /api/v1/drivers/{id}/status # Update availability
GET /api/v1/drivers/{id}/rides # Get assigned rides
PUT /api/v1/rides/{rideId}/accept # Accept ride
PUT /api/v1/rides/{rideId}/complete # Complete ride
# Matching Service (internal gRPC)
rpc FindNearbyDrivers(Location) returns (stream Driver)
rpc AssignDriver(RideRequest) returns (Assignment)
# Payment APIs
POST /api/v1/payments # Process payment
GET /api/v1/payments/{id} # Get payment status
POST /api/v1/payments/{id}/refund # Process refund
サービス間アーキテクチャ
flowchart TB
Client["モバイルアプリ"]
subgraph GW["API Gateway"]
Auth2["認証"]
RL2["Rate Limit"]
end
Client --> GW
subgraph Core["コアサービス"]
Ride["配車サービス"]
Match["マッチングサービス"]
Driver["ドライバーサービス"]
Payment["決済サービス"]
Notify["通知サービス"]
end
GW --> Ride
Ride -->|gRPC| Match
Match -->|gRPC| Driver
Ride --> Payment
Ride --> Notify
subgraph Data["データストア"]
RideDB["Rides DB"]
GeoIdx["Geospatial Index\n(Redis)"]
PayDB["Payments DB"]
end
Ride --> RideDB
Driver --> GeoIdx
Payment --> PayDB
style GW fill:#3b82f6,color:#fff
style Core fill:#22c55e,color:#fff
style Data fill:#8b5cf6,color:#fff
まとめ
今日のポイント一覧
| トピック | 重要ポイント |
|---|---|
| モノリス vs マイクロサービス | トレードオフを理解し、状況に応じて選択 |
| API設計 | REST(公開API)、gRPC(サービス間)、GraphQL(複雑なデータ取得) |
| API Gateway | ルーティング、認証、レートリミティングの一元管理 |
| サービスディスカバリ | 動的なサービスインスタンスの管理 |
| レートリミティング | Token Bucket が最も一般的 |
| 認証 | OAuth 2.0 + JWT がマイクロサービスの標準 |
| 冪等性 | ネットワーク障害時のリトライ安全性を確保 |
面接で使えるキーフレーズ
- 「公開APIにはRESTを使い、サービス間通信にはgRPCを選択します」
- 「API Gatewayで認証とレートリミティングを一元管理します」
- 「決済APIには冪等性キーを必須にして、二重課金を防ぎます」
練習問題
基礎レベル
- RESTful APIの設計原則を5つ挙げ、それぞれブログ管理APIの例で説明してください
- Token BucketとLeaky Bucketの違いを図を描いて説明してください
中級レベル
- ECサイトのマイクロサービス分割を設計してください。サービス間の通信方式(同期/非同期)も含めて説明してください
- JWTベースの認証で、トークンが漏洩した場合の対策を3つ以上考えてください
チャレンジ
- ライドシェアサービスで、ドライバーの位置情報をリアルタイムで更新するAPIを設計してください。1秒ごとの位置更新を100万人のドライバーから受け取る場合のスケーラビリティを考慮してください
参考リンク
- RESTful API Design Best Practices
- gRPC Documentation
- GraphQL Official
- OAuth 2.0 Specification
- Martin Fowler - Microservices
次回予告
Day 7: URL短縮サービスの設計 — いよいよ本格的なシステム設計面接の実践です。URL短縮サービスの要件定義からアーキテクチャ設計まで、面接の流れに沿って一通り設計します。