微服務:鑑權與限流#

微服務架構中,鑑權和限流是保障系統穩定運行的關鍵機制。

鑑權 (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

策略

  1. 無通配符規則 → 有序陣列或 Trie
  2. 有通配符規則 → 陣列 + 回溯演算法

先查無通配符規則,不匹配再查有通配符規則。

限流 (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 樹前缀匹配
滑動窗口限流迴圈佇列固定大小,高效增刪

實踐建議#

基礎架構工程師必須精通資料結構和演算法,才能開發出性能卓越的中間件。

  1. 根據匹配模式選擇合適的資料結構
  2. 優先使用簡單方案,複雜方案按需引入
  3. 考慮實際場景的性能需求