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

レッスン 5: 同期通信 — REST API と gRPC

REST API 設計のベスト プラクティス、gRPC と Protobuf、HTTP/2 多重化、REST と gRPC の比較、どちらを選択するか、API のバージョン管理戦略。

🏗️ アーキテクチャ — レッスン 5 レッスン 5: 同期通信 — REST API と gRPC

クラウドネイティブのマイクロサービスアーキテクチャ

パート 2: マイクロサービスの設計と通信パターン

xdev.asia

レッスン 5: 同期通信 — REST API と gRPC

はじめに

同期通信はリクエスト/レスポンス モデルです。クライアントはリクエストを送信し、サーバーの応答を待ちます。 REST と gRPC は、内部サービス間通信の 2 つの最も一般的な選択肢です。


1. REST API

1.1 RESTful 設計原則

REST (Representational State Transfer) は、HTTP メソッドを使用してリソースを操作します。

GET    /api/v1/orders          → Liệt kê đơn hàng
GET    /api/v1/orders/{id}     → Chi tiết đơn hàng
POST   /api/v1/orders          → Tạo đơn hàng mới
PUT    /api/v1/orders/{id}     → Cập nhật toàn bộ
PATCH  /api/v1/orders/{id}     → Cập nhật một phần
DELETE /api/v1/orders/{id}     → Xoá đơn hàng

1.2 ベストプラクティス

命名規則:

✅ /api/v1/orders                    # Noun, plural
✅ /api/v1/orders/{id}/items         # Nested resource
✅ /api/v1/orders?status=pending     # Filtering via query params

❌ /api/v1/getOrders                 # Verb in URL
❌ /api/v1/order                     # Singular
❌ /api/v1/orders/getByStatus/pending # Logic in URL

HTTP ステータス コード:

2xx Success:
  200 OK              — GET, PUT, PATCH thành công
  201 Created          — POST tạo resource mới
  204 No Content       — DELETE thành công

4xx Client Error:
  400 Bad Request      — Validation error
  401 Unauthorized     — Chưa xác thực
  403 Forbidden        — Không có quyền
  404 Not Found        — Resource không tồn tại
  409 Conflict         — Trùng lặp (duplicate)
  422 Unprocessable    — Business logic error
  429 Too Many Requests — Rate limit exceeded

5xx Server Error:
  500 Internal Server Error — Lỗi server
  502 Bad Gateway           — Upstream service error
  503 Service Unavailable   — Service đang quá tải
  504 Gateway Timeout       — Upstream timeout

ページネーション:

GET /api/v1/orders?page=2&per_page=20&sort=-created_at

{
  "data": [...],
  "meta": {
    "current_page": 2,
    "per_page": 20,
    "total": 150,
    "total_pages": 8
  },
  "links": {
    "first": "/api/v1/orders?page=1&per_page=20",
    "prev": "/api/v1/orders?page=1&per_page=20",
    "next": "/api/v1/orders?page=3&per_page=20",
    "last": "/api/v1/orders?page=8&per_page=20"
  }
}

1.3 API のバージョン管理

Strategy 1: URL Path (khuyến nghị)
  /api/v1/orders
  /api/v2/orders

Strategy 2: Header
  Accept: application/vnd.myapi.v2+json

Strategy 3: Query Parameter
  /api/orders?version=2

1.4 OpenAPI / Swagger

以前のコントラクト API (API First) を定義します。

openapi: 3.0.3
info:
  title: Order Service API
  version: 1.0.0
paths:
  /api/v1/orders:
    post:
      summary: Create a new order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: Order created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          description: Validation error
components:
  schemas:
    CreateOrderRequest:
      type: object
      required: [customer_id, items]
      properties:
        customer_id:
          type: string
          format: uuid
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'

2.gRPC

2.1 概要

gRPC は、Google によって開発された RPC (リモート プロシージャ コール) フレームワークであり、以下を使用します。

  • プロトコル バッファー (Protobuf) — バイナリ シリアル化
  • HTTP/2 — 多重化、サーバープッシュ、ヘッダー圧縮
Order Service                     Inventory Service
┌──────────────┐                  ┌──────────────┐
│              │  gRPC/HTTP2      │              │
│  gRPC Client │──────────────────▶  gRPC Server │
│  (generated) │  Protobuf binary │  (generated) │
│              │◀─────────────────│              │
└──────────────┘                  └──────────────┘

2.2 プロトコルバッファ

サービス契約を定義する .proto ファイル:

syntax = "proto3";

package inventory;

option go_package = "github.com/myorg/inventory/proto";
option java_package = "com.myorg.inventory.grpc";

// Service definition
service InventoryService {
  // Unary RPC
  rpc CheckStock(StockRequest) returns (StockResponse);
  rpc ReserveItems(ReserveRequest) returns (ReserveResponse);

  // Server streaming
  rpc StreamStockUpdates(StockFilter) returns (stream StockUpdate);

  // Bidirectional streaming
  rpc SyncInventory(stream InventoryEvent) returns (stream SyncResult);
}

// Messages
message StockRequest {
  string product_id = 1;
  int32 quantity = 2;
}

message StockResponse {
  bool available = 1;
  int32 current_stock = 2;
  string warehouse_id = 3;
}

message ReserveRequest {
  string order_id = 1;
  repeated ReserveItem items = 2;
}

message ReserveItem {
  string product_id = 1;
  int32 quantity = 2;
}

message ReserveResponse {
  bool success = 1;
  string reservation_id = 2;
  google.protobuf.Timestamp expires_at = 3;
}

2.3 gRPC 通信パターン

1. Unary RPC (Request-Response):
   Client ──request──▶ Server
   Client ◀─response── Server

2. Server Streaming:
   Client ──request──▶ Server
   Client ◀─stream 1── Server
   Client ◀─stream 2── Server
   Client ◀─stream N── Server

3. Client Streaming:
   Client ──stream 1──▶ Server
   Client ──stream 2──▶ Server
   Client ──stream N──▶ Server
   Client ◀──response── Server

4. Bidirectional Streaming:
   Client ──stream──▶ Server
   Client ◀──stream── Server
   (đồng thời, full-duplex)

2.4 コード生成

から .proto ファイルに含めると、すべての言語のコードが自動的に生成されます。

# Go
protoc --go_out=. --go-grpc_out=. proto/inventory.proto

# Java
protoc --java_out=. --grpc-java_out=. proto/inventory.proto

# TypeScript
protoc --ts_out=. proto/inventory.proto

3. REST と gRPC の比較

基準休憩gRPC
プロトコルHTTP/1.1 (または 2)HTTP/2
形式JSON (テキスト)Protobuf (バイナリ)
パフォーマンス遅い (~2 ~ 10 倍)より速く
ペイロードサイズ大 (JSON 冗長)小さい (JSON の約 30%)
ストリーミングネイティブではありませんフルサポート
コード生成マニュアル / OpenAPI コード生成内蔵、成熟
ブラウザのサポートネイティブgRPC-Web プロキシが必要
デバッグ人間が読める難しい(バイナリ)
ツーリング郵便屋さん、カール、...grpurl、ブルームRPC
学習曲線低い平均
契約オプション (OpenAPI)必須 (.proto)

3.1 REST を選択するのはどのような場合ですか?

  • クライアント/ブラウザ/モバイル用の外部 API
  • サードパーティ統合用のパブリック API
  • シンプルなCRUD操作
  • チームは gRPC に慣れていない

3.2 gRPC を選択するのはどのような場合ですか?

  • 内部サービス間通信
  • 高いパフォーマンス要件 (低遅延、高スループット)
  • ストリーミングの使用例 (リアルタイム更新、IoT)
  • 多言語環境 (多くの言語、コード生成が必要)
  • 厳格な契約執行

3.3 一般的なパターン: REST は外側、gRPC は内側

┌──────────┐     REST/JSON     ┌──────────────┐     gRPC/Protobuf     ┌─────────────┐
│  Client  │──────────────────▶│ API Gateway  │─────────────────────▶│ Internal    │
│ (Browser)│◀──────────────────│              │◀─────────────────────│ Services    │
└──────────┘                   └──────────────┘                      └─────────────┘

4. 同期通信でのエラー処理

4.1 タイムアウト

Order Service ──request──▶ Payment Service
     │                           │
     │      (đợi response)       │
     │                           │
     │  timeout = 3 giây         │
     │                           │
     ├── Nếu < 3s: nhận response ✓
     └── Nếu > 3s: timeout error ✗
         → Retry? Circuit breaker? Fallback?

ルール: 送信リクエストごとに常にタイムアウトを設定し、無期限に待機しないでください。

4.2 カスケード障害

❌ Synchronous chain dài:
Client → A → B → C → D → E
   │
   └── Nếu E chậm → D chậm → C chậm → B chậm → A chậm → Client timeout

Giải pháp:
1. Circuit Breaker (bài 18)
2. Timeout cho mỗi hop
3. Chuyển sang async khi có thể
4. Bulkhead pattern

5. API コントラクトのテスト

サービスプロバイダーとコンシューマーが API について同意していることを確認してください。

Consumer-Driven Contract Testing (Pact):

┌──────────────┐                    ┌──────────────┐
│ Order Service│   Pact Contract    │Payment Service│
│  (Consumer)  │◀──────────────────▶│  (Provider)  │
└──────────────┘                    └──────────────┘

1. Consumer viết test với expected request/response
2. Pact generate contract file
3. Provider verify contract
4. Nếu provider thay đổi API → contract test fail → phát hiện breaking change

6. まとめ

パターン使用例
休憩外部 API、ブラウザ、単純な CRUD
gRPC内部サービス通信、高性能、ストリーミング
REST + gRPC外部用は REST、内部用は gRPC
タイムアウトすべての同期呼び出しに必須
契約テストサービス間の API 互換性を確保する

次の記事: 非同期通信 — メッセージ キュー、イベント ストリーミング、および同期ではなく非同期を使用する場合。