Chuyển đến nội dung chính

レッスン 17: サービス通信パターン

同期: REST、gRPC、GraphQL の詳細な比較。非同期: メッセージベース、イベントベース。サービス メッシュ (Istio、Linkerd)。サーキット ブレーカー、リトライ、タイムアウト パターン。 API のバージョン管理戦略。

🏗️ アーキテクチャ — レッスン 17 レッスン 17: サービス通信パターン

システムアーキテクチャ: ゼロからヒーローへ

パート 5: アーキテクチャ パターン

xdev.asia

はじめに

マイクロサービスでは、サービスは相互に通信する必要があります。間違った通信パターンを選択すると、連鎖的な障害、高い遅延、密結合が発生する可能性があります。この記事では、一般的なパターンをすべて分析します。


1. 同期通信

1.1 休憩

GET /api/users/123 HTTP/1.1
Host: user-service
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 123,
  "name": "Duy Tran",
  "email": "[email protected]"
}

Ưu điểm:
  ✅ Simple, human-readable
  ✅ Widely supported
  ✅ HTTP caching
  ✅ Dễ debug (curl, Postman)

Nhược điểm:
  ❌ Over-fetching / Under-fetching
  ❌ Multiple round trips (N+1)
  ❌ Text-based → larger payload

1.2 gRPC

// Proto definition
service UserService {
  rpc GetUser(GetUserRequest) returns (User);
  rpc ListUsers(ListUsersRequest) returns (stream User);
}

message User {
  int64 id = 1;
  string name = 2;
  string email = 3;
}

Ưu điểm:
  ✅ Binary (Protobuf) → nhỏ hơn, nhanh hơn
  ✅ HTTP/2 → multiplexing, streaming
  ✅ Strongly typed (code generation)
  ✅ Bi-directional streaming

Nhược điểm:
  ❌ Không human-readable
  ❌ Browser support hạn chế (cần grpc-web)
  ❌ Khó debug hơn REST

1.3 GraphQL

# Client quyết định lấy fields nào
query {
  user(id: 123) {
    name
    orders(last: 5) {
      id
      total
      items {
        product { name }
      }
    }
  }
}

# 1 request lấy đúng data cần thiết
# Không over-fetching, không under-fetching

Ưu điểm:
  ✅ Client-driven queries
  ✅ Single endpoint
  ✅ Strongly typed schema
  ✅ Introspection

Nhược điểm:
  ❌ Complexity (resolver, dataloader)
  ❌ Caching khó hơn REST
  ❌ N+1 queries ở backend
  ❌ Security (query depth attacks)

1.4 比較

特長休憩gRPCグラフQL
プロトコルHTTP/1.1+HTTP/2HTTP
フォーマットJSONプロトブフJSON
タイプセーフティ弱い強い強い
ストリーミングいいえ (SSE)はい定期購読
ブラウザはい限定はい
こんな方に最適パブリック APIサービス↔サービスフロントエンド↔バックエンド
パフォーマンス中高中

2. 非同期通信

2.1 メッセージベース (ポイントツーポイント)

Order Service ──message──► Queue ──► Payment Service

  Tight contract: Order Service biết Payment Service sẽ xử lý
  1 message → 1 consumer
  Use case: Task distribution

2.2 イベントベース (Pub/Sub)

Order Service ──event──► Topic
                            │
                  ┌─────────┼─────────┐
                  ▼         ▼         ▼
              Payment   Inventory   Email

  Loose coupling: Order Service KHÔNG biết ai subscribe
  1 event → N consumers
  Use case: Notifications, data sync

2.3 リクエスト/リプライ (非同期)

Order Service ──► Request Queue ──► Payment Service
                                        │
Order Service ◄── Reply Queue ◄─────────┘

  Correlation ID để match request ↔ reply
  Async nhưng vẫn request-response semantic

3. 回復力のパターン

3.1 サーキットブレーカー

States:
  CLOSED (normal):
    Requests đi qua bình thường
    Đếm failures

  OPEN (tripped):
    Failures > threshold → OPEN
    Requests bị reject ngay (fail fast)
    Không gọi downstream service

  HALF-OPEN (testing):
    After timeout → cho 1 request thử
    Success → CLOSED
    Fail → OPEN lại

  ┌────────┐  failure > 5  ┌────────┐
  │ CLOSED │──────────────►│  OPEN  │
  │        │◄──────────────│        │
  └────────┘  success      └───┬────┘
                               │ timeout
                         ┌─────▼─────┐
                         │ HALF-OPEN │
                         └───────────┘

3.2 指数バックオフを使用した再試行

Attempt 1: Fail → Wait 1s
Attempt 2: Fail → Wait 2s
Attempt 3: Fail → Wait 4s
Attempt 4: Fail → Wait 8s + jitter
Attempt 5: Fail → Give up, return error

Jitter: Random delay thêm vào
  Tránh "thundering herd" khi nhiều clients retry cùng lúc

Retry Budget:
  Max 20% requests là retries
  Tránh retry storm amplification

3.3 タイムアウト戦略

Cascading timeout:

  Client ──(timeout: 5s)──► API Gateway
  API Gateway ──(timeout: 3s)──► Order Service
  Order Service ──(timeout: 1s)──► Payment Service

  Rule: Outer timeout > Inner timeout
  Tránh: Client đã timeout nhưng backend vẫn xử lý

3.4 バルクヘッド

Vấn đề: 1 slow service chiếm hết threads → toàn bộ app chậm

Giải pháp: Isolate resource pools

  ┌─────────────────────────────────────┐
  │ Application                         │
  │                                     │
  │ ┌─────────────┐ ┌─────────────┐    │
  │ │ Thread Pool │ │ Thread Pool │    │
  │ │ Service A   │ │ Service B   │    │
  │ │ (10 threads)│ │ (10 threads)│    │
  │ └─────────────┘ └─────────────┘    │
  │                                     │
  │ Service A chậm → Pool A hết        │
  │ Service B vẫn hoạt động bình thường │
  └─────────────────────────────────────┘

4. サービスメッシュ

4.1 サイドカー パターン

Không có Service Mesh:
  Service A ──(retry, circuit breaker, mTLS, tracing)──► Service B
  Logic phức tạp TRONG code mỗi service

Có Service Mesh:
  ┌──────────────────┐         ┌──────────────────┐
  │ Pod A            │         │ Pod B            │
  │ ┌──────────────┐ │         │ ┌──────────────┐ │
  │ │ Service A    │ │         │ │ Service B    │ │
  │ │ (business    │ │         │ │ (business    │ │
  │ │  logic only) │ │         │ │  logic only) │ │
  │ └──────┬───────┘ │         │ └──────▲───────┘ │
  │        │         │         │        │         │
  │ ┌──────▼───────┐ │         │ ┌──────┴───────┐ │
  │ │ Sidecar Proxy│◄├─────────├►│ Sidecar Proxy│ │
  │ │ (Envoy)      │ │  mTLS   │ │ (Envoy)      │ │
  │ │ retry,circuit│ │         │ │ retry,circuit│ │
  │ │ trace,metrics│ │         │ │ trace,metrics│ │
  │ └──────────────┘ │         │ └──────────────┘ │
  └──────────────────┘         └──────────────────┘

  Control Plane (Istio/Linkerd):
    Config policies, certificates, routing rules

5. API のバージョン管理

1. URL versioning:
   /api/v1/users    → Version 1
   /api/v2/users    → Version 2
   Simple, explicit

2. Header versioning:
   Accept: application/vnd.myapp.v2+json
   Clean URLs

3. Query parameter:
   /api/users?version=2
   Easy to test

4. No versioning (evolution):
   Thêm fields mới (backward compatible)
   Deprecate old fields (nhưng không remove)
   GraphQL style

概要

パターンいつ使用するか
休憩パブリック API、単純な CRUD
gRPCサービス ↔ サービス、パフォーマンス重視
グラフQL複雑なフロントエンド クエリ
非同期/イベント疎結合、結果整合性
サーキットブレーカー連鎖的な障害から保護する
サービスメッシュ多くのサービス、複雑なネットワーキング

演習

  1. プロトコルの選択: マイクロサービス: API ゲートウェイ → ユーザー サービス、注文サービス → インベントリ サービス、フロントエンド → BFF。各ペアに対して REST/gRPC/GraphQL を選択します。説明する。

  2. サーキット ブレーカー構成: 支払いサービスには SLA 99.9% (ダウンタイム 43 分/月) があります。サーキット ブレーカー構成の設計: 障害しきい値、タイムアウト、ハーフオープン要求、回復時間。

  3. 回復力設計: サービス A はサービス B (重要)、サービス C (オプション) を呼び出します。依存関係ごとに再試行 + タイムアウト + フォールバック戦略を設計します。