python-redis-lock實現(xiàn)鎖自動續(xù)期的源碼邏輯
python-redis-lock簡介
python-redis-lock是一個python的第三方庫,基于Redis,封裝了分布式鎖的邏輯,提供了更高級的API來簡化鎖的獲取、保持和釋放過程。包括自動續(xù)期、鎖超時、重入鎖等功能。
相比于直接使用redis的setnx,避免了寫額外代碼來實現(xiàn)鎖的復雜邏輯。
鎖的續(xù)期
在使用分布式鎖的情況下,如果某個服務器A的業(yè)務還未執(zhí)行完(可能因為網絡擁塞、數(shù)據量突然變大等各種原因),但是鎖過期了,可能引發(fā)額外的問題。例如另一臺服務器B發(fā)現(xiàn)鎖釋放了,于是加鎖并開始執(zhí)行業(yè)務,從而導致出現(xiàn)問題。
更有可能導致服務器A業(yè)務在執(zhí)行完后去釋放鎖時,意外地釋放了服務器B加的鎖,導致服務器C進入,從而引發(fā)問題(在未使用唯一性ID表示加鎖者的情況下)。
所以對鎖的過期時間來續(xù)期是很有必要的,它確保了鎖在業(yè)務執(zhí)行完后才釋放。
python-redis-lock實現(xiàn)自動續(xù)期的源碼分析
首先在配置python-redis-lock實例時,有兩個參數(shù):expire int 和 auto_renewal boolean。
expire:鎖過期時間,單位為秒。
auto_renewal:是否開啟自動續(xù)期鎖。
python-redis-lock實例在初始化時,針對這兩個參數(shù)的源碼:
class Lock(object): def __init__(self, redis_client, name, expire=None, auto_renewal=False, ...): ... if expire: expire = int(expire) ... self._expire = expire self._lock_renewal_interval = float(expire) * 2/3 if auto_renewal else None ...
假設我們設置了一個過期時間30秒,開啟自動續(xù)期的Lock實例,則self._expire=30秒,self._lock_renewal_interval=20秒。
當在代碼層調用Lock.acquire方法時,判斷self._lock_renewal_interval是否為空,如果不為空,則開啟鎖的自動續(xù)期(這里省略了一些內容,因為只關注續(xù)期的代碼實現(xiàn)邏輯):
class Lock(object): def acquire(self, blocking=True, timeout=None): ... if self._lock_renewal_interval is not None: self._start_lock_renewer()
在self._start_lock_renewer方法中,基于python的threading模塊,開啟了一個鎖自動更新線程self._lock_renewal_thread。這個線程執(zhí)行self._lock_renewer方法
def _start_lock_renewer(self):
...
self._lock_renewal_stop = threading.Event() # threading.Event()用于線程間的協(xié)調
self._lock_renewal_thread = threading.Thread(
group=None,
target=self._lock_renewer,
kwargs={
'name': self._name,
'lockref': weakref.ref(self), # 對Lock實例的弱引用
'interval': self._lock_renewal_interval,
'stop': self._lock_renewal_stop,
},
)
self._lock_renewal_thread.demon = True
self._lock_renewal_thread.start()weakref.ref(self)創(chuàng)建當前類實例(self)的弱引用,并將其存儲在變量 lockref 中。使用 weakref.ref 創(chuàng)建的弱引用不會阻止對象被垃圾回收。
在self._lock_renewer方法中,首先用了while循環(huán)來每次等待20秒(interval=20)再執(zhí)行循環(huán)體:如果弱引用對象(即Lock實例本身)沒有被垃圾回來,則執(zhí)行續(xù)期的方法(lock.extend):
def _lock_renewer(name, lockref, interval, stop): while not stop.wait(timeout=interval): ... lock: "Lock" = lockref() if lock is None: break lock.extend(expire=lock._expire)
在self.extend方法中,執(zhí)行了一個Lua腳本來更新鎖的過期時間。
在滿足self._name和self._signal的緩存鍵值存在且鎖未過期的情況下,將當前鎖的過期時間重置為expire(30秒)。
def extend(self. expire=None):
if expire:
expire = int(expire)
error = self.extend_script(
client=self._client, # 對redis的連接
keys=(self._name, self._signal),
args=(self._id, expire))
...
# self.extend_script的執(zhí)行邏輯:
EXTEND_SCRIPT = b"""
if redis.call("get", KEYS[1]) ~= ARGV[1] then
return 1
elseif redis.call("ttl", KEYS[1]) < 0 then
return 2
else
redis.call("expire", KEYS[1], ARGV[2])
return 0
end
"""
cls.extend_script = redis_client.register_script(EXTEND_SCRIPT)以上就是python-redis-lock實現(xiàn)鎖自動續(xù)期的源碼邏輯。
其中用到了多線程threading、弱引用weakref和Lua腳本等相關知識。
到此這篇關于python-redis-lock是如何實現(xiàn)鎖自動續(xù)期的的文章就介紹到這了,更多相關python-redis-lock鎖自動續(xù)期內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
python3 numpy中數(shù)組相乘np.dot(a,b)運算的規(guī)則說明
這篇文章主要介紹了python3 numpy中數(shù)組相乘np.dot(a,b)運算的規(guī)則說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03
Python+tkinter實現(xiàn)一個繪圖風格控件
這篇文章主要為大家詳細介紹了Python如何利用tkinter實現(xiàn)一個簡單的繪圖風格控件,文中的示例代碼講解詳細,感興趣的小伙伴可以學習一下2023-09-09
利用Python高效實現(xiàn)Word轉HTML的全流程方案
在日常工作中,我們可能會遇到將大量 Word 文檔(.docx)轉換為 HTML 文件的需求,比如為了將文檔內容展示到網頁上,或者實現(xiàn)文檔在線閱讀功能,所以本文將給大家介紹如何利用Python高效實現(xiàn)Word轉HTML,需要的朋友可以參考下2025-11-11
解決jupyter notebook import error但是命令提示符import正常的問題
這篇文章主要介紹了解決jupyter notebook import error但是命令提示符import正常的問題,具有很好的參考2020-04-04
Python?Generator生成器函數(shù)基本概念及高級用途技巧示例
這篇文章主要為大家介紹了Python?Generator生成器函數(shù)基本概念及高級用途技巧示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
Pytorch 使用opnecv讀入圖像由HWC轉為BCHW格式方式
這篇文章主要介紹了Pytorch 使用opnecv讀入圖像由HWC轉為BCHW格式方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06

