精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

基于 Redis 構建簡單分布式鎖的局限

數據庫 Redis
Redis 官方為用戶提供了 Lua 腳本支持,用戶可以向 Redis 服務器發送 Lua 腳本執行自定義的邏輯,Redis 服務器會單線程原子性的執行 Lua 腳本。

簡介

業務中,常有分布式鎖的需求,常見的解決方案便是基于 Redis 作為中心節點實現偽分布式效果,因為存在中心節點,所以我將其定義為偽分布式。

回歸主題,這篇文章,主要理一下,基于 Redis 實現簡單分布式鎖的一些問題,Redis 支持 RedLock(紅鎖)等復雜的實現,以后的文章再討論。

基于 SETNX 命令實現分布式鎖

使用 SETNX 命令構建分布式鎖是最常見的實現方式,具體而言:

1. 通過 SETNX key value 向 Redis 新增一個值,SETNX 命令只有當 key 不存在時,才會插入值并返回成功,否則返回失敗,而 KEY 便可以作為分布式鎖的鎖名,通?;跇I務來決定該鎖名;

2. 通過 DEL key 命令刪除 key,從而實現釋放鎖的效果,當鎖釋放后,其他線程才可以通過 SETNX 獲得鎖(相同的 KEY);

3. 利用 EXPIRE key timeout 對 KEY 設置超時時間,從而實現鎖的超時自動釋放的效果,避免資源一直被占用。

redis-py (https://github.com/redis/redis-py) 這個庫便基于這種形式實現 Redis 分布式鎖,將其源碼中相關代碼復制出來,如下:

# 獲得分布式鎖
def do_acquire(self, token):
# 利用SETNX實現分布式鎖
if self.redis.setnx(self.name, token):
if self.timeout:
timeout = int(self.timeout * 1000) # 轉成毫秒
# 設置分布式超時時間
self.redis.pexpire(self.name, timeout)
return True
return False

# 釋放分布式鎖
def do_release(self, expected_token):
name = self.name

def execute_release(pipe):
lock_value = pipe.get(name)
if lock_value != expected_token:
raise LockError("Cannot release a lock that's no longer owned")
# 利用DEL value實現鎖的釋放
pipe.delete(name)

self.redis.transaction(execute_release, name)

這種方式,存在一些問題,下文進行簡單的分析。

SETNX 與 EXPIRE 非原子性問題

SETNX 與 EXPIRE 是兩個操作,在 Redis 中不是原子操作。

如果 SETNX 成功(即獲得鎖),但在通過 EXPIRE 設置鎖超時時間時,服務器掛機、網絡中斷等問題,導致 EXPIRE 沒有成功執行,此時鎖就變成了沒有超時時間的鎖了,如果業務邏輯沒有處理好鎖的釋放,則容易出現死鎖。

Redis 官方考慮到了這種情況,讓 SET 命令可以直接設置 Timeout 并實現 SETNX 效果,SET 支持的語法變為:SETEX key value NX timeout,這樣就不再需要通過 EXPIRE 設置超時時間,從而實現原子性了。

當然,在 Redis 官方還沒有實現這一功能時,很多開源庫也考慮到了這個問題,然后使用 Lua 腳本實現 SETEX 與 EXPIRE 兩個操作的原子性。

因為用戶希望自定義若干指令來完成特定的業務,Redis 官方為這些用戶提供了 Lua 腳本支持,用戶可以向 Redis 服務器發送 Lua 腳本執行自定義的邏輯,Redis 服務器會單線程原子性的執行 Lua 腳本。

鎖誤解除

鎖誤解除也是常見的情況。

假設現在有 A、B 兩個線程在工作并競爭同一把鎖,線程 A 獲得了鎖,并將鎖的超時時間設置完成 30s,但線程 A 在處理業務邏輯時,因為數據庫 SQL 超時,原本 20s 就可以完成的任務,現在需要 40s 才能完成,當線程 A 花費 30s 時,鎖會自動釋放,此時線程 B 會獲得這把鎖,當線程 A 處理完業務邏輯時,會通過 DEL 去釋放鎖,此時釋放的是線程 B 的鎖,直觀如下圖所示:

解決方法便是添加唯一標識,在釋放鎖時,校驗 KEY 對應的唯一標識是否被當前線程持有,在 redis-py 中,通過 UUID 生成了當前線程的唯一標識 token,并在釋放鎖時,判斷當前線程是否擁有相同的 token,相關代碼如下 (你會發現與上面復制出來的代碼不同,這是因為舊文中使用的 redis-py 版本為 2.10.6,現在使用的 redis-py 版本為 3.5.3,相關的 bug 已經被修改了,舊文的代碼,只是為了引出問題):

class Lock(object):
def __init__(self, redis, name, timeout=None, sleep=0.1,
blocking=True, blocking_timeout=None, thread_local=True):
# 線程本地存儲
self.local = threading.local() if self.thread_local else dummy()
self.local.token = None


def acquire(self, blocking=None, blocking_timeout=None, token=None):
sleep = self.sleep
if token is None:
# 基于UUID算法生成唯一token
token = uuid.uuid1().hex.encode()
# 省略剩余代碼...

def do_acquire(self, token):
if self.timeout:
timeout = int(self.timeout * 1000)
else:
timeout = None
# Token會通過set方法存入到Redis中
if self.redis.set(self.name, token, nx=True, px=timeout):
return True
return False

redis-py 基于 uuid 庫生成 token,并將其存到當前線程的本地存儲空間中(獨立于其他線程),在釋放時,判斷當前線程的 token 與加鎖時存儲的 token 釋放相同,redis-py 中利用 Lua 來實現這個過程,相關代碼如下:

def release(self):
"Releases the already acquired lock"
# 從線程本地存儲中獲得token
expected_token = self.local.token
if expected_token is None:
raise LockError("Cannot release an unlocked lock")
self.local.token = None
self.do_release(expected_token)

def do_release(self, expected_token):
# 利用Lua來釋放鎖,并實現判斷token是否相同的邏輯
if not bool(self.lua_release(keys=[self.name],
args=[expected_token],
client=self.redis)):
raise LockNotOwnedError("Cannot release a lock"
" that's no longer owned")

其中 lua_release 變量具體的值為:

LUA_RELEASE_SCRIPT = """
local token = redis.call('get', KEYS[1])
if not token or token ~= ARGV[1] then
return 0
end
redis.call('del', KEYS[1])
return 1
"""

上述 Lua 代碼中,通過 get 獲得 KEY 的 value,這個 value 就是 token,然后判斷與傳入的 token 是否相同,不相同的話,便不會執行 DEL 命令,即不會釋放鎖。

鎖超時導致的并發

這種情況與鎖誤解除類似,同樣假設有線程 A、B,線程 A 獲得鎖并設置過期時間 30s,當線程 A 執行時間超過 30s 時,鎖過期釋放,此時線程 B 獲得鎖,如果線程 A 與線程 B 是在業務上是有順序依賴的,此時出現了并發情況,便會導致業務結果的錯誤,直觀如下圖:

線程 A、B 同時執行導致業務錯誤是我們不希望出現的,對于這種情況,有兩種解決方案:

1. 增大鎖的過期時間,讓業務邏輯有充足的執行時間;

2. 添加守護線程,當鎖過期時,添加過期時間

建議使用第一種方案,簡單直接,此外,可以添加單一線程,對 Redis 的 key 做監控,對于時長特別長的 key,做監控報警。

輪詢等待的效率問題

依舊是線程 A、B,當線程 A 獲得鎖時,線程 B 也想獲得鎖,此時就需要等待,直到線程 A 釋放鎖或者鎖過期自己釋放了,看 redis-py 的源碼,其等待的邏輯就是一個死循環,相關代碼如下:

def acquire(self, blocking=None, blocking_timeout=None, token=None):
# ...省略部分代碼

# 死循環等待獲得鎖
while True:
if self.do_acquire(token):
self.local.token = token
return True
if not blocking:
return False
next_try_at = mod_time.time() + sleep
if stop_trying_at is not None and next_try_at > stop_trying_at:
return False
# 阻塞睡眠一段時間
mod_time.sleep(sleep)

簡單而言,這種方式就是在客戶端輪詢,未獲得鎖時,就等待一段時間再嘗試去獲得鎖,直到成功獲得鎖或等待超時,這種方式實現簡單,但當并發量比較大時,輪詢的方式會耗費比較多資源,影響服務器性能。

更好的一種方式是使用 Redis 發布訂閱功能,當線程 B 獲取鎖失敗時,訂閱鎖釋放的消息,當線程 A 執行完業務釋放鎖時,會發送鎖釋放信息,線程 B 獲得信息后,再去獲取鎖,這樣就不需要一直輪詢了,而是直接休眠等待到鎖釋放消息則可。

Redis 集群主從切換

比較復雜的項目會使用多個 Redis 服務構建集群,Redis 集群采用主從方式部署,簡單而言,通過算法選擇出 Redis 集群中的主節點,所有寫操作都會落到主節點上,主節點會將指令記錄在 buffer 中,再通過異步的方式將 buffer 中的指令同步到其他從節點,從節點執行相同的指令,便會獲得與主節點相同的數據結構。

當我們基于 Redis 集群來構建分布式鎖時,可能會出現主從切換導致鎖丟失的問題。

依舊以例子來說明,客戶端 A 通過 Redis 集群成功加鎖,這個操作首先會發生在主節點,但由于某些問題,當前 Redis 集群的主節點 down 了,此時根據相應的算法,Redis 集群會從從節點中選出新的主節點,這個過程對客戶端 A 而言是透明的,但如果在主從切換時,客戶端 A 在舊主節點加鎖的指令還未同步它就 down 了,那么新的主節點就不會有客戶端 A 加速的信息,此時,如果有新的客戶端 B 要加鎖,便可以輕松加上。

Redis 集群腦裂腦裂

這次確實挺抽象的,簡單而言,Redis 集群中因為網絡問題,某些從節點無法感知到主節點了,此時這些從節點會認為主節點 down 了,便會選出新的主節點,而客戶端卻可以連接上兩個主節點,從而會出現兩個客戶端擁有同一把鎖的情況。

結尾復雜分布式系統中鎖的問題一直是個設計難題,學無止境呀。

責任編輯:武曉燕 來源: 懶編程
相關推薦

2019-06-19 15:40:06

分布式鎖RedisJava

2021-06-03 00:02:43

RedisRedlock算法

2021-07-30 00:09:21

Redlock算法Redis

2017-10-24 11:28:23

Zookeeper分布式鎖架構

2023-09-22 08:00:00

分布式鎖Redis

2017-04-13 10:51:09

Consul分布式

2022-06-16 08:01:24

redis分布式鎖

2023-08-21 19:10:34

Redis分布式

2022-01-06 10:58:07

Redis數據分布式鎖

2019-02-26 09:51:52

分布式鎖RedisZookeeper

2021-11-01 12:25:56

Redis分布式

2022-10-27 10:44:14

分布式Zookeeper

2022-03-08 15:24:23

BitMapRedis數據

2020-07-15 09:20:48

MyCatMySQL分布式

2023-03-01 08:07:51

2024-10-07 10:07:31

2020-11-16 12:55:41

Redis分布式鎖Zookeeper

2022-09-19 08:17:09

Redis分布式

2021-06-16 07:56:21

Redis分布式

2024-04-01 05:10:00

Redis數據庫分布式鎖
點贊
收藏

51CTO技術棧公眾號

久热精品在线| 精品丝袜久久| 一区二区在线看| 国产精品久久久一区二区三区| 日韩av女优在线观看| 小嫩嫩12欧美| 欧美高清性hdvideosex| 日韩伦理在线免费观看| 国产69精品久久app免费版| 国内精品第一页| 97国产在线观看| 麻豆视频免费在线播放| 亚洲日本va午夜在线电影| 欧美性xxxx18| www.一区二区.com| 激情在线视频| jlzzjlzz亚洲日本少妇| 国产欧美一区二区| 日本一级黄色大片| 一本一道久久a久久精品蜜桃| 亚洲国产精品嫩草影院久久| 九九热精品国产| 亚洲三级欧美| 亚洲自拍偷拍欧美| 一区二区视频在线免费| 日韩电影免费| 成人午夜精品在线| 92裸体在线视频网站| 9i精品福利一区二区三区| 欧美日韩精品| 久久伊人免费视频| 亚洲黄色免费视频| 亚洲动漫在线观看| 精品成人在线观看| 波多野结衣电影免费观看| 欧美成人家庭影院| 日本韩国欧美三级| 国产精品秘入口18禁麻豆免会员| 午夜激情在线| 亚洲免费伊人电影| 亚洲精品国产系列| 国产一级在线| 国产亚洲午夜高清国产拍精品| 韩国精品一区二区三区六区色诱| hs视频在线观看| 久久 天天综合| 国产精品美女av| 亚洲性猛交富婆| 久久国产免费| 国产成人精品av在线| 亚洲 欧美 视频| 一区二区三区高清视频在线观看| 欧美激情免费在线| 九九热视频精品| 欧美区日韩区| 欧美激情2020午夜免费观看| 亚洲国产精品免费在线观看| 一区二区国产在线| 久久中文字幕视频| 国产成人无码aa精品一区| 亚洲破处大片| 欧美精品videos| 国产在线拍揄自揄拍| 亚洲成人资源| 91成人在线观看国产| 在线观看中文字幕视频| 久久久精品网| 国产免费亚洲高清| 国产特黄一级片| 国产成人av资源| 国产美女99p| 日本天堂在线| 欧美激情一区二区在线| 免费久久久久久| av免费看在线| 欧美日韩美女在线观看| 37pao成人国产永久免费视频| 亚洲精品555| 欧美高清性hdvideosex| youjizz.com国产| 网红女主播少妇精品视频| 亚洲人成免费电影| 亚洲毛片亚洲毛片亚洲毛片| 51精产品一区一区三区| 欧美激情国内偷拍| 天堂网视频在线| 狠狠色综合播放一区二区| 成人免费看片网址| 国内在线免费高清视频| 亚洲视频在线一区观看| 人妻av中文系列| 8av国产精品爽爽ⅴa在线观看 | 一个色综合导航| 搜索黄色一级片| 亚洲人www| 国产精品中文字幕久久久| 亚洲av无码乱码在线观看性色| 26uuu亚洲综合色欧美 | 91caoporm在线视频| 亚洲精品成人悠悠色影视| av片中文字幕| 看亚洲a级一级毛片| 日韩精品在线播放| 九九热最新地址| 日韩精品每日更新| av色综合网| av二区在线| 亚洲va国产天堂va久久en| 日韩av片网站| 日韩高清影视在线观看| 美女999久久久精品视频| 一级黄色av片| 成人免费毛片a| 青春草在线视频免费观看| 色老头在线一区二区三区| 3d动漫精品啪啪一区二区竹菊| 色噜噜在线观看| 欧美激情一区| 91色p视频在线| 国产资源在线播放| 午夜欧美一区二区三区在线播放| 欧美国产日韩另类| 精品国产午夜| 51精品在线观看| 欧日韩在线视频| 亚洲黄色av一区| 天堂在线中文在线| 欧美禁忌电影网| 欧美中文字幕视频在线观看| 成人午夜免费福利| 亚洲免费在线播放| 亚洲欧美日韩三级| 成人一级毛片| 国产精品xxxxx| 黄色av网站在线看| 欧美日韩亚洲一区二区三区| 高清中文字幕mv的电影| 欧美日本精品| www.一区二区三区| 影音先锋中文在线视频| 91精品国产aⅴ一区二区| 国产精品综合激情| 奇米亚洲午夜久久精品| 日日噜噜噜噜夜夜爽亚洲精品| 亚洲人体影院| 亚洲天堂影视av| 国产第一页在线观看| 久久精品视频一区二区三区| 久久精品国产精品亚洲色婷婷| 黑色丝袜福利片av久久| 久久人人爽国产| 黄频在线免费观看| 五月激情综合婷婷| 波多野结衣先锋影音| 国产美女一区| 欧美一区二区影视| 欧美在线va视频| 色妞欧美日韩在线| 亚洲无码精品在线观看| 亚洲欧美色图小说| 国产精品91av| 国产精品一二| 亚洲欧美日韩精品在线| av日韩一区| 久久久久久国产精品美女| 人妻丰满熟妇av无码区hd| 色综合婷婷久久| 在线观看免费黄色网址| 国产麻豆视频一区二区| 欧妇女乱妇女乱视频| 欧美成人基地| 国产精品69av| 黄色av网站在线播放| 欧美r级电影在线观看| 国产一区二区99| 国产女同互慰高潮91漫画| 中文字幕66页| 影音先锋中文字幕一区| 日本一区二区三区视频在线观看 | 国产精品一区二区av| 亚洲福利影院| 久久精品成人一区二区三区| www.天天干.com| 精品久久久久久国产91| 黄色国产在线播放| 国产成人综合亚洲网站| 久久久999视频| 日韩欧美不卡| 精品国产日本| 不卡精品视频| 欧美一级高清免费播放| 国产精品久久麻豆| 亚洲精品国产品国语在线 | 精品第一国产综合精品aⅴ| av一级在线观看| 亚洲免费观看视频| 91精品人妻一区二区三区蜜桃欧美| 精品在线播放午夜| 免费看国产曰批40分钟| 国产精品91一区二区三区| 国产欧美一区二区视频| 国产资源一区| 欧美一区二粉嫩精品国产一线天| 麻豆免费在线视频| 亚洲免费中文字幕| 亚洲国产精品视频在线| 欧美日韩一区中文字幕| 九九热国产视频| 中文字幕在线不卡| 伊人网伊人影院| 懂色av一区二区三区免费看| 91网址在线播放| 99国产精品| av动漫在线播放| 欧美成人激情| 欧美精品一区二区三区四区五区| 五月亚洲婷婷| 91免费电影网站| 四虎4545www精品视频| 欧美激情在线观看| 成人av黄色| 日韩亚洲精品电影| 黄视频在线播放| 日韩国产在线看| 蜜桃久久一区二区三区| 欧美一区二区三区啪啪| 在线免费看av片| 日本精品视频一区二区| 西西44rtwww国产精品| 亚洲一区二区三区中文字幕 | 国产精品成人av| 色综合久久av| 国产精品三级| 欧美成人蜜桃| 日韩精品丝袜美腿| 国产精品免费区二区三区观看| 狂野欧美xxxx韩国少妇| 亚洲自拍小视频| 国产美女精品视频免费播放软件| 国产精品视频自拍| 日韩精品三区| 国产成人精品免高潮在线观看| 蜜桃在线视频| 91wwwcom在线观看| 欧美亚洲日本精品| 日产精品99久久久久久| 少妇视频一区| 欧美中文在线观看| 欧美aaa视频| 国产精品爽爽爽爽爽爽在线观看| 日产精品一区| 国产乱肥老妇国产一区二| 亚洲午夜剧场| 97中文在线| 国产成人tv| 久精品国产欧美| 欧美美乳视频| 亚洲三区四区| 一区二区中文字| 成人免费视频91| 亚洲欧美日韩国产一区| aaaaaa亚洲| 久久精品国产免费| 伦伦影院午夜理论片| 国产91富婆露脸刺激对白| 日韩综合第一页| 久久综合色鬼综合色| 欧美成人国产精品一区二区| 中文字幕国产一区| 亚洲国产123| 亚洲国产精品尤物yw在线观看| 日干夜干天天干| 欧美午夜一区二区三区| 国产麻豆免费观看| 亚洲国产天堂网精品网站| 国产最新视频在线| 久久综合亚洲社区| 国产h片在线观看| 国产精品偷伦一区二区| 麻豆视频久久| 日本不卡二区| 午夜精品影院| 情侣黄网站免费看| 国产九色精品成人porny| 黄色工厂在线观看| 成人欧美一区二区三区| 97免费在线观看视频| 欧美系列亚洲系列| 韩国av免费在线| 中文字幕久精品免费视频| 特级毛片在线| 国产精品久久久久久亚洲调教| 欧美黄色一级| 日韩精品一区二区三区外面| 国产精品大片| www亚洲成人| 99久久久精品| 中文字幕在线2021| 色综合中文字幕国产| www.国产精品视频| 在线观看中文字幕亚洲| а√在线中文在线新版| 国产一区玩具在线观看| 亚洲永久精品唐人导航网址| 50度灰在线观看| 日韩国产欧美三级| 亚洲图片综合网| 亚洲猫色日本管| 波多野结衣爱爱| 亚洲第一页自拍| 国产素人视频在线观看| 国产精品人成电影| 羞羞色国产精品网站| 国产精品视频二| 国内精品伊人久久久久av影院| 欧洲av一区二区三区| 精品国产91久久久久久老师| 99精品视频免费看| 日韩视频精品在线| 精品国产欧美日韩一区二区三区| 久久久久久草| 亚洲伦伦在线| 亚洲少妇中文字幕| 亚洲人成在线观看一区二区| 欧美 亚洲 另类 激情 另类| 亚洲精品在线视频| 国产精品电影| 国产日韩欧美一区二区三区四区| 自拍日韩欧美| 香蕉视频xxxx| 亚洲视频图片小说| 国产精品久久婷婷| 色偷偷噜噜噜亚洲男人| 本网站久久精品| 日韩.欧美.亚洲| 日韩电影网1区2区| xxx在线播放| 欧美艳星brazzers| 成年女人的天堂在线| 国产成人综合av| 国产一区二区三区不卡视频网站| 成人av一级片| 久久久久久毛片| 少妇无套内谢久久久久| 这里只有精品久久| 高清欧美日韩| 日本黄色a视频| 韩国女主播成人在线观看| 国产午夜精品理论片在线| 7777精品久久久大香线蕉 | 欧美有码在线视频| 九九久久电影| www.日本一区| 亚洲三级在线看| 粉嫩小泬无遮挡久久久久久| 国内精品久久久久久久久| 欧美日韩破处| 久章草在线视频| 亚洲国产高清aⅴ视频| 中文字字幕在线中文乱码| 最好看的2019年中文视频| 亚洲精品tv| 路边理发店露脸熟妇泻火| 成人三级在线视频| 国产成人综合欧美精品久久| 亚洲欧洲一区二区三区久久| 成人全视频免费观看在线看| 在线视频91| 成人美女在线视频| 欧美国产成人精品一区二区三区| 永久免费精品影视网站| 国产精品高清一区二区| 久草免费福利在线| 2023国产精品| 国产美女三级无套内谢| 海角国产乱辈乱精品视频| 伊人成综合网yiren22| 国产成人美女视频| 亚洲国产精品久久一线不卡| 黄色国产在线| 99中文字幕| 人人爽香蕉精品| 久久久无码精品亚洲国产| 国产婷婷成人久久av免费高清| 亚洲美女色播| 免费av手机在线观看| 国产精品不卡一区二区三区| 日韩在线一区二区三区四区| 国产精品九九九| 国一区二区在线观看| 午夜时刻免费入口| 欧美成人高清电影在线| 成人黄色免费观看| 中文字幕无码精品亚洲资源网久久| 国产视频亚洲色图| 亚洲乱熟女一区二区| 国产精品网址在线| 亚洲高清av| 国产一区二区播放| 亚洲男人的天堂在线播放|