精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

xf在线a精品一区二区视频网站| 精品一区在线| 亚洲国产精品一区二区久久恐怖片 | 午夜精品久久久久久久久久蜜桃| 国产精品情趣视频| 成人免费观看网址| 亚洲久久在线观看| 狠狠做深爱婷婷综合一区| 91精品国产综合久久久蜜臀粉嫩 | 国产成人av一区二区三区在线观看| 国产+人+亚洲| 啪啪一区二区三区| 一区二区导航| 欧美成人r级一区二区三区| 国产精品无码av无码| 三级网站视频在在线播放| 久久亚洲春色中文字幕久久久| 亚洲bt欧美bt日本bt| 国产一级免费视频| 国产一区日韩欧美| 一道本无吗dⅴd在线播放一区| www.欧美com| 涩涩涩久久久成人精品| 色综合天天视频在线观看 | 久久一区二区三区四区五区 | 亚洲人线精品午夜| 熟女人妻在线视频| 极品束缚调教一区二区网站 | 欧美精品国产一区| 国产视频精品在线| 亚洲精美视频| 日本韩国精品一区二区| 国产精品一区在线| 国产在线播放91| 成人a v视频| 亚洲中午字幕| 国外成人性视频| 欧美极品aaaaabbbbb| 图片小说视频色综合| 成人视屏免费看| 在线看日韩av| 天天躁日日躁狠狠躁av麻豆男男| 欧美一区二区激情视频| 国产精品久久久久一区二区三区厕所| 亚洲男人天堂网站| 黄色录像a级片| 成人av婷婷| 欧美变态tickle挠乳网站| 久久精品亚洲天堂| 精品成人18| 欧美一个色资源| 青娱乐精品在线| 久久精品九色| 日韩片之四级片| 一二三区视频在线观看| 免费观看亚洲天堂| 日韩区在线观看| 欧美丰满熟妇bbb久久久| 一区二区三区国产好| 日韩亚洲欧美一区| 午夜影院福利社| 国产亚洲成av人片在线观黄桃| 亚洲第一色中文字幕| 完美搭档在线观看| 日韩有码中文字幕在线| 亚洲日韩欧美视频一区| 久久中文字幕精品| 久久美女精品| 久久99精品久久久久久琪琪| 青春草免费视频| 你懂的国产精品| 欧美变态网站| 欧美高清视频不卡网| 欧美男女交配视频| 99精品国产九九国产精品| 欧美一区二区三区的| 野战少妇38p| 少妇一区二区视频| 久久久99久久精品女同性| 久久久久久久久久久久久久免费看 | 免费黄网站欧美| 国产精品高精视频免费| 国产精品久久久久久无人区 | 亚洲字幕在线观看| 手机福利小视频在线播放| 久久九九影视网| 一区二区三区精品国产| 黄色大片在线| 日本亚州欧洲精品不卡| 黄色成人av在线| 性chinese极品按摩| 亚洲精品午夜| 国产一区二区三区三区在线观看| 手机av在线看| 久久国产精品毛片| 亚洲最大的免费| 欧美色视频免费| 亚洲老妇xxxxxx| 99久久久无码国产精品6| 高清国产一区二区三区四区五区| 日韩精品福利在线| 国产一区第一页| 欧美亚洲自偷自偷| 99久久精品久久久久久ai换脸| 黄色毛片在线看| 亚洲一区精品在线| 亚洲欧美自拍另类日韩| 老牛精品亚洲成av人片| 精品国偷自产在线视频| 日韩成年人视频| 国产一区二区按摩在线观看| 欧美一区二区在线| 91白丝在线| 欧美一级片在线观看| 中字幕一区二区三区乱码| 精品动漫av| 97人人模人人爽人人少妇| av在线播放网| 日韩欧美精品网站| 妖精视频一区二区| 国语精品一区| 亚洲free性xxxx护士hd| 视频一区二区三区不卡| 色婷婷av一区二区三区软件| 你懂的在线观看网站| 国内精品福利| 97在线电影| av免费在线网站| 91精品中文字幕一区二区三区 | 亚洲男人的天堂一区二区| 国产视频一区二区三区在线播放 | 久久久精品影视| 欧美亚洲精品一区二区| 91精品短视频| 欧美黄色成人网| 精品久久久久中文慕人妻| 中文字幕五月欧美| 日本精品一级二级| 亚洲精品视频导航| 欧美一区三区| 国产精品三级美女白浆呻吟 | 精品欧美一区免费观看α√| 亚洲精品a区| 666av成人影院在线观看| 国产福利不卡视频| 一区二区三区国| 国产精品99久久久久久董美香| 精品五月天久久| 中文字幕第15页| 91麻豆高清视频| 日韩视频第二页| 亚洲黄色录像| 国产精欧美一区二区三区| 久草在线免费福利资源| 91搞黄在线观看| 中文字幕欧美激情极品| 毛片av中文字幕一区二区| 亚洲一区二区三区色| 99热这里有精品| 欧美高跟鞋交xxxxxhd| 懂色av一区二区三区四区| 午夜精品久久久久久| 欧美bbbbb性bbbbb视频| 久久精品主播| 亚洲不卡中文字幕| 国产95亚洲| 91成人天堂久久成人| 女人天堂在线| 91精品国产综合久久久久久久 | 亚洲黄色尤物视频| 午夜剧场免费看| 奇米888四色在线精品| 中文字幕一区二区三区有限公司| 欧美电影院免费观看| 久久免费精品视频| 超碰97在线免费观看| 日韩午夜激情视频| 久久精品久久久久久久| 国产精品成人免费精品自在线观看| www.色欧美| 一区二区毛片| 椎名由奈jux491在线播放| 成人激情自拍| 国产精品稀缺呦系列在线| 51xtv成人影院| 亚洲人成电影网| www.蜜桃av.com| 91成人在线精品| 免费人成在线观看| 中文av一区特黄| 又黄又爽的网站| 国产中文字幕精品| 久久精品国产精品亚洲色婷婷| 欧美国产美女| 久久免费一区| aiai久久| 成人激情视频在线| 欧美大片免费| 欧美高清性猛交| 婷婷免费在线视频| 日韩精品免费观看| 性欧美一区二区三区| 91福利社在线观看| 国产污污视频在线观看| 亚洲女人小视频在线观看| 日本少妇xxxxx| 2020国产精品久久精品美国| 杨幂一区二区国产精品| 日本特黄久久久高潮| 久久久一本二本三本| 欧美激情第二页| 一区二区精品国产| 欧美少妇xxxx| 免费亚洲精品视频| 久久精品国产亚洲5555| 成人情视频高清免费观看电影| 国产亚洲精品精品国产亚洲综合| 欧美一区第一页| 888av在线视频| 久久久久久久久综合| 国产成人在线视频免费观看| 在线成人激情黄色| 九色在线播放| 亚洲欧洲一区二区三区久久| 欧美熟女一区二区| 精品播放一区二区| 成人午夜免费福利| 精品久久久久久亚洲综合网| 国产精品一区二区免费视频| 欧美日韩在线综合| 最近中文字幕在线视频| 在线中文字幕不卡| 国产裸体美女永久免费无遮挡| 色综合久久久久网| 99精品人妻国产毛片| 欧美性感美女h网站在线观看免费| 国产在线拍揄自揄拍| 亚洲国产日韩在线一区模特| 久久久久久久久精| 亚洲成在人线在线播放| 精品少妇久久久| 亚洲va欧美va国产va天堂影院| 国产亚洲欧美精品久久久www| 亚洲影视在线播放| 精品一区二区三区人妻| 亚洲福利一二三区| 国产又爽又黄的视频| 色天天综合久久久久综合片| 91丨九色丨海角社区| 欧美午夜不卡视频| 国产精品九九九九| 日韩情涩欧美日韩视频| 狠狠人妻久久久久久综合麻豆| 精品国产乱码久久久久久浪潮| 国产 欧美 精品| 日韩成人免费视频| 高清性色生活片在线观看| 在线电影av不卡网址| 日本免费中文字幕在线| 久久69精品久久久久久久电影好 | 久久精品一区二区免费播放| 久久婷婷国产综合精品青草| 在线视频第一页| 亚洲欧美自拍偷拍色图| 波多野结衣不卡视频| 偷拍与自拍一区| 中文字幕一区二区人妻视频| 制服丝袜成人动漫| 欧美一区二区三区黄片| 亚洲天堂久久av| av网站大全在线| 欧美一级黄色网| 亚洲精品大全| 国产在线精品一区| 日本a级不卡| 国产精品69久久久| 久久婷婷激情| 午夜福利123| av一本久道久久综合久久鬼色| 五月天综合视频| 亚洲综合视频在线| 波多野结衣一区二区三区在线| 欧美一区二区三区日韩| 日本护士...精品国| 久久资源免费视频| 制服丝袜专区在线| 91嫩草国产在线观看| 欧美精品第一区| 91视频 - 88av| 日本不卡的三区四区五区| 337p日本欧洲亚洲大胆张筱雨| 2020国产成人综合网| 真实国产乱子伦对白在线| 色偷偷久久一区二区三区| 精品人妻aV中文字幕乱码色欲| 亚洲欧美综合v| 免费在线播放电影| 国产欧美日韩免费| 偷拍一区二区| 国产在线视频综合| 久久国产生活片100| jizz日本免费| 一区二区三区国产| 91在线公开视频| 亚洲天堂av高清| 都市激情亚洲综合| 国产欧美日韩一区二区三区| 亚洲精彩视频| 最新中文字幕免费视频| 2020国产精品| 六月丁香在线视频| 精品欧美乱码久久久久久1区2区| 免费av在线| 国产欧美一区二区| 国产传媒欧美日韩成人精品大片| 精品国产av无码一区二区三区| 韩国精品在线观看 | 亚洲一线二线三线视频| 一级特黄aa大片| 在线激情影院一区| 欧美激情喷水| 精品人伦一区二区三区| 好看的av在线不卡观看| 手机精品视频在线| **欧美大码日韩| 97人妻精品一区二区三区视频| 亚洲一级黄色片| 成人天堂yy6080亚洲高清| 久久国产精品一区二区三区| 欧美另类视频| 真实乱偷全部视频| 亚洲自拍偷拍综合| 精品人妻一区二区三区含羞草| 日韩中文字幕网站| 黄色成人小视频| 亚洲综合五月天| 老司机午夜精品99久久| 91免费在线看片| 欧美日韩国产高清一区| 里番在线观看网站| 成人黄色免费片| 亚洲精品极品少妇16p| 自拍一级黄色片| 亚洲综合无码一区二区| 空姐吹箫视频大全| 78色国产精品| 国产午夜一区| 中文字幕av不卡在线| 中文字幕在线不卡视频| av网站在线免费看| 久久久久国产精品免费网站| 黄色免费大全亚洲| 日韩av资源在线| 国产嫩草影院久久久久| 一级黄色片在线播放| 久久国产精品影视| 粉嫩精品导航导航| www.玖玖玖| 国产精品区一区二区三| 国产夫妻在线观看| 97视频在线观看免费高清完整版在线观看| 四虎5151久久欧美毛片| 成年人在线观看视频免费| 国产精品大尺度| 韩国av在线免费观看| 欧美中文字幕在线视频| 成人无号精品一区二区三区| 国产欧美精品一二三| 亚洲18女电影在线观看| 高清性色生活片在线观看| 亚洲精品日产aⅴ| 一本色道久久综合| 欧美老女人性生活视频| 精品人在线二区三区| 欧美大胆成人| 人妻互换免费中文字幕| 久久综合色鬼综合色| 97精品人妻一区二区三区| 欧美激情一二三| 精品香蕉视频| 国产精品偷伦视频免费观看了| 色综合咪咪久久| 搞黄网站在线观看| 久久久久久欧美精品色一二三四| 免费在线观看成人| 日本少妇激情视频| 中文字幕欧美在线| 国产精品久久久网站| 少妇一级淫免费播放| 午夜视黄欧洲亚洲| 日本中文在线| 麻豆av福利av久久av| 国产另类ts人妖一区二区| 好看的av在线| 欧美裸体xxxx极品少妇| 国产精品片aa在线观看| 欧美午夜精品一区二区| 欧美三级电影在线看| 久热在线观看视频| 波多野结衣 作品|