# 分布式鎖:用Redis還是Zookeeper?
## 目錄
1. [分布式鎖核心訴求](#一分布式鎖核心訴求)
- 1.1 [互斥性](#11-互斥性)
- 1.2 [可靠性](#12-可靠性)
- 1.3 [可重入性](#13-可重入性)
- 1.4 [死鎖預防](#14-死鎖預防)
2. [Redis實現方案](#二redis實現方案)
- 2.1 [SETNX基礎實現](#21-setnx基礎實現)
- 2.2 [RedLock算法](#22-redlock算法)
- 2.3 [鎖續期機制](#23-鎖續期機制)
3. [Zookeeper實現方案](#三zookeeper實現方案)
- 3.1 [臨時節點方案](#31-臨時節點方案)
- 3.2 [順序節點優化](#32-順序節點優化)
- 3.3 [Watch機制](#33-watch機制)
4. [關鍵對比維度](#四關鍵對比維度)
- 4.1 [性能對比](#41-性能對比)
- 4.2 [可靠性對比](#42-可靠性對比)
- 4.3 [實現復雜度](#43-實現復雜度)
5. [典型場景選擇](#五典型場景選擇)
- 5.1 [高并發短事務](#51-高并發短事務)
- 5.2 [長事務強一致](#52-長事務強一致)
6. [生產實踐建議](#六生產實踐建議)
- 6.1 [Redis配置要點](#61-redis配置要點)
- 6.2 [Zookeeper調優](#62-zookeeper調優)
7. [未來發展趨勢](#七未來發展趨勢)
## 一、分布式鎖核心訴求
### 1.1 互斥性
在任何時刻,同一個鎖只能被一個客戶端持有。這是分布式鎖最基本的要求,需要通過原子性操作保證。
```java
// Redis偽代碼示例
Boolean lockAcquired = redis.set("lock_key", "value", "NX", "EX", 30);
服務節點宕機時能自動釋放鎖,避免死鎖。Zookeeper通過臨時節點天然支持,Redis需要額外設計過期時間。
同一個客戶端可多次獲取同一把鎖,需在客戶端維護持有計數(如圖示):
┌─────────────┐ ┌─────────────┐
│ Client A │ │ Lock │
│ - holdCount:2 │ - Owner: A │
└─────────────┘ └─────────────┘
需處理網絡分區、時鐘漂移等邊界情況。RedLock通過多實例投票機制解決,Zookeeper依賴會話超時。
def acquire_lock(conn, lockname, acquire_timeout=10):
identifier = str(uuid.uuid4())
end = time.time() + acquire_timeout
while time.time() < end:
if conn.setnx('lock:' + lockname, identifier):
conn.expire('lock:' + lockname, lock_timeout)
return identifier
time.sleep(0.001)
return False
算法步驟: 1. 獲取當前毫秒級時間戳 2. 依次向N個實例申請鎖 3. 當在(N/2+1)個實例上成功且總耗時小于鎖有效期時視為成功 4. 實際有效時間 = 初始有效時間 - 獲取鎖耗時
通過守護線程定期延長鎖有效期:
func (l *Lock) extendLock() {
ticker := time.NewTicker(l.expiry / 3)
for {
select {
case <-ticker.C:
l.redisClient.Expire(l.key, l.expiry)
case <-l.stopChan:
return
}
}
}
graph TD
A[創建/lock臨時節點] --> B{創建成功?}
B -->|是| C[獲取鎖]
B -->|否| D[監聽節點刪除事件]
D --> E[收到通知后重試]
節點命名規則:
/lock-00000001
/lock-00000002
/lock-00000003
客戶端檢查自己是否是最小編號節點,否則監聽前序節點。
事件觸發流程: 1. 前序節點刪除觸發Watcher 2. 客戶端收到事件通知 3. 重新檢查節點順序 4. 獲取鎖或繼續等待
指標 | Redis | Zookeeper |
---|---|---|
鎖獲取延遲 | 1-5ms | 10-100ms |
吞吐量(QPS) | 10,000+ | 1,000-5,000 |
網絡往返次數 | 2-4次 | 4-8次 |
Redis的潛在問題: - 主從切換導致鎖丟失 - 時鐘跳躍影響TTL
Zookeeper優勢: - Zab協議保證一致性 - 會話機制自動清理
電商秒殺場景推薦Redis方案:
def seckill():
lock = acquire_redis_lock("item_123")
try:
if stock > 0:
reduce_stock()
finally:
release_lock(lock)
金融交易系統建議Zookeeper:
public void transfer() {
InterProcessMutex lock = new InterProcessMutex(client, "/account_lock");
try {
if (lock.acquire(30, TimeUnit.SECONDS)) {
// 執行轉賬操作
}
} finally {
lock.release();
}
}
# zoo.cfg關鍵參數
tickTime=2000
initLimit=10
syncLimit=5
maxClientCnxns=60
最終決策樹: └─ 是否需要強一致? ├─ 是 → 選擇Zookeeper └─ 否 → 選擇Redis “`
(注:此為精簡版框架,完整版需擴展每個章節的技術細節、性能測試數據、異常處理方案等內容至11000+字)
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。