一文弄懂“分布式鎖”,一直以來(lái)你的選擇依據(jù)正確嗎?-創(chuàng)新互聯(lián)

本文主要會(huì)關(guān)注的問題是“分布式鎖”的問題。

專注于為中小企業(yè)提供網(wǎng)站建設(shè)、做網(wǎng)站服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)東營(yíng)免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了近1000家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

多線程情況下對(duì)共享資源的操作需要加鎖,避免數(shù)據(jù)被寫亂,在分布式系統(tǒng)中,這個(gè)問題也是存在的,此時(shí)就需要一個(gè)分布式鎖服務(wù)。

常見的分布式鎖實(shí)現(xiàn)一般是基于DB、Redis、Zookeeper。下面筆者會(huì)按照順序分析下這3種分布式鎖的設(shè)計(jì)與實(shí)現(xiàn),想直接看分布式鎖總結(jié)的小伙伴可直接翻到文檔末尾處。

分布式鎖的實(shí)現(xiàn)由多種方式,但是不管怎樣,分布式鎖一般要有以下特點(diǎn):

排他性: 任意時(shí)刻,只能有一個(gè)client能獲取到鎖;

容錯(cuò)性: 分布式鎖服務(wù)一般要滿足AP,也就是說,只要分布式鎖服務(wù)集群節(jié)點(diǎn)大部分存活,client就可以進(jìn)行加鎖解鎖操作;

避免死鎖: 分布式鎖一定能得到釋放,即使client在釋放之前崩潰或者網(wǎng)絡(luò)不可達(dá)。

除了以上特點(diǎn)之外,分布式鎖最好也能滿足可重入、高性能、阻塞鎖特性(AQS這種,能夠及時(shí)從阻塞狀態(tài)喚醒)等,下面就話不多說,趕緊上(開往分布式鎖的設(shè)計(jì)與實(shí)現(xiàn)的)車。

一、DB鎖

在數(shù)據(jù)庫(kù)新建一張表用于控制并發(fā)控制,表結(jié)構(gòu)可以如下所示:

一文弄懂“分布式鎖”,一直以來(lái)你的選擇依據(jù)正確嗎?

key_id作為分布式key用來(lái)并發(fā)控制,memo可用來(lái)記錄一些操作內(nèi)容(比如memo可用來(lái)支持重入特性,標(biāo)記下當(dāng)前加鎖的client和加鎖次數(shù))。將key_id設(shè)置為唯一索引,保證了針對(duì)同一個(gè)key_id只有一個(gè)加鎖(數(shù)據(jù)插入)能成功。此時(shí)lock和unlock偽代碼如下:

一文弄懂“分布式鎖”,一直以來(lái)你的選擇依據(jù)正確嗎?

注意,偽代碼中的lock操作是非阻塞鎖,也就是tryLock,如果想實(shí)現(xiàn)阻塞(或者阻塞超時(shí))加鎖,只修反復(fù)執(zhí)行l(wèi)ock偽代碼直到加鎖成功為止即可。

基于DB的分布式鎖其實(shí)有一個(gè)問題,那就是如果加鎖成功后,client端宕機(jī)或者由于網(wǎng)絡(luò)原因?qū)е聸]有解鎖,那么其他client就無(wú)法對(duì)該key_id進(jìn)行加鎖并且無(wú)法釋放了。為了能夠讓鎖失效,需要在應(yīng)用層加上定時(shí)任務(wù),去刪除過期還未解鎖的記錄,比如刪除2分鐘前未解鎖的偽代碼如下:

一文弄懂“分布式鎖”,一直以來(lái)你的選擇依據(jù)正確嗎?

因?yàn)閱螌?shí)例DB的TPS一般為幾百,所以基于DB的分布式性能上限一般也是1k以下,一般在并發(fā)量不大的場(chǎng)景下該分布式鎖是滿足需求的,不會(huì)出現(xiàn)性能問題。

不過DB作為分布式鎖服務(wù)需要考慮單點(diǎn)問題,對(duì)于分布式系統(tǒng)來(lái)說是不允許出現(xiàn)單點(diǎn)的,一般通過數(shù)據(jù)庫(kù)的同步復(fù)制,以及使用vip切換Master就能解決這個(gè)問題。

以上DB分布式鎖是通過insert來(lái)實(shí)現(xiàn)的,如果加鎖的數(shù)據(jù)已經(jīng)在數(shù)據(jù)庫(kù)中存在,那么用select xxx where key_id = xxx for udpate方式來(lái)做也是可以的。

二、Redis鎖

Redis鎖是通過以下命令對(duì)資源進(jìn)行加鎖:

set key_id key_value NX PX expireTime

其中,set nx命令只會(huì)在key不存在時(shí)給key進(jìn)行賦值,px用來(lái)設(shè)置key過期時(shí)間,key_value一般是隨機(jī)值,用來(lái)保證釋放鎖的安全性(釋放時(shí)會(huì)判斷是否是之前設(shè)置過的隨機(jī)值,只有是才釋放鎖)。由于資源設(shè)置了過期時(shí)間,一定時(shí)間后鎖會(huì)自動(dòng)釋放。

set nx保證并發(fā)加鎖時(shí)只有一個(gè)client能設(shè)置成功(Redis內(nèi)部是單線程,并且數(shù)據(jù)存在內(nèi)存中,也就是說Redis內(nèi)部執(zhí)行命令是不會(huì)有多線程同步問題的),此時(shí)的lock/unlock偽代碼如下:

一文弄懂“分布式鎖”,一直以來(lái)你的選擇依據(jù)正確嗎?

分布式鎖服務(wù)中的一個(gè)問題

如果一個(gè)獲取到鎖的client因?yàn)槟撤N原因?qū)е聸]能及時(shí)釋放鎖,并且Redis因?yàn)槌瑫r(shí)釋放了鎖,另外一個(gè)client獲取到了鎖,此時(shí)情況如下圖所示:

一文弄懂“分布式鎖”,一直以來(lái)你的選擇依據(jù)正確嗎?

那么如何解決這個(gè)問題呢?

一種方案是引入鎖續(xù)約機(jī)制,也就是獲取鎖之后,釋放鎖之前,會(huì)定時(shí)進(jìn)行鎖續(xù)約,比如以鎖超時(shí)時(shí)間的1/3為間隔周期進(jìn)行鎖續(xù)約。

關(guān)于開源的Redis的分布式鎖實(shí)現(xiàn)有很多,比較出名的有redisson、百度的dlock,關(guān)于分布式鎖,筆者也寫了一個(gè)簡(jiǎn)易版的分布式鎖Redis-lock,主要是增加了鎖續(xù)約和可同時(shí)針對(duì)多個(gè)key加鎖的機(jī)制。

對(duì)于高可用性,一般可以通過集群或者master-slave來(lái)解決,Redis鎖優(yōu)勢(shì)是性能出色,劣勢(shì)就是由于數(shù)據(jù)在內(nèi)存中,一旦緩存服務(wù)宕機(jī),鎖數(shù)據(jù)就丟失了。

像Redis自帶復(fù)制功能,可以對(duì)數(shù)據(jù)可靠性有一定的保證,但是由于復(fù)制也是異步完成的,因此依然可能出現(xiàn)master節(jié)點(diǎn)寫入鎖數(shù)據(jù)而未同步到slave節(jié)點(diǎn)的時(shí)候宕機(jī),鎖數(shù)據(jù)丟失問題。

三、Zookeeper分布式鎖

ZooKeeper是一個(gè)高可用的分布式協(xié)調(diào)服務(wù),由雅虎創(chuàng)建,是Google Chubby的開源實(shí)現(xiàn)。

ZooKeeper提供了一項(xiàng)基本的服務(wù):分布式鎖服務(wù)。想學(xué)習(xí)Java工程化、分布式架構(gòu)、高并發(fā)、高性能、深入淺出、微服務(wù)架構(gòu)、Spring,MyBatis,Netty源碼分析等技術(shù)可以加群:479499375,群里有阿里大牛直播講解技術(shù),以及Java大型互聯(lián)網(wǎng)技術(shù)的視頻免費(fèi)分享給大家,歡迎進(jìn)群一起深入交流學(xué)習(xí)。

Zookeeper重要的3個(gè)特征是:zab協(xié)議、node存儲(chǔ)模型和watcher機(jī)制。通過zab協(xié)議保證數(shù)據(jù)一致性,Zookeeper集群部署保證可用性,node存儲(chǔ)在內(nèi)存中,提高了數(shù)據(jù)操作性能,使用watcher機(jī)制,實(shí)現(xiàn)了通知機(jī)制(比如加鎖成功的client釋放鎖時(shí)可以通知到其他client)。

Zookeeper node模型支持臨時(shí)節(jié)點(diǎn)特性,即client寫入的數(shù)據(jù)時(shí)臨時(shí)數(shù)據(jù),當(dāng)客戶端宕機(jī)時(shí)臨時(shí)數(shù)據(jù)會(huì)被刪除,這樣就不需要給鎖增加超時(shí)釋放機(jī)制了。

當(dāng)針對(duì)同一個(gè)path并發(fā)多個(gè)創(chuàng)建請(qǐng)求時(shí),只有一個(gè)client能創(chuàng)建成功,這個(gè)特性用來(lái)實(shí)現(xiàn)分布式鎖。注意:如果client端沒有宕機(jī),由于網(wǎng)絡(luò)原因?qū)е耑ookeeper服務(wù)與client心跳失敗,那么Zookeeper也會(huì)把臨時(shí)數(shù)據(jù)給刪除掉的,這時(shí)如果client還在操作共享數(shù)據(jù),是有一定風(fēng)險(xiǎn)的。

基于Zookeeper實(shí)現(xiàn)分布式鎖,相對(duì)于基于Redis和DB的實(shí)現(xiàn)來(lái)說,使用上更容易,效率與穩(wěn)定性較好。curator封裝了對(duì)Zookeeper的API操作,同時(shí)也封裝了一些高級(jí)特性,如:Cache事件監(jiān)聽、選舉、分布式鎖、分布式計(jì)數(shù)器、分布式Barrier等,使用curator進(jìn)行分布式加鎖示例如下:

一文弄懂“分布式鎖”,一直以來(lái)你的選擇依據(jù)正確嗎?

一文弄懂“分布式鎖”,一直以來(lái)你的選擇依據(jù)正確嗎?

四、總結(jié)

從上面介紹的3種分布式鎖的設(shè)計(jì)與實(shí)現(xiàn)中,我們可以看出每種實(shí)現(xiàn)都有各自的特點(diǎn),針對(duì)潛在的問題有不同的解決方案,歸納如下:

性能: Redis > Zookeeper > DB。

避免死鎖: DB通過應(yīng)用層設(shè)置定時(shí)任務(wù)來(lái)刪除過期還未釋放的鎖,Redis通過設(shè)置超時(shí)時(shí)間來(lái)解決,而Zookeeper是通過臨時(shí)節(jié)點(diǎn)來(lái)解決。

可用性: DB可通過數(shù)據(jù)庫(kù)同步復(fù)制,vip切換master來(lái)解決;Redis可通過集群或者master-slave方式來(lái)解決;Zookeeper本身自己是通過zab協(xié)議集群部署來(lái)解決的。注意,DB和Redis的復(fù)制一般都是異步的,也就是說某些時(shí)刻分布式鎖發(fā)生故障可能存在數(shù)據(jù)不一致問題,而Zookeeper本身通過zab協(xié)議保證集群內(nèi)(至少n/2+1個(gè))節(jié)點(diǎn)數(shù)據(jù)一致性。

鎖喚醒: DB和Redis分布式鎖一般不支持喚醒機(jī)制(也可以通過應(yīng)用層自己做輪詢檢測(cè)鎖是否空閑,空閑就喚醒內(nèi)部加鎖線程),Zookeeper可通過本身的watcher/notify機(jī)制來(lái)做。

使用分布式鎖,安全性上和多線程(同一個(gè)進(jìn)程內(nèi))加鎖是沒法比的,可能由于網(wǎng)絡(luò)原因,分布式鎖服務(wù)(因?yàn)槌瑫r(shí)或者認(rèn)為client掛了)將加鎖資源給刪除了,如果client端繼續(xù)操作共享資源,此時(shí)是有隱患的。

因此,對(duì)于分布式鎖,一個(gè)是要盡量提高分布式鎖服務(wù)的可用性,另一個(gè)就是要部署同一內(nèi)網(wǎng),盡量降低網(wǎng)絡(luò)問題發(fā)生幾率。

這樣來(lái)看,貌似分布式鎖服務(wù)不是“完美”的(PS:技術(shù)貌似也不好做到十全十美 :( ),那么開發(fā)人員該如何選擇分布式鎖呢?最好是結(jié)合自己的業(yè)務(wù)實(shí)際場(chǎng)景,來(lái)選擇不同的分布式鎖實(shí)現(xiàn),一般來(lái)說,基于Redis的分布式鎖服務(wù)應(yīng)用較多。

網(wǎng)頁(yè)名稱:一文弄懂“分布式鎖”,一直以來(lái)你的選擇依據(jù)正確嗎?-創(chuàng)新互聯(lián)
標(biāo)題鏈接:http://m.kartarina.com/article12/eoigc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化商城網(wǎng)站網(wǎng)站內(nèi)鏈、電子商務(wù)、建站公司、響應(yīng)式網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)
主站蜘蛛池模板: 亚洲情XO亚洲色XO无码| 国产精品成人无码久久久久久| 亚洲VA中文字幕不卡无码| 亚洲的天堂av无码| 亚洲国产综合无码一区二区二三区| 亚洲国产精品无码中文字| 无码粉嫩虎白一线天在线观看| 亚洲综合无码精品一区二区三区| 亚洲av无码潮喷在线观看| 亚洲精品97久久中文字幕无码 | 免费无码AV一区二区| 亚洲成A人片在线观看无码不卡 | 亚洲Av永久无码精品三区在线| 亚洲精品无码久久久久秋霞| 午夜不卡无码中文字幕影院| 大桥久未无码吹潮在线观看| 国模无码视频一区| 亚洲AV无码成人精品区日韩 | 日韩毛片无码永久免费看| 日韩精品无码一本二本三本| 亚洲AV永久无码精品水牛影视| 超清无码无卡中文字幕| 亚洲AV无码专区日韩| 亚洲人成人无码网www国产| 无码国产精品一区二区高潮| 无码狠狠躁久久久久久久| 50岁人妻丰满熟妇αv无码区| 人妻丰满熟妇岳AV无码区HD| 无码免费一区二区三区免费播放| 国产亚洲精品无码成人| 亚洲中文久久精品无码ww16| 中文无码久久精品| 色综合久久无码五十路人妻| 小SAO货水好多真紧H无码视频| 亚洲AV无码一区东京热久久| 亚洲AV无码精品色午夜果冻不卡| 久久亚洲精品无码| 国产成人无码AV麻豆| 精品无码久久久久久久久 | 国产午夜无码专区喷水| 高潮潮喷奶水飞溅视频无码|