環境:python3
實現原理:WATCH, MULTI, EXEC, DISCARD事務機制實現分佈式鎖
MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事務的基礎。
事務可以一次執行多個命令, 並且帶有以下兩個重要的保證:
-
事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。
-
事務是一個原子操作:事務中的命令要麼全部被執行,要麼全部都不執行。
EXEC 命令負責觸發並執行事務中的所有命令:
import uuid
import redis
import time
redis_client=redis.Redis(host='localhost', port=6379)
# 獲取一個分佈式鎖
def acquire_lock(lock_name, acquire_time=10, time_out=10):
# 生成唯一id
identifier = str(uuid.uuid4())
# 客戶端獲取鎖的結束時間
end = time.time() + acquire_time
# key
lock_names = "lock_name:" + lock_name
while time.time() < end:
# setnx(key,value) 只有key不存在情況下,將key的值設置爲value,若key存在則不做任何動作,返回True和False
if redis_client.setnx(lock_names, identifier):
# 設置鍵的過期時間,過期自動剔除,釋放鎖
redis_client.expire(lock_names, time_out)
return identifier
# 當鎖未被設置過期時間時,重新設置其過期時間
elif redis_client.ttl(lock_names)==-1:
redis_client.expire(lock_names, time_out)
time.sleep(0.001)
return False
# 鎖的釋放
def release_lock(lock_name, identifire):
lock_names = "lock_name:" + lock_name
pipe = redis_client.pipeline(True)
while True:
try:
# 通過watch命令監視某個鍵,當該鍵未被其他客戶端修改值時,事務成功執行。當事務運行過程中,發現該值被其他客戶端更新了值,任務失敗
pipe.watch(lock_names)
if pipe.get(lock_names) == identifire: # 檢查客戶端是否仍然持有該鎖
# multi命令用於開啓一個事務,它總是返回ok
# multi執行之後, 客戶端可以繼續向服務器發送任意多條命令, 這些命令不會立即被執行, 而是被放到一個隊列中, 當 EXEC 命令被調用時, 所有隊列中的命令纔會被執行
pipe.multi()
# 刪除鍵,釋放鎖
pipe.delete(lock_names)
# execute命令負責觸發並執行事務中的所有命令
pipe.execute()
return True
pipe.unwatch()
break
except redis.exceptions.WatchError:
# # 釋放鎖期間,有其他客戶端改變了鍵值對,鎖釋放失敗,進行循環
pass
return False