
簡介
同步通訊是一種請求-回應模型:客戶端發送請求,等待伺服器回應。 REST 和 gRPC 是內部服務間通訊的兩種最受歡迎的選擇。
1.REST API
1.1 RESTful 設計原則
REST(表述性狀態傳輸)使用 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-10x) | 更快 |
| 有效負載大小 | 大(JSON 詳細) | 小(約 JSON 的 30%) |
| 串流媒體 | 非本土 | 全力支持 |
| 程式碼生成 | 手冊 / OpenAPI 程式碼生成 | 內置,成熟 |
| 瀏覽器支援 | 本地 | 需要 gRPC-Web 代理 |
| 調試 | 人類可讀 | 困難(二進制) |
| 工具 | 郵差、捲曲、... | grpcurl、BloomRPC |
| 學習曲線 | 低 | 平均 |
| 合約 | 可選(OpenAPI) | 必需(.proto) |
3.1 何時選擇休息?
- 客戶端/瀏覽器/行動裝置的外部API
- 用於第三方整合的公共API
- 簡單的CRUD操作
- 團隊不熟悉 gRPC
3.2 什麼時候選擇gRPC?
- 內部服務間通信
- 高效能需求(低延遲、高吞吐量)
- 串流媒體用例(即時更新、物聯網)
- 多語言環境(多種語言,需要程式碼產生)
- 嚴格合約執行
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 相容性 |
下一篇文章:非同步通訊 - 訊息佇列、事件流以及何時使用非同步而不是同步。