微服務:鑑權與限流#
微服務架構中,鑑權和限流是保障系統穩定運行的關鍵機制。
鑑權 (Authentication)#
場景#
不同應用對同一服務的不同介面有不同的訪問權限。
應用 A → 可訪問 /user/info, /user/login
應用 B → 可訪問 /user/info
應用 C → 可訪問 /user/register實作策略#
根據匹配模式選擇不同的資料結構:
| 匹配模式 | 資料結構 | 匹配演算法 |
|---|---|---|
| 精確匹配 | 有序陣列 | 二分查找 + 字串匹配 |
| 前缀匹配 | Trie 樹 | 前缀匹配 |
| 模糊匹配 | 陣列 + Trie | 回溯演算法 |
精確匹配#
將規則存入有序陣列,使用二分查找:
規則:["/user/info", "/user/login", "/user/register"]
請求:"/user/login"
→ 二分查找 → 匹配成功時間複雜度:O(log n)
前缀匹配#
使用 Trie 樹,節點存儲 URL 子目錄:
root
|
user
/ \
info login將子節點組織成有序陣列,可用二分查找加速子節點定位。
模糊匹配#
規則包含通配符(* 匹配單層,** 匹配多層):
規則:/user/**/info
匹配:/user/123/info, /user/abc/def/info策略:
- 無通配符規則 → 有序陣列或 Trie
- 有通配符規則 → 陣列 + 回溯演算法
先查無通配符規則,不匹配再查有通配符規則。
限流 (Rate Limiting)#
固定時間窗口#
|-------- 1s --------|-------- 1s --------|
計數: 0...100 計數: 0...
↓ ↓
達到限制 重新計數問題:無法處理臨界時刻的突發流量
臨界問題示例
限制:100 QPS
第 1 秒末 10ms:100 次請求 ✓
第 2 秒初 10ms:100 次請求 ✓在 20ms 內產生了 200 次請求,超過了預期限制。
滑動時間窗口#
維護一個迴圈佇列,記錄每個請求的時間戳:
// 限制 K 次/秒
CircularQueue queue = new CircularQueue(K + 1);
boolean allowRequest(long timestamp) {
// 移除超過 1 秒的舊請求
while (!queue.isEmpty() &&
timestamp - queue.peek() > 1000) {
queue.dequeue();
}
// 檢查是否還有空間
if (queue.size() < K) {
queue.enqueue(timestamp);
return true;
}
return false;
}優點:保證任意 1 秒窗口內不超過限制
滑動窗口仍無法限制更細粒度的突發(如 10ms 內的集中請求)。如需更平滑的流量控制,可使用令牌桶或漏桶演算法。
其他限流演算法#
| 演算法 | 特點 |
|---|---|
| 令牌桶 | 以固定速率產生令牌,請求需取得令牌 |
| 漏桶 | 請求入桶,以固定速率處理 |
| 計數器 | 簡單但有臨界問題 |
資料結構總結#
| 功能 | 資料結構 | 原因 |
|---|---|---|
| 應用 → 規則集合 | 散列表 | O(1) 查找 |
| 精確匹配規則 | 有序陣列 | 二分查找 |
| 前缀匹配規則 | Trie 樹 | 前缀匹配 |
| 滑動窗口限流 | 迴圈佇列 | 固定大小,高效增刪 |
實踐建議#
基礎架構工程師必須精通資料結構和演算法,才能開發出性能卓越的中間件。
- 根據匹配模式選擇合適的資料結構
- 優先使用簡單方案,複雜方案按需引入
- 考慮實際場景的性能需求