- [客戶端一]讀取[key1],值爲[1]
- [客戶端二]讀取[key1],值爲[1]
- [客戶端一]將[key1]自增1,值爲[2]
- [客戶端二]將[key1]自增1,值爲[2]
- [客戶端一]輸出[key1],值爲[2]
- [客戶端二]輸出[key2],值爲[2]
- [客戶端一]、[客戶端二]的R(讀)、M(自增)、W(寫)三個操作作爲一個原子操作執行
- [客戶端]對RMW整個操作過程加鎖,加鎖期間其它客戶端不能對[key1]執行寫操作
- Lua腳本
加鎖主要是將多客戶端線程調用相同業務方法轉換爲串行化處理,比如多個客戶端調用同一個方法對某個鍵自增(這裏不考慮其它方法或業務會對該鍵同時執行自增操作) 調用SETNX命令對某個鍵進行加鎖(如果獲取鎖則執行後續RMW操作,否則直接返回未獲取鎖提示) 執行RMW業務操作 調用DEL命令刪除鎖
假如某個客戶端在執行了SETNX命令加鎖之後,在後面操作業務邏輯時發生了異常,沒有執行 DEL 命令釋放鎖。
該鎖就會一直被這個客戶端持有,其它客戶端無法拿到鎖,導致其它客戶端無法執行後續操作。
解決思路:給鎖變量設置一個過期時間,到期自動釋放鎖
SET key value [EX seconds | PX milliseconds] [NX]
如果客戶端 A 執行了 SETNX 命令加鎖後,客戶端 B 執行 DEL 命令釋放鎖,此時,客戶端 A 的鎖就被誤釋放了。如果客戶端 C 正好也在申請加鎖,則可以成功獲得鎖。 解決思路:加鎖操作時給每個客戶端設置一個唯一值(比如UUID),唯一值可以用來標識當前操作的客戶端。在釋放鎖操作時,客戶端判斷當前鎖變量的值是否和唯一標識相等,只有在相等的情況下,才能釋放鎖。(同一客戶端線程中加鎖、釋放鎖) SET lock_key unique_value NX PX 10000
local current current = redis.call("incr",KEYS[1])
if tonumber(current) == 1
then redis.call("expire",KEYS[1],60)
end
redis-cli --eval lua.script keys , args