API 閘道(API Gateway)是微服務架構中至關重要的基礎設施組件。它作為系統的統一入口,承擔著路由、安全、限流等關鍵職責。本章節將深入探討 API 閘道的原理、功能與實作。
為什麼需要 API 閘道#
微服務架構的挑戰#
在微服務架構中,內部通常包含多個獨立的服務模組(如購物車服務、庫存服務、推薦服務、訂單服務等),這些服務由不同的團隊獨立維護。
對於外部客戶端而言:
- 不應該直接感知到後端複雜的服務拓撲結構
- 不應該需要知道每個服務的地址
- 不應該處理跨服務的通用邏輯(如認證、限流)
API 閘道的核心價值#
API 閘道對外提供一個「統一的介面」。無論後端有多少個微服務在運作,外部使用者面對的只是一個統一的服務入口。這不僅簡化了客戶端的呼叫邏輯,也保護了內部架構的隱私與安全。
flowchart TB
subgraph Clients["外部客戶端"]
C1["Web App"]
C2["Mobile App"]
C3["Third Party"]
end
Clients --> GW["API Gateway<br/>(統一入口)"]
GW --> S1["用戶服務"]
GW --> S2["訂單服務"]
GW --> S3["商品服務"]
style GW fill:#fff3e0API 閘道的部署架構#
典型的請求鏈路#
從部署視圖來看,API 閘道通常位於負載均衡器與內部微服務之間:
flowchart TB
L1["1. 用戶接入層<br/>無線設備、桌面應用、伺服器等"]
L2["2. 負載均衡層<br/>接收外部流量並分發"]
L3["3. API 閘道層<br/>處理路由、認證等邏輯"]
L4["4. 微服務層<br/>實際的業務邏輯處理單元"]
L1 --> L2 --> L3 --> L4
style L1 fill:#e3f2fd
style L2 fill:#e8f5e9
style L3 fill:#fff3e0
style L4 fill:#f3e5f5高可用設計原則#
為了確保系統的高可用性,通常會在閘道前置一層負載均衡器。這要求閘道本身設計為「無狀態(Stateless)」的。
無狀態設計的優勢:
- 允許閘道進行水平擴展(Scale-out)
- 即使某一台閘道實例故障,流量可以無縫切換至其他存活節點
- 避免單點故障(SPOF)
- 保障整體系統的穩定性
API 閘道的四大核心功能#
1. 反向路由 (Reverse Routing)#
這是閘道最基本的功能。當外部請求進入時,閘道需要根據請求的特徵(如 URL 路徑),將其精準地「導航」並轉換為內部具體服務的呼叫。
路由組態示例:
routes:
- path: /api/users/**
service: user-service
- path: /api/orders/**
service: order-service
- path: /api/products/**
service: product-service路由策略:
| 策略 | 說明 |
|---|---|
| 路徑匹配 | 根據 URL 路徑前綴路由 |
| Header 匹配 | 根據請求頭資訊路由 |
| 參數匹配 | 根據查詢參數路由 |
| 權重路由 | 按比例分配流量(用於灰度發布) |
2. 安全認證 (Security Authentication)#
如同門衛負責識別訪客身份,閘道是防禦惡意攻擊的第一道防線。
主要職責:
| 功能 | 說明 |
|---|---|
| 請求過濾 | 區分正常用戶訪問與惡意爬蟲、黑客攻擊 |
| 身份驗證 | 驗證請求者的身份(如 JWT Token 驗證) |
| 權限校驗 | 檢查請求者是否有權限訪問目標資源 |
| 統一認證 | 在請求到達後端服務之前,集中處理認證 |
認證流程示例:
flowchart TD
A["1. 客戶端發送請求<br/>(攜帶 Token)"] --> B["2. 閘道提取並驗證 Token"]
B -->|驗證失敗| C["返回 401 Unauthorized"]
B -->|驗證成功| D["3. 提取用戶資訊"]
D --> E["4. 將用戶資訊注入請求頭"]
E --> F["5. 轉發請求到後端服務"]
style C fill:#ffcdd2
style F fill:#c8e6c93. 限流與熔斷 (Rate Limiting & Circuit Breaking)#
應對突發流量(如「雙 11」大促、秒殺活動)的關鍵機制。
限流 (Rate Limiting):
當大流量洪峰湧入時,如果沒有防護措施,後端服務極易癱瘓。閘道需實施限流策略,拒絕超過系統負荷的請求。
常見限流算法:
| 算法 | 特點 |
|---|---|
| 令牌桶 | 允許一定程度的突發流量 |
| 漏桶 | 流量輸出速率恆定 |
| 固定窗口 | 簡單但可能有臨界點問題 |
| 滑動窗口 | 更精確但實作複雜 |
熔斷 (Circuit Breaking):
當後端某個服務出現不穩定時,閘道可快速切斷對該服務的呼叫,防止故障擴散導致雪崩效應。
stateDiagram-v2
[*] --> Closed: 初始狀態
Closed --> Open: 失敗率超過閾值
Open --> HalfOpen: 經過一段時間
HalfOpen --> Closed: 嘗試請求成功
HalfOpen --> Open: 嘗試請求失敗
note right of Closed: 正常狀態
note right of Open: 快速失敗<br/>不呼叫後端服務
note right of HalfOpen: 嘗試少量請求4. 日誌監控 (Logging & Monitoring)#
由於所有外部流量都必須經過閘道,這使其成為資料採集的最佳位置。
主要功能:
| 功能 | 說明 |
|---|---|
| 訪問審計 | 對所有請求進行記錄與審計 |
| 效能分析 | 通過分析日誌,監控呼叫延遲、成功率等指標 |
| 流量統計 | 統計各服務的訪問量、峰值等 |
| 異常告警 | 檢測異常模式並觸發告警 |
閘道過濾器架構#
以 Netflix Zuul 為例#
Zuul 的請求處理流程通過一系列的過濾器來完成,主要分為三個階段:
flowchart TD
A[請求進入] --> B[Pre-routing Filters<br/>前置過濾器]
B --> |日誌處理<br/>路由決策<br/>參數校驗| C[Routing Filters<br/>路由過濾器]
C --> |服務呼叫<br/>網路請求| D[Post-routing Filters<br/>後置過濾器]
D --> |響應加工<br/>統計審計<br/>日誌記錄| E[響應返回]
B -.-> |異常| F[Error Filters<br/>錯誤處理]
C -.-> |異常| F
D -.-> |異常| F
F --> E
style B fill:#e3f2fd
style C fill:#fff3e0
style D fill:#e8f5e9
style F fill:#ffebee在 Pre、Routing、Post 的任一環節中,若發生錯誤或拋出異常,流程會轉交給 Error Filters 進行全域的錯誤處理與訊息封裝,確保客戶端能收到格式統一的錯誤回應。
動態過濾器機制#
閘道作為流量入口,通常承受巨大的訪問壓力,不適合頻繁重啟。但業務需求往往需要頻繁調整閘道邏輯。
Zuul 的解決方案:使用 Groovy 腳本編寫過濾器,支援動態載入。
過濾器動態上傳與載入流程
- 上傳 (Upload):開發人員編寫 Groovy 過濾器腳本,上傳至過濾器儲存資料庫
- 輪詢 (Polling):Filter Poller 定期輪詢資料庫,檢查是否有新增或更新的過濾器
- 下載 (Download):若發現變更,Poller 將腳本下載至本地特定目錄
- 掃描與載入 (Scan & Load):
- Filter File Manager 定期掃描本地目錄
- 發現新文件,呼叫 Filter Loader 動態載入 Groovy 腳本
- 最終註冊到 Zuul Filter Runner 中,新邏輯立即生效
請求上下文共享#
由於請求會流經多級過濾器,需要在不同階段之間傳遞資料。
Request Context:
- 基於 ThreadLocal 實作
- 允許在單次請求的生命週期內,讓 Pre、Routing、Post 等各階段的過濾器共享狀態與資訊
閘道設計的權衡#
瘦閘道 vs 胖閘道#
在實際的架構演進中,關於閘道的職責邊界往往存在爭議:是否應該在 API 閘道層引入「業務邏輯」?
瘦閘道 (Thin Gateway) - 推薦:
| 特點 | 說明 |
|---|---|
| 職責 | 專注於路由、限流、安全等通用基礎設施功能 |
| 業務邏輯 | 完全下沉到微服務中 |
| 穩定性 | 更穩定,升級維護不依賴具體業務團隊 |
| 發布 | 發布頻率低,風險可控 |
胖閘道 (Fat Gateway):
| 特點 | 說明 |
|---|---|
| 職責 | 包含聚合接口(BFF)或部分業務校驗邏輯 |
| 問題 | 容易成為單體瓶頸 |
| 發布 | 不同業務團隊的程式碼糾纏,嚴重拖慢發布效率 |
建議保持閘道「輕量化」。若需處理複雜的資料聚合,可考慮引入獨立的 BFF (Backend for Frontend) 層,而不是將邏輯塞入全域的 API 閘道中。
BFF 模式#
當需要為不同的前端(Web、iOS、Android)提供定製化的 API 時,可以採用 BFF 模式:
flowchart TB
subgraph Apps["客戶端應用"]
A1["Web App"]
A2["iOS App"]
A3["Android App"]
end
subgraph BFFs["BFF 層"]
B1["Web BFF"]
B2["iOS BFF"]
B3["Android BFF"]
end
A1 --> B1
A2 --> B2
A3 --> B3
B1 --> GW
B2 --> GW
B3 --> GW
GW["API Gateway"] --> MS["後端微服務"]
style BFFs fill:#e3f2fd
style GW fill:#fff3e0常見的 API 閘道實作#
Netflix Zuul#
特點:
- 基於 Servlet,運行於 Tomcat 容器
- 過濾器架構,支援動態載入
- Spring Cloud 早期默認閘道
Spring Cloud Gateway#
特點:
- 基於 Spring WebFlux,非阻塞
- 響應式編程模型
- Spring Cloud 新一代閘道
Kong#
特點:
- 基於 Nginx + Lua
- 豐富的插件生態
- 支援聲明式組態
APISIX#
特點:
- 基於 Nginx + Lua
- 雲原生友好
- 高效能
API 閘道選型對比
| 特性 | Zuul 1.x | Spring Cloud Gateway | Kong | APISIX |
|---|---|---|---|---|
| 效能 | 中等 | 高 | 高 | 極高 |
| 協議支援 | HTTP | HTTP, WebSocket | HTTP, gRPC | HTTP, gRPC |
| 組態方式 | 程式碼 | 程式碼/組態 | 聲明式 | 聲明式 |
| 插件機制 | Filter | Filter | Plugin | Plugin |
| 語言 | Java | Java | Lua | Lua |
| 雲原生 | 一般 | 良好 | 良好 | 優秀 |
實踐建議#
閘道設計清單#
| 考量點 | 建議 |
|---|---|
| 無狀態設計 | 確保閘道實例可以水平擴展 |
| 健康檢查 | 組態完善的健康檢查機制 |
| 超時設置 | 合理設置連接超時和讀取超時 |
| 重試策略 | 組態合理的重試策略,避免重試風暴 |
| 限流粒度 | 根據業務需求選擇合適的限流粒度 |
| 監控告警 | 建立完善的監控和告警機制 |
| 灰度發布 | 支援基於權重或規則的灰度發布 |
| 文檔管理 | 與 API 文檔系統(如 Swagger)集成 |
常見問題與解決方案#
| 問題 | 解決方案 |
|---|---|
| 閘道成為效能瓶頸 | 水平擴展 + 效能最佳化 |
| 組態變更需要重啟 | 引入動態組態機制 |
| 跨域問題 | 在閘道層統一處理 CORS |
| 請求體過大 | 組態合理的請求體大小限制 |
| 長連接支援 | 選擇支援 WebSocket 的閘道 |