分布式鎖簡(jiǎn)單介紹

工作中經(jīng)常會(huì)遇到爭(zhēng)搶共享資源的場(chǎng)景山卦,比如用戶搶購(gòu)秒殺商品鞋邑,如果不對(duì)商品庫(kù)存進(jìn)行保護(hù),可能會(huì)造成超賣的情況账蓉。超賣現(xiàn)象在售賣火車票的場(chǎng)景下更加明顯枚碗,兩個(gè)人購(gòu)買到同一天同一輛列車,相同座位的情況是不允許出現(xiàn)的铸本。交易系統(tǒng)中的退款同樣如此肮雨,由于網(wǎng)絡(luò)延遲和重復(fù)提交極端時(shí)間差的情況下,可能會(huì)造成同一個(gè)用戶重復(fù)的退款請(qǐng)求归敬。以上無(wú)論是超賣酷含,還是重復(fù)退款,都是沒有對(duì)需要保護(hù)的資源或業(yè)務(wù)進(jìn)行完善的保護(hù)而造成的汪茧,從設(shè)計(jì)方面一定要避免這種情況的發(fā)生。

本文以退款交易場(chǎng)景入手限番,引入分布式鎖舱污,嘗試分析分布式鎖需要考慮關(guān)注點(diǎn),包括以下內(nèi)容:

  • 鎖的引入和局限性
  • 分布式鎖的三要素
  • 分布式鎖進(jìn)階
    • 獲取鎖操作的原子性
    • 鎖與保護(hù)共享資源的數(shù)據(jù)一致性
    • 分布式鎖的性能
    • 可重入
    • 公平鎖和非公平鎖
  • 分布式鎖的容錯(cuò)弥虐,使用分布式鎖時(shí)注意考慮哪些問題
鎖的引入和局限性

鎖是一種控制共享資源爭(zhēng)搶的機(jī)制扩灯,采用互斥方式防止多線程(或多進(jìn)程)間造成的沖突。鎖是一種獲取保護(hù)資源的憑證霜瘪,就像公園門票珠插,只有持有門票才有資格入園;鎖是使得對(duì)同一類共享資源的訪問串行化颖对。沒有獲得鎖只能排隊(duì)等待捻撑,直到其他線程釋放掉鎖。這里需要對(duì)“同一類共享資源”正確理解缤底,比如訂單系統(tǒng)中的同一種商品庫(kù)存顾患,退款系統(tǒng)中同一個(gè)用戶。

在多線程中个唧,Java 已經(jīng)提供了很好原生鎖(包括synchronized江解,lock),前面的其他文章中也已經(jīng)講到了內(nèi)置鎖和顯示鎖的理解和使用徙歼,在此不再贅述犁河。但是(是不是已經(jīng)料到了我要說(shuō)但是了呢鳖枕?),在分布式系統(tǒng)中桨螺,因?yàn)橐邕M(jìn)程或者跨服務(wù)器 耕魄,這種場(chǎng)景下JDK原生鎖已經(jīng)無(wú)法滿足我們的需求,需要一種能夠分布式系統(tǒng)中保護(hù)共享資源的方式彭谁,分布式鎖在這種情況下產(chǎn)生了吸奴。

很多事情往往都是如此,為了解決一個(gè)問題缠局,引入了新方案则奥,而新方案卻會(huì)帶來(lái)其他的問題,又需要用更多的時(shí)間去解決新方案帶來(lái)的問題狭园。沒有一個(gè)完美的方案读处,因此對(duì)方案的取舍,就是具體場(chǎng)景中應(yīng)該重點(diǎn)關(guān)注哪些問題唱矛,忽略哪些問題的選擇罚舱。

分布式鎖的三要素

分布式鎖是一個(gè)在分布式環(huán)境中很重要的原語(yǔ),它表明不同進(jìn)程間采用互斥的方式操作共享資源绎谦。如何才稱得上分布式鎖呢管闷?分布式鎖需要滿足三個(gè)基本的條件:

外部存儲(chǔ)
顧名思義,分布式鎖是在分布式部署環(huán)境中給多個(gè)主機(jī)提供鎖服務(wù)窃肠。Java具有天生的多線程優(yōu)勢(shì)包个,在同一個(gè)進(jìn)程的線程中可以通過(guò)互斥鎖住共享資源來(lái)保證多線程之間干擾,鎖的載體是堆中共享變量冤留,使用JDK原生鎖synchronized和lock可以很方便的解決碧囊,但是將問題擴(kuò)展到分布式環(huán)境中,就超出了JDK原生鎖作用范疇纤怒。需要另外的存儲(chǔ)載體糯而,可以是共享內(nèi)存或者磁盤文件〔淳剑考慮到分布式鎖的高可用性熄驼,避免單點(diǎn)問題,因此共享內(nèi)存中數(shù)據(jù)是需要持久化的州既,這點(diǎn)內(nèi)容會(huì)在下文中的分布式鎖的高可用中涉及到谜洽。

全局唯一標(biāo)識(shí)
與JDK原生鎖類似,分布式鎖同樣需要標(biāo)記為全局唯一吴叶。在多線程環(huán)境中阐虚,鎖可以使一個(gè)對(duì)象引用,也可以是基本類型變量蚌卤,都有唯一的標(biāo)識(shí)來(lái)區(qū)分鎖保護(hù)的不同資源实束。仍然以上面的退款為例奥秆,為了保護(hù)用戶的賬戶資金,不允許同一個(gè)用戶并發(fā)退款咸灿。因此同一個(gè)用戶退款操作采用互斥鎖保護(hù)起來(lái)构订,不同用戶之間不需要互斥操作。具體方法一種可以通過(guò)鎖用戶賬戶的方式避矢,另一種對(duì)用戶userId設(shè)置不同的狀態(tài)標(biāo)識(shí)悼瘾,這兩種方式都是采用對(duì)堆中變量的原子操作保證互斥的。
分布式環(huán)境中上述第一種方法就不適用了审胸,舉個(gè)例子亥宿,小明的賬戶可以同時(shí)在A、B兩個(gè)不同實(shí)例中加鎖砂沛。那么可以采用第二種方法烫扼,自定義一個(gè)標(biāo)識(shí),使其全局唯一即可碍庵,每次申請(qǐng)退款時(shí)映企,首先嘗試獲取該標(biāo)識(shí),如果該標(biāo)識(shí)已經(jīng)被其他占用静浴,則需要等待堰氓,直到釋放該標(biāo)識(shí)(是不是與synchronized很相似)。對(duì)于交易而言马绝,全局唯一的標(biāo)識(shí)很簡(jiǎn)單:業(yè)務(wù)+userId即可唯一標(biāo)識(shí)豆赏。

至少有兩種狀態(tài)
鎖至少需要兩種狀態(tài):加鎖(lock)和解鎖(unlock)。用狀態(tài)區(qū)分當(dāng)前嘗試獲取的鎖是否已經(jīng)被其他操作占用富稻,被占用只有等待鎖釋放后才能嘗試獲取鎖并加鎖,保護(hù)共享資源白胀。

分布式鎖進(jìn)階

為解決共享資源在分布式環(huán)境下并發(fā)訪問帶來(lái)的問題椭赋,引入分布式鎖采用互斥訪問的方式將并發(fā)訪問串行化。下文中以Redis為例或杠,分析使用分布式鎖時(shí)重點(diǎn)需要考慮的情況哪怔。

獲取鎖操作的原子性
從讀取鎖的狀態(tài),到設(shè)置鎖狀態(tài)為加鎖(獲取鎖的過(guò)程)向抢,不是原子性的操作认境,如果不能保證這兩步作為一個(gè)的原子操作,可能存在競(jìng)態(tài)條件挟鸠,在極端的時(shí)間差的情況下叉信,會(huì)有多個(gè)服務(wù)同時(shí)獲取到同一個(gè)鎖,從而獲取操作工作資源的憑證艘希,這是不允許的硼身。幸運(yùn)的是Redis提供了CAS原子性功能SETNX硅急,是「SET if Not eXists」的縮寫,也就是只有不存在的時(shí)候才設(shè)置佳遂。

鎖與保護(hù)共享資源的數(shù)據(jù)一致性
獲取鎖與開始操作共享資源必須保證一致性营袜,結(jié)束操作共享資源和釋放鎖必須保證一致性。共享資源操作結(jié)束后必須釋放鎖丑罪,退出臨界區(qū)荚板,否則會(huì)造成鎖饑餓;開始操作共享資源吩屹,必須是在獲取鎖之后跪另,否則鎖就無(wú)法保護(hù)共享資源。

分布式鎖的性能
分布式鎖需要考慮網(wǎng)絡(luò)傳輸時(shí)間祟峦,超時(shí)時(shí)間同樣需要考慮網(wǎng)絡(luò)時(shí)間消耗罚斗。

可重入
某個(gè)請(qǐng)求試圖獲得一個(gè)已經(jīng)由它自己持有的鎖,那么這個(gè)請(qǐng)求就會(huì)成功宅楞,這是重入针姿。當(dāng)重入時(shí)需要將計(jì)數(shù)器加一,釋放鎖時(shí)厌衙,計(jì)數(shù)器相應(yīng)減一距淫,一般分布式鎖同樣支持可重入,因此需要設(shè)計(jì)標(biāo)記不同的請(qǐng)求婶希。

公平鎖和非公平鎖
公平鎖設(shè)定按照請(qǐng)求的順序獲取鎖榕暇,不允許插隊(duì)。公平是個(gè)好東西喻杈,不過(guò)大多數(shù)情況下非公平鎖的性能要高于公平鎖彤枢。

分布式鎖的容錯(cuò)

正常情況下,加鎖筒饰,執(zhí)行保護(hù)資源缴啡,釋放鎖。如果沒有異常瓷们,那這世界就太美好了业栅。那么生產(chǎn)環(huán)境中,使用分布式鎖時(shí)應(yīng)該注意哪些容錯(cuò)的問題谬晕。

鎖無(wú)法釋放
以退款為例碘裕,退款服務(wù)宕機(jī),分布式鎖服務(wù)正常攒钳。此時(shí)鎖保護(hù)的資源(或部分)已無(wú)法對(duì)外提供服務(wù)帮孔,無(wú)法通知鎖自身運(yùn)行情況,為避免鎖服務(wù)一直無(wú)法釋放夕玩,可以為鎖設(shè)置超時(shí)時(shí)間你弦,當(dāng)鎖執(zhí)行時(shí)間超過(guò)了超時(shí)時(shí)間惊豺,鎖會(huì)過(guò)期,從而保證鎖與保護(hù)服務(wù)的最終一致性禽作。當(dāng)然鎖設(shè)置超時(shí)時(shí)間又會(huì)引出另一個(gè)問題:比如鎖的超時(shí)時(shí)間是500ms尸昧,而部分退款服務(wù)可能由于網(wǎng)絡(luò)等原因執(zhí)行時(shí)間為800ms(退款服務(wù)沒有宕機(jī),僅僅是執(zhí)行時(shí)間相比平均執(zhí)行時(shí)間較長(zhǎng)而已)旷偿,這種情況下烹俗,鎖已經(jīng)過(guò)期,而退款服務(wù)仍在執(zhí)行萍程,鎖作為保護(hù)資源的功能失效了幢妄。有一個(gè)辦法可以兼顧超時(shí)時(shí)間和鎖失效的問題,退款服務(wù)保持心跳通知鎖服務(wù)茫负,鎖服務(wù)收到心跳后延長(zhǎng)鎖的超時(shí)時(shí)間蕉鸳,不足在于即使退款服務(wù)已經(jīng)宕機(jī),鎖服務(wù)仍然需要到達(dá)超時(shí)時(shí)間后才會(huì)解鎖忍法。Redisson分布式鎖就是采用這種方式潮尝。分布式鎖時(shí)效設(shè)置的必要性:確保在未來(lái)的一定時(shí)間內(nèi),無(wú)論獲得鎖的節(jié)點(diǎn)發(fā)生了什么問題饿序,最終鎖都能被釋放掉勉失。

性能
針對(duì)訪問量大的共享資源,嘗試自旋方式獲取鎖時(shí)的長(zhǎng)時(shí)間等待原探,即容易造成CPU空轉(zhuǎn)性能的消耗乱凿,又容易造成節(jié)點(diǎn)阻塞;而每隔一段時(shí)間嘗試獲取鎖咽弦,便無(wú)法保證資源的高效利用徒蟆。基于以上兩種解決方案的弊端型型,可以采用嘗試獲取鎖一定次數(shù)后后专,加入到等待隊(duì)列中,當(dāng)鎖釋放后输莺,通知等待隊(duì)列中的下一個(gè)等待節(jié)點(diǎn)獲取鎖。既可以避免CPU空轉(zhuǎn)帶來(lái)的性能消耗裸诽,又可以及時(shí)響應(yīng)嫂用,保證系統(tǒng)的性能和穩(wěn)定性,避免毛刺的出現(xiàn)丈冬。設(shè)計(jì)上可以參考Java并發(fā)包中AQS嘱函。

鎖饑餓
一個(gè)線程在嘗試獲取鎖的過(guò)程中一直無(wú)法獲取鎖,這種情況就是鎖饑餓埂蕊,比如體弱的狼很難在一群強(qiáng)壯的狼群中搶到食物往弓,很多情況下鎖饑餓是由于優(yōu)先級(jí)較低造成的疏唾。發(fā)生鎖饑餓時(shí),無(wú)法獲取鎖便無(wú)法進(jìn)行鎖保護(hù)資源的操作函似。為避免鎖饑餓情況的發(fā)生槐脏,設(shè)計(jì)時(shí)需要將鎖設(shè)計(jì)成公平鎖。

監(jiān)控
監(jiān)聽鎖的運(yùn)行情況撇寞,掌握鎖持有者的動(dòng)態(tài)顿天,若判斷鎖持有者處于不活動(dòng)狀態(tài),要能夠強(qiáng)制釋放其持有的鎖蔑担,引入第三方監(jiān)控系統(tǒng)牌废。

當(dāng)然,分布式鎖還有一些其他的問題:比如頻繁獲取鎖釋放鎖帶來(lái)的系統(tǒng)穩(wěn)定和性能問題啤握,如何保證鎖的高可用鸟缕,分布式鎖的持久化,分布式鎖單點(diǎn)問題排抬,分布式鎖網(wǎng)絡(luò)傳輸性能等懂从,還有分布式鎖主節(jié)點(diǎn)宕機(jī),從節(jié)點(diǎn)還沒同步到鎖畜埋,鎖的唯一性被破壞莫绣,多個(gè)客戶端可以獲得同一個(gè)鎖…

原文鏈接:http://geyifan.cn/2017/02/11/what-problems-when-using-distributed-locks/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市悠鞍,隨后出現(xiàn)的幾起案子对室,更是在濱河造成了極大的恐慌,老刑警劉巖咖祭,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掩宜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡么翰,警方通過(guò)查閱死者的電腦和手機(jī)牺汤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)浩嫌,“玉大人檐迟,你說(shuō)我怎么就攤上這事÷肽停” “怎么了追迟?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)骚腥。 經(jīng)常有香客問我敦间,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任廓块,我火速辦了婚禮厢绝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘带猴。我一直安慰自己昔汉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布浓利。 她就那樣靜靜地躺著挤庇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贷掖。 梳的紋絲不亂的頭發(fā)上嫡秕,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音苹威,去河邊找鬼昆咽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛牙甫,可吹牛的內(nèi)容都是我干的掷酗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼窟哺,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼泻轰!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起且轨,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤浮声,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后旋奢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泳挥,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年至朗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屉符。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锹引,死狀恐怖矗钟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嫌变,我是刑警寧澤真仲,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站初澎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碑宴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一软啼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧延柠,春花似錦祸挪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至增热,卻和暖如春整以,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背峻仇。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工公黑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摄咆。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓凡蚜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親吭从。 傳聞我的和親對(duì)象是個(gè)殘疾皇子朝蜘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 鎖 分布式鎖 distributed locks 資源有限,爭(zhēng)搶難免涩金,最簡(jiǎn)單粗暴的辦法是誰(shuí)的拳頭大誰(shuí)就可以搶到最好...
    曲水流觴TechRill閱讀 11,474評(píng)論 9 43
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理谱醇,服務(wù)發(fā)現(xiàn),斷路器鸭廷,智...
    卡卡羅2017閱讀 134,633評(píng)論 18 139
  • 我初中的時(shí)候還是一個(gè)不知世事的孩子枣抱,很崇拜那些學(xué)校里的校園人物,自己也加入他們辆床。很崇拜一位學(xué)姐佳晶,她喜歡別人叫她田哥...
    LEEJONGSUK98閱讀 215評(píng)論 0 1
  • 數(shù)組中可以包含任何數(shù)據(jù)類型的元素 var arr = [10,8,'hello',null,true,3.1415...
    夏臻Rock閱讀 188評(píng)論 0 0
  • 周末和帝都的產(chǎn)品朋友在一起胡侃的時(shí)候咨堤,提到一個(gè)問題菇篡,如果這兩三年行業(yè)泡沫爆發(fā),一些沒有商業(yè)模式的公司倒閉或轉(zhuǎn)行一喘,那...
    Nick777閱讀 310評(píng)論 0 1