首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Memcached 客戶端分佈式演算法深度解析:一致性哈希前身與擴展策略

     編輯:關於.NET

核心問題:多伺服器如何分發 Key 實現負載均衡?

Memcached 客戶端支援多伺服器叢集,核心演算法在 SockIOPool.GetSock(key, hashCode) 中。本文剖析 .NET 客戶端 (Enyim/BeIT 等) 的分發邏輯、權重機制與遷移難題。

核心演算碼:取模分發

int hv = (hashCode != null) ? (int)hashCode : ComputeHash(key); // 三種哈希算法可選
int bucket = hv % _buckets.Count;  // 核心:哈希值對伺服器列表長度取模
if (bucket < 0) bucket += _buckets.Count; // 處理負數
SockIO sock = GetConnection((string)_buckets[bucket]);

關鍵屬性:_buckets 非去重列表

  • _buckets 為 ArrayList,**允許重複伺服器地址**
  • 權重實現:pool.SetWeights(new int[] {5, 2}) → 伺服器 A 出現 5 次,B 出現 2 次
  • 選中機率 ∝ 在 _buckets 中出現次數

三種哈希算法選項

算法枚舉實現特點
HashingAlgorithm.Nativekey.GetHashCode().NET 內建,版本間可能不一致
HashingAlgorithm.OldCompatibleHash自定義舊版相容算法跨版本穩定,舊客戶端相容
HashingAlgorithm.NewCompatibleHash自定義新版相容算法分佈更均勻,推薦新專案使用

鐵律:叢集內所有客戶端**必須使用相同哈希算法與相同伺服器列表順序**,否則會導致資料讀寫錯位、重複緩存。

容錯與故障轉移機制

int tries = 0;
while (tries++ <= _buckets.Count) {
    int bucket = hv % _buckets.Count;
    SockIO sock = GetConnection(_buckets[bucket]);
    if (sock != null) return sock;
    
    if (!_failover) return null; // 不故障轉移則放棄
    
    // 重新哈希:在 key 前加入嘗試次數,改變 hv
    hv += ComputeHash("" + tries + key);
}
return null;
  • 連線失敗時,修改哈希值重試下一個桶位
  • 最多嘗試 _buckets.Count 次(遍歷所有伺服器)

權重配置實戰

String[] serverlist = { "192.168.1.2:11211", "192.168.1.3:11211" };
int[] weights = { 5, 2 }; // 伺服器1權重5,伺服器2權重2
SockIOPool pool = SockIOPool.GetInstance();
pool.SetServers(serverlist);
pool.SetWeights(weights); // 內部展開 _buckets:5次IP1 + 2次IP2
pool.Initialize();

取模分發的致命弱點:節點變更導致大規模失效

場景

4 台伺服器 A/B/C/D 運行數月,C 突然宕機。客戶端仍按 4 台算法計算,原映射到 C 的 Key 全部失效,必須回源 DB。若移除 C 重新初始化,**所有 Key 映射關係改變**,A/B/D 上現有緩存全部失效,引發緩存雪崩。

解決方案對比

方案一:業務模組隔離 — 多客戶端實例

  • 不同業務模組(用戶日誌、相冊、音樂、基礎資料)使用**獨立客戶端實例**,各自配置專屬伺服器列表
  • 優點:故障隔離,單模組遷移不影響其他
  • 缺點:資源碎片化,無法統一彈性擴縮容

方案二:命名空間路由 — 擴展演算法

  • Key 格式:Namespace.Entity.Id(如 Sns.UserLogs.Log.999999)
  • 演算法解析命名空間,映射至預設伺服器組
  • 配置範例:
    
    // 概念代碼
    if (key.StartsWith("Sns.UserLogs")) return serverGroupA;
    if (key.StartsWith("Sns.Photos")) return serverGroupB;
    
  • 優點:邏輯清晰,業務語義與儲存物理拓撲對齊
  • 缺點:需修改客戶端核心邏輯,維護成本較高

方案三:一致性哈希 — 終極解法 (業界標準)

雖本文未提及,但現代 Memcached/Redis 客戶端(如 EnyimMemcached、StackExchange.Redis)均採用 **Consistent Hashing (Ketama 算法)**:

  • 伺服器與 Key 同樣映射至 2^32 環狀空間
  • Key 順時針尋找最近伺服器
  • 虛擬節點技術解決傾斜
  • 增減節點僅影響鄰近 Key,遷移量極小

總結與建議

  1. 理解取模分發原理與權重機制,是排查緩存不均、熱點問題的基礎。
  2. **生產環境強烈建議升級支援一致性哈希的客戶端庫**(EnyimMemcached 2.0+、StackExchange.Redis)。
  3. 若受限於舊庫,採用「命名空間路由」或「多客戶端隔離」作為過渡方案。
  4. 叢集變更(增減機器)務必在低峰期執行,並預熱新節點。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved