來(lái)源:北大青鳥(niǎo)總部 2020年11月03日 09:33
當(dāng)下在互聯(lián)網(wǎng)技術(shù)架構(gòu)中,最流行的莫過(guò)于分布式架構(gòu)了。為什么大家紛紛都采用分布式架構(gòu)呢?
1、高效低廉,將部署在高性能機(jī)的程序分散在多個(gè)小型機(jī)中部署;
2、擴(kuò)展性強(qiáng),可隨著業(yè)務(wù)的擴(kuò)展而橫向擴(kuò)展系統(tǒng)的性能;
3、可靠性強(qiáng),當(dāng)系統(tǒng)中一臺(tái)或幾臺(tái)出現(xiàn)故障時(shí),仍然有其它機(jī)器在提供服務(wù);
4、并發(fā)性強(qiáng),各臺(tái)機(jī)器同時(shí)運(yùn)作提供服務(wù)。
分布式,真香!
不過(guò)使用分布式架構(gòu)也會(huì)存在一些問(wèn)題,最嚴(yán)重的問(wèn)題便是數(shù)據(jù)一致性問(wèn)題。因?yàn)闃I(yè)務(wù)是部署在多臺(tái)機(jī)器上,由于時(shí)間空間的不一致,從而導(dǎo)致數(shù)據(jù)會(huì)不一樣,分布式的CAP理論已經(jīng)告訴我們“分布式系統(tǒng)無(wú)法同時(shí)滿(mǎn)足一致性Consistency、可用性Availability、分區(qū)容錯(cuò)性Partitiontolerance,最多滿(mǎn)足兩項(xiàng)”。對(duì)于數(shù)據(jù)不一致的問(wèn)題,互聯(lián)網(wǎng)有幾種思考,比如BASE服務(wù)基本可用,犧牲暫時(shí)的數(shù)據(jù)不一致,只要數(shù)據(jù)最終一致即可;采用分布式事務(wù)進(jìn)行解決;采用分布式鎖進(jìn)行解決。而今天我們要介紹的便是分布式鎖的解決方案。
首先來(lái)看一個(gè)具體的case解釋為什么需要分布式鎖。在電商業(yè)務(wù)采用分布式架構(gòu)后,程序部署在3個(gè)tomcat容器中(1個(gè)tomcat容器代表一個(gè)服務(wù)器,3個(gè)tomcat可理解在北京上海深圳都有部署電商服務(wù)),成員變量A代表商品數(shù)量。在北京的Alice,上海的Bob,深圳的Tom,都分別發(fā)起了購(gòu)買(mǎi)或取消iPhone12的用戶(hù)請(qǐng)求,經(jīng)過(guò)Nginx負(fù)載均衡將Alice的請(qǐng)求發(fā)給了北京服務(wù)器,Bob的請(qǐng)求發(fā)給了上海服務(wù)器,Tom的請(qǐng)求發(fā)給了深圳服務(wù)器,這時(shí)候每臺(tái)服務(wù)器都會(huì)對(duì)iPhone12這個(gè)商品數(shù)量進(jìn)行更改,Alice的請(qǐng)求是將商品數(shù)量加到200,Bob的請(qǐng)求是將商品數(shù)量減少100,Tom的請(qǐng)求是將商品數(shù)量加1,如果對(duì)于商品數(shù)量的修改沒(méi)有任何限制,整體就會(huì)亂起來(lái),可能Bob的先減少,Tom的在增加,數(shù)據(jù)就完全亂了,所以需要分布式鎖解決方案。
鎖的概念并不是在分布式中才存在,傳統(tǒng)互聯(lián)網(wǎng)的開(kāi)發(fā)中也存在鎖。比如在多進(jìn)程處理請(qǐng)求時(shí),內(nèi)存資源就會(huì)不足,這時(shí)候操作系統(tǒng)會(huì)使用信號(hào)量來(lái)解決資源的搶奪,如果信號(hào)量的值大于0,則將信號(hào)量數(shù)值減1,同時(shí)分配內(nèi)存資源,如果信號(hào)量的值小于0,則進(jìn)程處于等待狀態(tài),
總結(jié)一下,實(shí)現(xiàn)鎖有三個(gè)要素:
1、有存儲(chǔ)鎖的空間,在多進(jìn)程中,內(nèi)存就是存儲(chǔ)鎖的空間,通過(guò)對(duì)鎖的控制實(shí)現(xiàn)不同進(jìn)程的訪問(wèn)控制。2、能唯一標(biāo)識(shí),不同的空間用不同的鎖保護(hù),那必須要唯一標(biāo)識(shí)。
3、有狀態(tài),即存在、不存在。在分布式系統(tǒng)環(huán)境中,分布式鎖就是一個(gè)變量一個(gè)方法在同一時(shí)間只能被一個(gè)機(jī)器的一個(gè)線程執(zhí)行,對(duì)分布式鎖的實(shí)現(xiàn)也提出了更高的要求,即需要高性能高可用的獲取與釋放鎖,需要鎖超時(shí)機(jī)制,避免死鎖出現(xiàn)。
那么如何實(shí)現(xiàn)分布式鎖呢?業(yè)內(nèi)有三種實(shí)現(xiàn)方式:
1、基于數(shù)據(jù)庫(kù);
2、基于redis;
3、基于Zookeeper。
對(duì)于第一種實(shí)現(xiàn)方案,很簡(jiǎn)單,我們知道在傳統(tǒng)數(shù)據(jù)庫(kù)中是有ACID事務(wù)原子性、一致性、持久性、可用性規(guī)則的,如果基于數(shù)據(jù)庫(kù)實(shí)現(xiàn)分布式鎖,只需要在數(shù)據(jù)庫(kù)中創(chuàng)建一個(gè)表,表中包含方法名,對(duì)方法名加上唯一索引,想要執(zhí)行該方法時(shí),就使用這個(gè)方法名向表中插入數(shù)據(jù),插入時(shí),其它數(shù)據(jù)都沒(méi)法插入,等于獲得鎖,成功插入后,刪除對(duì)應(yīng)的數(shù)據(jù)釋放鎖。這種方案的好處就是簡(jiǎn)單,但存在的問(wèn)題是對(duì)數(shù)據(jù)庫(kù)要求高,因?yàn)閿?shù)據(jù)庫(kù)的可用性、性能會(huì)直接影響分布式鎖的可用性,數(shù)據(jù)庫(kù)可能需要主從部署、讀寫(xiě)分離。
對(duì)于第二種實(shí)現(xiàn)方案,只需要使用redis的命令setnx、expire、delete就可以了(請(qǐng)?jiān)试S我再感嘆一下,redis真的太好用了,又簡(jiǎn)單性能又好),setnxkeyvalue就會(huì)給某個(gè)變量賦予一個(gè)值,返回1,當(dāng)業(yè)務(wù)請(qǐng)求來(lái)時(shí),如返回key值為1,線程獲得鎖,如果key值為0,線程搶鎖失敗。
對(duì)于第三種實(shí)現(xiàn)方案,我們知道zookeeper是一個(gè)分布式協(xié)調(diào)服務(wù),它內(nèi)部是一個(gè)分層的文件系統(tǒng)目錄樹(shù)結(jié)構(gòu),同一個(gè)目錄下只能有一個(gè)唯一文件名,因此當(dāng)實(shí)現(xiàn)分布式鎖時(shí),只需要?jiǎng)?chuàng)建一個(gè)目錄,線程想要獲取鎖就在目錄下創(chuàng)建臨時(shí)順序節(jié)點(diǎn),然后遍歷獲取是否存在比自己小的節(jié)點(diǎn),如果存在則獲取鎖失敗,如果不存在則獲取鎖成功,缺點(diǎn)就是會(huì)頻繁的創(chuàng)建節(jié)點(diǎn)。
通過(guò)本文的介紹,認(rèn)真閱讀的小伙伴又獲得了分布式架構(gòu)使用的一個(gè)技巧。在分布式環(huán)境中,對(duì)資源的上鎖非常重要,通過(guò)分布式鎖解決了數(shù)據(jù)的一致性問(wèn)題,小伙伴們可以根據(jù)自己業(yè)務(wù)實(shí)際情況選擇合適的分布式鎖方案噢~