Redis分布式鎖詳解
分布式鎖是在分布式系統中實現互斥訪問共享資源的重要機制。Redis因其高性能和原子性操作特性,常被用來實現分布式鎖。
一、基礎實現方案
1. SETNX + EXPIRE方案(基本版)
# 加鎖
SETNX lock_key unique_value # 設置唯一標識
EXPIRE lock_key 10 # 設置過期時間# 解鎖
DEL lock_key # 刪除鍵
問題:
- 非原子性操作(SETNX和EXPIRE分開執行可能失敗)
- 可能誤刪其他客戶端的鎖
2. SET擴展命令方案(推薦)
# 原子性加鎖
SET lock_key unique_value NX PX 10000 # NX表示不存在才設置,PX設置毫秒級過期時間# 解鎖(Lua腳本保證原子性)
if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1])
elsereturn 0
end
優勢:
- 原子性加鎖
- 設置過期時間防止死鎖
- 通過唯一值避免誤刪
二、Redlock算法(多節點版)
當需要更高可靠性時,Redis作者提出的Redlock算法:
- 獲取當前時間(毫秒)
- 依次嘗試從N個獨立的Redis節點獲取鎖
- 計算獲取鎖總耗時(小于鎖過期時間)
- 當從多數節點(N/2+1)獲取成功,且總耗時小于鎖有效時間,才認為加鎖成功
- 若失敗,向所有節點發起解鎖請求
三、Java實現示例(Redisson)
// 1. 獲取鎖對象
RLock lock = redissonClient.getLock("myLock");try {// 2. 嘗試加鎖(參數:等待時間,鎖自動釋放時間,時間單位)boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS);if (isLocked) {// 3. 執行業務代碼doBusiness();}
} finally {// 4. 釋放鎖lock.unlock();
}
四、關鍵問題與解決方案
1. 鎖續期(Watchdog機制)
問題:業務執行時間超過鎖過期時間
方案:Redisson的看門狗會定期(默認10秒)檢查并延長鎖時間
2. 可重入性
方案:使用計數器記錄重入次數(Redisson已實現)
3. 鎖等待與公平性
方案:
- 實現鎖等待隊列
- 使用Redis的List結構模擬隊列
4. 主從切換問題
問題:主節點崩潰可能導致鎖丟失
方案:
- 使用Redlock多節點方案
- 或使用Redis的WAIT命令確保數據同步
五、生產環境建議
- 鎖命名規范:
業務:資源:操作
如order:123:pay
- 超時時間設置:
- 不宜過短(業務未完成鎖已釋放)
- 不宜過長(系統故障時恢復慢)
- 監控指標:
- 鎖獲取成功率
- 平均持有時間
- 等待隊列長度
- 降級方案:Redis不可用時切換本地鎖或數據庫鎖
六、與其他方案對比
方案 | 優點 | 缺點 | 適用場景 |
---|---|---|---|
Redis鎖 | 性能高、實現簡單 | 可靠性依賴Redis | 大多數分布式場景 |
Zookeeper鎖 | 可靠性高 | 性能較低 | 強一致性要求場景 |
數據庫鎖 | 無需額外組件 | 性能差、有死鎖風險 | 簡單場景 |
七、最佳實踐
- 始終為鎖設置合理的過期時間
- 使用唯一標識(UUID/線程ID)作為鎖值
- 釋放鎖前驗證持有者身份
- 考慮使用成熟的客戶端(如Redisson)而非自己實現
- 重要業務實現鎖續期機制
Redis分布式鎖在大多數場景下能很好工作,但對于對可靠性要求極高的場景,建議考慮Zookeeper或etcd等強一致性協調服務實現的分布式鎖。