在現代軟體工程中,「如何定義系統間的通訊合約」是每個架構師必須面對的核心決策。

長久以來,REST(Representational State Transfer)一直是 Web 開發的事實標準;然而隨著微服務拆分帶來的內部超高頻 RPC 呼叫,gRPC 憑藉二進位序列化與 HTTP/2 雙向串流強勢崛起;與此同時,面對複雜的多端前端(Web、iOS、Android、IoT)與龐大的資料視圖聚合需求,GraphQL 又以「宣告式按需查詢」顛覆了傳統 API 的消費模式。

這三種技術並非簡單的替代關係,而是各自擁有截然不同的架構邊界與設計哲學。本文基於 gRPC 官方技術指南、GraphQL 官方規範 與 ByteByteGo System Design 101,建立一套工程化的選型決策模型。

gRPC vs. REST vs. GraphQL 通訊範式與架構邊界對比 比較三種主流 API 通訊典範:基於 Protobuf 二進位與 HTTP/2 串流的 gRPC、成熟通用的 REST/JSON,以及靈活圖查詢但伴隨 N+1 查詢與 DataLoader 挑戰的 GraphQL。BINARY & HIGH PERFORMANCEgRPC (Protobuf / HTTP/2)• 二進位序列化 (Protocol Buffers)• 序列化體積縮小 70%,速度快 5-10x• 原生雙向串流 (Bi-directional Streaming)• Schema-First 強型別合約與代碼自動生成• 最佳定位:內部微服務高速 RPC⚖️ 優劣權衡• (+) 極致傳輸效率與強型別約束• (-) 瀏覽器除錯困難 (無法肉眼讀 JSON)• (-) 對外公開 API 整合門檻較高內部微服務黃金標準RESOURCE-ORIENTEDREST (JSON / HTTP 1.1/2)• 資源導向架構 (URI + HTTP 動詞)• JSON 文字格式,人眼直觀可讀• 標準 HTTP 狀態碼與快取 (Cache-Control)• OpenAPI / Swagger 生態極度成熟• 最佳定位:對外公開 API、第三方整合⚖️ 優劣權衡• (+) 全球相容性最高、生態最完整• (-) Over-fetching (冗餘欄位) / Under-fetching• (-) 移動端複雜頁面需多次來回 Round-trips公開生態與合作夥伴首選DECLARATIVE GRAPH QUERYGraphQL (Schema / AST)• 客戶端精準按需查詢 (No Over-fetching)• 單一端點 `/graphql` 聚合跨領域資料• 強型別 GraphQL Schema 定義• 訂閱機制 (GraphQL Subscriptions)• 最佳定位:複雜多端前端、儀表板聚合⚖️ 優劣權衡• (+) 大幅降低前端發起之 HTTP 請求數• (-) 後端 N+1 查詢瓶頸 (需 DataLoader 快取)• (-) HTTP 快取失效、惡意深層查詢 DoS 風險前端儀表板與多端視圖神器
01. 內部微服務

gRPC (Protobuf / HTTP/2)

極致效能與強型別合約,二進位序列化節省 70% 體積,內部服務間低延遲 RPC 通訊首選。

02. 公開 API 生態

REST (JSON / HTTP)

標準資源導向架構,人眼可讀、瀏覽器原生友好,具備最強的生態工具鏈與公開對外相容性。

03. 複雜視圖聚合

GraphQL (宣告式圖查詢)

前端按需宣告欄位,單一請求聚合多服務資料;需搭配 DataLoader 解決後端 N+1 查詢與查詢複雜度熔斷。

圖 1:API 典範選型矩陣:gRPC(內部高吞吐)、REST(公開生態)與 GraphQL(靈活前端聚合)。

1. gRPC:內部微服務極致吞吐與強型別合約

gRPC 由 Google 開源,核心建立在兩大支柱之上:Protocol Buffers(Protobuf) 二進位序列化協定與 HTTP/2 傳輸協定。

為什麼 gRPC 的效能比 REST 快 5 ~ 10 倍?

  1. 二進位緊湊編碼(Varint & Tag-Length-Value):
    • REST 傳輸 JSON 時,每個鍵名(如 "user_id": 12345)都以 ASCII 字元傳送,浪費大量位元組。
    • Protobuf 將欄位映射為整數編號(Tag),只傳輸二進位值與型別標記,Payload 體積平均縮小 60% ~ 80%。
  2. CPU 序列化/反序列化極快:JSON 解析需要大量字串掃描與記憶體分配;Protobuf 直接映射為記憶體結構體,CPU 消耗大幅降低。
  3. 原生雙向串流(Bi-directional Streaming):單一 TCP 連線上支援 Client Streaming、Server Streaming 與雙向全雙工串流,極度適合高頻遙測日誌與即時訊息。
syntax = "proto3";

service OrderService {
  rpc CreateOrder (CreateOrderRequest) returns (OrderResponse);
  rpc StreamOrderStatus (OrderLookup) returns (stream OrderStatusUpdate);
}

message CreateOrderRequest {
  string user_id = 1;
  repeated string item_ids = 2;
  int64 timestamp = 3;
}

gRPC 的代價與邊界

  • 瀏覽器支援度差:瀏覽器不允許 JavaScript 直接控制 HTTP/2 幀,需透過 grpc-web 與 Envoy 代理轉發。
  • 人眼不可讀:網路抓包(Wireshark)需要載入 .proto 定義檔才能解碼,除錯門檻高於 JSON。

2. REST:公開生態、跨團隊協同與 HTTP 快取的王者

REST 誕生於 2000 年 Roy Fielding 的博士論文,強調**「以資源為核心(Resource-Oriented)」**,充分利用 HTTP 協定本身的語意。

REST 的核心架構優勢

  1. 天然的 HTTP 快取生態(Cache-Control & ETag):
    • 瀏覽器、CDN(Cloudflare/Akamai)與反向代理完全理解 HTTP GET 與 304 Not Modified,靜態與低頻數據可直接在邊緣快取,根本無需打到後端。
  2. 全球最大的開發者生態與工具鏈:Postman、cURL、Swagger/OpenAPI 等工具極度成熟,第三方開發者看文件 5 分鐘即可上手。
  3. 鬆偶合與無狀態(Statelessness):客戶端與伺服器各自獨立演進,透過標準 HTTP 動詞(GET, POST, PUT, DELETE)操作資源。

REST 遭遇的現代瓶頸

  • Over-fetching(過度獲取):手機端只需要用戶姓名與頭像,但 /api/v1/users/123 回傳包含 50 個欄位的龐大 JSON。
  • Under-fetching 與瀑布請求(Waterfall Requests):渲染一個訂單詳情頁面,前端必須先請求 /orders,再遍歷每個 Order ID 發起 /users、/payments、/products,造成嚴重的網路來回延遲(Round-trips)。

3. GraphQL:多端前端宣告式圖查詢與 N+1 陷阱

GraphQL 由 Meta(Facebook)於 2012 年開發並於 2015 年開源,專門解決複雜移動應用的資料聚合難題。

1. 客戶端按需宣告(No Over-fetching)

前端透過單一查詢語句宣告精準欄位,伺服器保證回傳完全一致的 JSON 形狀:

query GetOrderDetails($id: ID!) {
  order(id: $id) {
    id
    totalAmount
    user {
      name
      avatarUrl
    }
    items {
      productName
      price
    }
  }
}

2. 致命陷阱:後端 N+1 查詢問題

在 GraphQL 的 Resolver 模型中,若查詢 10 筆訂單及其關聯用戶:

  • 執行 1 次 SQL 查詢 10 筆訂單:SELECT * FROM orders LIMIT 10
  • 針對每筆訂單的 user 欄位,GraphQL 引擎會觸發 10 次獨立查詢:SELECT * FROM users WHERE id = ?
  • 原本 1 次 SQL 爆炸為 11 次 SQL 查詢(N+1 Problem)。

解決方案:DataLoader 批次合併快取

Meta 開源了 DataLoader 函式庫,利用 Node.js Event Loop 的 Microtask 階段:

  • 收集同一個 Tick 內發起的所有 userId。
  • 自動將 10 次單筆查詢合併為單一 SQL:SELECT * FROM users WHERE id IN (1, 2, ... 10)。
// DataLoader 批次加載器原理
const userLoader = new DataLoader(async (userIds) => {
  const users = await db.users.findMany({ where: { id: { in: userIds } } });
  return userIds.map((id) => users.find((u) => u.id === id));
});

三大通訊典範深度決策維度

評估維度gRPC (Protobuf)REST (JSON)GraphQL (AST Query)
通訊協定HTTP/2 二進位HTTP/1.1 或 HTTP/2HTTP/1.1 或 HTTP/2 (POST)
資料格式Protocol BuffersJSONJSON (按 Query 格式回傳)
Schema 約束性強 (編譯期強制生成 SDK)弱至中 (需手動維護 OpenAPI)強 (GraphQL Schema SDL)
傳輸效率與延遲極致 (最小 Payload & CPU)中等 (JSON 字串開銷)中等 (需伺服器 AST 解析)
HTTP 快取友好度差極佳 (天然 CDN / 瀏覽器)差 (全部走 POST 請求)
客戶端靈活性固化 (需發布新 Proto)固化 (依賴後端 API 定義)極高 (前端自主宣告欄位)
除錯與工具鏈體驗較高 (需專用工具)極低 (cURL / 瀏覽器直開)良好 (GraphiQL 互動式操場)
主要應用場景內部微服務高速 RPC公開 API / 第三方整合複雜前端視圖 / 多端 BFF

現代架構最佳實踐組合(Hybrid Architecture)

在成熟的企業級系統中,最佳實踐絕非「三選一」,而是**「分層混用、各司其職」**:

現代分散式通訊邊界混用最佳實踐拓撲圖展示前端透過 GraphQL/REST 連接 BFF 閘道,BFF 轉為 gRPC 與內部微服務高速互聯。前端 SPA / 行動 App• 按需宣告精準欄位• 消除網路請求瀑布HTTP/JSONGraphQL / REST BFF 閘道• 集中身份鑑權與速率限制• 協定轉換 ➔ JSON 轉 ProtogRPC內部微服務叢集• 萬級 QPS 高速二進位互聯• HTTP/2 多路復用強型別
  1. 內部微服務之間(Service-to-Service):全面採用 gRPC。享受強型別編譯保護、低延遲與最小化伺服器資源消耗。
  2. 對外公開與開放平台(Public APIs):一律採用 REST / OpenAPI。提供全球開發者最熟悉的體驗與最大化 CDN 快取效率。
  3. 多端前端與複雜儀表板(Client-to-BFF):採用 GraphQL 或輕量 REST BFF。消除移動端 Over-fetching 與網路瀑布請求。

參考資料與一手文獻