最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解一種用django_cache實現(xiàn)分布式鎖的方式

 更新時間:2019年09月01日 09:22:02   作者:知魚君  
這篇文章主要介紹了詳解一種用django_cache實現(xiàn)分布式鎖的方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

問題背景

在項目開發(fā)過程中,我遇到一個需求:對于某條記錄,一個用戶對它進行操作時會持續(xù)比較久,希望在一個用戶的操作期間,不允許有另一個用戶操作它,否容易會出現(xiàn)混亂。

在與同事們討論后,想通過加鎖的方式,起初想用redis鎖,但這樣會為項目增加別的依賴,因此轉而使用django-cache的緩存數(shù)據(jù)庫,來實現(xiàn)該功能。

資料查找

基于緩存實現(xiàn)分布式鎖,在網(wǎng)絡上查找了實現(xiàn)方式,大概可以總結為以下3種:

第一種鎖命令INCR

這種加鎖的思路是, key 不存在,那么 key 的值會先被初始化為 0 ,然后再執(zhí)行 INCR 操作進行加一。 然后其它用戶在執(zhí)行 INCR 操作進行加一時,如果返回的數(shù)大于 1 ,說明這個鎖正在被使用當中。

第二種鎖命令SETNX

這種加鎖的思路是,如果 key 不存在,將 key 設置為 value 如果 key 已存在,則 SETNX 不做任何動作

第三種鎖命令SET

上面兩種方法都有一個問題,會發(fā)現(xiàn),都需要設置 key 過期。那么為什么要設置key過期呢?如果請求執(zhí)行因為某些原因意外退出了,導致創(chuàng)建了鎖但是沒有刪除鎖,那么這個鎖將一直存在,以至于以后緩存再也得不到更新。于是乎我們需要給鎖加一個過期時間以防不測。

在實際編寫中,我綜合了第二種和第三種方式,即用鍵名來設置鎖,同時設置了過期時間,以防長時間占用。

另外,關于如何使用django-cache去使用數(shù)據(jù)庫緩存,相關的API整理如下:

from django.core.cache import caches
# 設置鎖和超時時間
cache.set('my_key', 'Initial value', 60)
# 獲取鎖
cache.get('my_key')
# 更新鎖
cache.add('add_key', 'New value')

代碼編寫

在經(jīng)過多次的迭代,并且對比了網(wǎng)上的各路寫法后,我結合django-cache的特性,最終總結了一套較為簡潔的寫法。

首先是一個CacheLock的類,初始化方法里可以傳執(zhí)行超時時間,和拿鎖等待的時間。CacheLock類的主要方法有兩個,一個是拿鎖的方法,一個是釋放鎖的方法。

拿鎖的方法中,鍵名根據(jù)操作的具體對象來定,鍵值為uuid值,超時時間默認為60s。一旦發(fā)現(xiàn)能拿到鎖,則返回uuid值。

釋放鎖的方法中,首先比較鍵值和uuid值是否一致,一致則釋放,避免因超時情況導致把其他的正在操作的鎖給釋放掉。

class CacheLock(object):
 def __init__(self, expires=60, wait_timeout=0):
 self.cache = cache
 self.expires = expires # 函數(shù)執(zhí)行超時時間
 self.wait_timeout = wait_timeout # 拿鎖等待超時時間

 def get_lock(self, lock_key):
 # 獲取cache鎖
 wait_timeout = self.wait_timeout
 identifier = uuid.uuid4()
 while wait_timeout >= 0:
  if self.cache.add(lock_key, identifier, self.expires):
  return identifier
  wait_timeout -= 1
  time.sleep(1)
 raise LockTimeout({'msg': '當前有其他用戶正在編輯該采集配置,請稍后重試'})

 def release_lock(self, lock_key, identifier):
 # 釋放cache鎖
 lock_value = self.cache.get(lock_key)
 if lock_value == identifier:
  self.cache.delete(lock_key)

另外,將緩存鎖寫成一個裝飾器,對需要加鎖的地方,添加上該裝飾器,則可以很輕松地實現(xiàn)鎖功能。

def lock(cache_lock):
 def my_decorator(func):
 def wrapper(*args, **kwargs):
  lock_key = 'bk_monitor:lock:xxx' # 具體的lock_key要根據(jù)調(diào)用時傳的參數(shù)而定
  identifier = cache_lock.get_lock(lock_key)
  try:
  return func(*args, **kwargs)
  finally:
  cache_lock.release_lock(lock_key, identifier)
 return wrapper
 return my_decorator

再舉一個實際調(diào)用中的例子:

@lock(CacheLock())
def f():
 pass

另外,我在設置緩存的key名的時候,會根據(jù)函數(shù)的具體操作對象,從而給裝飾器傳遞相應的參數(shù),這里就不再舉例了。

優(yōu)化改進

當然,實現(xiàn)以上功能需求一定還有別的更好的方式,關于鎖的實現(xiàn),網(wǎng)絡上有很多別的方式,比如基于zookeeper實現(xiàn)分布式鎖、基于數(shù)據(jù)庫實現(xiàn)分布式鎖等等,它們在可靠性或性能方面都各有長短,要根據(jù)具體場景進行取舍,所以還有非常多值得研究的地方。

我這里也只是拋磚引玉,歡迎拍磚~

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

最新評論

凭祥市| 鄂尔多斯市| 温宿县| 正安县| 鞍山市| 平度市| 绥德县| 同心县| 甘泉县| 涟源市| 高台县| 广德县| 克东县| 安阳县| 万州区| 迁西县| 北碚区| 新源县| 澎湖县| 额济纳旗| 永州市| 盐边县| 固安县| 白河县| 仙桃市| 荥经县| 祁连县| 东丰县| 灵武市| 揭阳市| 田阳县| 卢龙县| 黑山县| 赤城县| 漳平市| 墨竹工卡县| 彩票| 毕节市| 弥渡县| 宽城| 珲春市|