小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

幾種分布式鎖

 景昕的花園 2023-10-10 發(fā)布于北京

數(shù)據(jù)庫鎖

數(shù)據(jù)庫鎖是分布式鎖的一種簡(jiǎn)單實(shí)現(xiàn),其加鎖的原理實(shí)際就是數(shù)據(jù)庫的唯一約束或者行鎖。其基本原理(偽代碼)如下:

數(shù)據(jù)庫鎖簡(jiǎn)單實(shí)現(xiàn) 

try{    // 按唯一鍵進(jìn)行insert操作    insertByUnique(uniqueKey);    // 如果沒有拋出異常,則認(rèn)為拿到了鎖    // 略去業(yè)務(wù)代碼}catch(唯一鍵沖突異常){    // 發(fā)生唯一鍵沖突,說明已有其它服務(wù)拿到了這個(gè)鎖    // 略去異常處理代碼}finally{    // 完成業(yè)務(wù)處理后,釋放鎖    deleteByUniqueKey(uniqueKey);}

阻塞性

鎖同步機(jī)制中,未獲取到鎖的一方往往需要阻塞當(dāng)前線程、并等待鎖釋放后再次競(jìng)爭(zhēng)。數(shù)據(jù)庫鎖利用行鎖可以方便的實(shí)現(xiàn)這個(gè)功能。

數(shù)據(jù)庫鎖:阻塞鎖簡(jiǎn)單實(shí)現(xiàn) 

try{    // 按唯一鍵進(jìn)行selectForUpdate操作,以爭(zhēng)奪其行鎖    selectForUpdate(uniqueKey);    // 如果沒有拋出異常,則認(rèn)為拿到了鎖    // 略去業(yè)務(wù)代碼}catch(鎖超時(shí)異常){    // 超時(shí)處理}finally{    // 完成業(yè)務(wù)處理后,釋放鎖    // 退出事務(wù)即可}

與簡(jiǎn)單實(shí)現(xiàn)不同的是,這里的“加鎖”操作不是通過insert uniqueKey實(shí)現(xiàn),而是select for update實(shí)現(xiàn)。與之對(duì)應(yīng)的,釋放鎖的操作也從delete uniqueKey變成了退出當(dāng)前事務(wù)。

鎖超時(shí)

一般來說,數(shù)據(jù)庫操作的超時(shí)時(shí)間即這把鎖的超時(shí)時(shí)間。這使得數(shù)據(jù)庫鎖無法為不同的鎖設(shè)置不同的超時(shí)時(shí)間。

個(gè)別情況下(insert了鎖、而沒有delete),還需要增加一個(gè)定時(shí)任務(wù),用于清理數(shù)據(jù)庫中寫入的鎖。

可重入

數(shù)據(jù)庫的鎖本身就是可重入的。對(duì)于代碼來說,只要保證對(duì)同一個(gè)鎖的多次請(qǐng)求在同一個(gè)數(shù)據(jù)庫事務(wù)里,就能夠做到可重入。

如果特別為加鎖、解鎖聲明了獨(dú)立的事務(wù)(如REQUEST_NEW),則需要在數(shù)據(jù)庫鎖上增加一個(gè)對(duì)象標(biāo)志,用以標(biāo)記當(dāng)前獲得這個(gè)鎖的請(qǐng)求是誰,并根據(jù)這個(gè)標(biāo)志來實(shí)現(xiàn)同一個(gè)請(qǐng)求的可重入。

讀寫鎖

由于數(shù)據(jù)庫的讀操作一般不加鎖(特別聲明了for update等除外),因此,數(shù)據(jù)庫鎖實(shí)現(xiàn)不了讀寫鎖。

其它

其它如公平/非公平鎖、信號(hào)量等,數(shù)據(jù)庫鎖都較難實(shí)現(xiàn)。

Redis鎖

用Redis實(shí)現(xiàn)分布式鎖,需要分單機(jī)和集群兩種情況來討論。

單機(jī)情況

單機(jī)情況下,Redis主要依靠SETNX命令(SET if Not eXists)來實(shí)現(xiàn)分布式鎖。這個(gè)命令的功能是:當(dāng)且僅當(dāng) key 不存在時(shí),將 key 的值設(shè)為 value ,并返回1;若給定的 key 已經(jīng)存在,則 SETNX 不做任何動(dòng)作,并返回0。

注:2019-01-16 使用setNX命令時(shí),不應(yīng)簡(jiǎn)單地將value值設(shè)定為固定值,而應(yīng)當(dāng)使用一個(gè)隨機(jī)數(shù),并根據(jù)此隨機(jī)數(shù)來釋放鎖。這樣可以防止其它線程錯(cuò)誤地刪除鎖。此時(shí),刪除鎖的腳本應(yīng)當(dāng)是:

if redis.call("get",KEYS[1]) == ARGV[1] then    return redis.call("del",KEYS[1])else    return 0end

集群情況

集群情況比較復(fù)雜。Redis官方提出了一個(gè)“RedLock”算法,其基本思路是:客戶端遍歷Redis集群中的每個(gè)實(shí)例,并嘗試獲取該實(shí)例上的鎖;如果能夠成功獲得集群實(shí)例中半數(shù)以上的鎖,則視為獲得了這個(gè)鎖;否則認(rèn)為沒有得到這個(gè)鎖,并刪除已經(jīng)獲得的少數(shù)實(shí)例上的鎖。

實(shí)際的原理要更復(fù)雜一些,考慮了各種超時(shí)、重試、性能、同步等問題。細(xì)節(jié)可以參見:Redis分布式鎖

注:2018-04-28 RedLock應(yīng)該是3.0版本之前提出來的。在3.0版本之前,Redis集群自身不做一致性哈希操作,各臺(tái)master之間相互獨(dú)立、互不影響;一致性哈希是由客戶端來實(shí)現(xiàn)的。但在3.0版本之后,Redis集群在服務(wù)端實(shí)現(xiàn)了一致性哈希,集群服務(wù)對(duì)外“視圖”與單機(jī)服務(wù)是一樣的。這種情況下,RedLock就失去了它的意義。在3.0版本后的Redis集群服務(wù)中,同一個(gè)Key會(huì)經(jīng)由一致性哈希算法而放到同一個(gè)插槽(Slot)、同一臺(tái)Master上去;這與單機(jī)服務(wù)是一樣的。

代碼實(shí)現(xiàn)

基于Redis實(shí)現(xiàn)的分布式鎖,已經(jīng)有成熟的代碼庫了,參見Redis分布式鎖中的介紹,或者redisson的Github地址。關(guān)于這個(gè)庫的分布式鎖特性,參見分布式鎖和同步器

ZooKepper鎖

相對(duì)于Redis鎖,ZooKeeper鎖的原理更好理解一些。其基本思路是:客戶端在ZooKeeper的lockName路徑下創(chuàng)建一個(gè)節(jié)點(diǎn),并判斷此節(jié)點(diǎn)是否此路徑下的第一個(gè)節(jié)點(diǎn);如果是,則得到鎖,并在業(yè)務(wù)處理完畢后刪除這個(gè)節(jié)點(diǎn);如果不是,說明沒有得到鎖。

稍感遺憾的是,我沒有找到相關(guān)的代碼庫,而只有一些實(shí)現(xiàn)此功能的代碼樣例。參見:使用zookeeper實(shí)現(xiàn)的分布式鎖。

阻塞性

由于客戶端可以監(jiān)聽ZooKeeper對(duì)某個(gè)節(jié)點(diǎn)的操作(是否被刪除),因此,當(dāng)需要阻塞鎖時(shí),當(dāng)前線程只需要監(jiān)聽ZooKeeper服務(wù)中上一個(gè)節(jié)點(diǎn)即可。如果上一個(gè)節(jié)點(diǎn)被刪除了,說明鎖已釋放,并且自己已經(jīng)是lockName路徑下的最小節(jié)點(diǎn),從而獲得鎖。

鎖超時(shí)

為了讓ZooKeeper鎖能自動(dòng)超時(shí),客戶端在lockName路徑下創(chuàng)建的節(jié)點(diǎn)一般是臨時(shí)順序節(jié)點(diǎn)。這樣,如果客戶端發(fā)生問題導(dǎo)致斷開連接,在會(huì)話超時(shí)之后,節(jié)點(diǎn)刪除,進(jìn)而釋放這個(gè)鎖。

可重入

按照基本思路來看,每次使用ZooKeeper加鎖時(shí)都會(huì)生成一個(gè)新的節(jié)點(diǎn),因此它本身并不支持可重入。

如果要求可重入,那么需要在客戶端(或者線程上下文中)臨時(shí)存儲(chǔ)當(dāng)前節(jié)點(diǎn),并在此基礎(chǔ)上進(jìn)行判斷處理。

讀寫鎖

讀寫鎖的思路可以參考 使用ZooKeeper實(shí)現(xiàn)Java跨JVM的分布式鎖(讀寫鎖)。簡(jiǎn)單來說,競(jìng)爭(zhēng)鎖時(shí),需要判斷已有節(jié)點(diǎn)中是否有寫入鎖。如果有,則需要等待寫入鎖釋放;如果沒有,則認(rèn)為自己已經(jīng)獲得了鎖。

其它

其它如公平/非公平鎖、信號(hào)量等,Zookeeper鎖也可以實(shí)現(xiàn),只是比較復(fù)雜。

參考

Redis分布式鎖

redisson的Github地址

分布式鎖和同步器

zookeeper 分布式鎖服務(wù)

使用zookeeper實(shí)現(xiàn)的分布式鎖

使用ZooKeeper實(shí)現(xiàn)Java跨JVM的分布式鎖

使用分布式鎖時(shí)考慮哪些問題

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多