分布式鎖上-初探
1.分布式鎖產(chǎn)生的背景
開(kāi)發(fā)人員很多時(shí)候會(huì)遇到在一個(gè)JVM實(shí)例內(nèi),多個(gè)線程要競(jìng)爭(zhēng)使用具有排它性的共享資源,恰好JDK中提供了如synchronized 、 JUC包中的xxxLock 這些鎖工具,使用它們可以方便我們實(shí)現(xiàn)對(duì)臨界資源的互斥使用;使用鎖是一種顯式同步的方式,來(lái)控制線程間操作發(fā)生相對(duì)順序的機(jī)制,除此之外其實(shí)還有另外一種隱式同步方式,即消息傳遞,但大家似乎對(duì)顯式使用鎖的方式更為熟悉一些。
現(xiàn)在的系統(tǒng)大多已演進(jìn)為分布式的架構(gòu),如實(shí)例內(nèi)多線程要互斥使用臨界資源,分布式情況下多實(shí)例之間也存在需要排它的使用共享資源,這個(gè)問(wèn)題就是分布式互斥問(wèn)題。雖然大佬Lamport 在論文 《Time, clocks, and the ordering of events in a distributed system》中早就證明了使用狀態(tài)機(jī)(如共識(shí)算法)就能夠去中心化解決多進(jìn)程互斥問(wèn)題,但我們還是會(huì)更偏向使用分布式鎖,原因大概有以下3點(diǎn):
- 使用分布式鎖服務(wù)更易于保持現(xiàn)有程序的結(jié)構(gòu)
- 程序員更熟悉用加鎖的方式來(lái)同步訪問(wèn)資源
- 共識(shí)算法可能會(huì)要求客戶端運(yùn)行在更多的服務(wù)器上以滿足共識(shí)算法要求,而實(shí)際只滿足客戶端功能性的需求卻不需要使用這么多服務(wù)器
概括來(lái)說(shuō),分布式鎖更輕便、更易用、也更節(jié)省資源。
2.使用分布式鎖的目的
使用分布式鎖的目的主要有兩種:
- 效率(Efficiency):通過(guò)鎖來(lái)避免多次做重復(fù)的工作,計(jì)算重復(fù)的內(nèi)容等等。這種場(chǎng)景下即便偶然出現(xiàn)多個(gè)用戶同時(shí)持有鎖,并同時(shí)與資源服務(wù)發(fā)生交互,也是可以忍受的。
- 正確性(Correctness):也就是“安全”,我們希望資源服務(wù)在鎖的保護(hù)下能夠做“正確”的事。更嚴(yán)謹(jǐn)?shù)恼f(shuō),我們希望任一時(shí)刻,只有一個(gè)用戶能夠訪問(wèn)資源服務(wù),而且即便鎖在該用戶與資源服務(wù)交互的中途過(guò)期,也不至于破壞資源服務(wù)的一致性。
3.分布式鎖的功能特點(diǎn)
一個(gè)分布式鎖應(yīng)具備這樣一些功能特點(diǎn):
- 互斥性:在同一時(shí)刻,只有一個(gè)客戶端能持有鎖
- 安全性:避免死鎖,如果某個(gè)客戶端獲得鎖之后處理時(shí)間超過(guò)最大約定時(shí)間,或者持鎖期間發(fā)生了故障導(dǎo)致無(wú)法主動(dòng)釋放鎖,其持有的鎖也能夠被其他機(jī)制正確釋放,并保證后續(xù)其它客戶端也能加鎖,整個(gè)處理流程繼續(xù)正常執(zhí)行。
- 可用性:也被稱作容錯(cuò)性,分布式鎖需要有高可用能力,避免單點(diǎn)故障,當(dāng)提供鎖的服務(wù)節(jié)點(diǎn)故障(宕機(jī))時(shí)不影響服務(wù)運(yùn)行,這里有兩種模式:一種是分布式鎖服務(wù)自身具備集群模式,遇到故障能自動(dòng)切換恢復(fù)工作;另一種是客戶端向多個(gè)獨(dú)立的鎖服務(wù)發(fā)起請(qǐng)求,當(dāng)某個(gè)鎖服務(wù)故障時(shí)仍然可以從其他鎖服務(wù)讀取到鎖信息(Redlock)
- 可重入性:對(duì)同一個(gè)鎖,加鎖和解鎖必須是同一個(gè)進(jìn)程,即不能把其他進(jìn)程持有的鎖給釋放了。
- 高效靈活:加鎖、解鎖的速度要快;支持阻塞和非阻塞;支持公平鎖和非公平鎖。
4.多視角下的分布式鎖
通過(guò)不同視角,可以從多維度充分了解各種分布式鎖的實(shí)現(xiàn)差異
視角1:
- 輪詢類:基于數(shù)據(jù)庫(kù)和基于 Redis 實(shí)現(xiàn)的分布式鎖,這類實(shí)現(xiàn)需要客戶端不停反復(fù)請(qǐng)求鎖服務(wù)以查看是否能夠獲取到鎖;
- 監(jiān)聽(tīng)類:基于 ZooKeeper 或 etcd 實(shí)現(xiàn)的分布式鎖,這類實(shí)現(xiàn)客戶端只需監(jiān)聽(tīng)(watch) 某個(gè) key,當(dāng)鎖可用時(shí)鎖服務(wù)會(huì)通知客戶端,無(wú)需客戶端不停請(qǐng)求鎖服務(wù)。
視角2:
基于數(shù)據(jù)庫(kù)實(shí)現(xiàn)的分布式鎖:使用樂(lè)觀鎖、悲觀鎖或基于主鍵唯一約束來(lái)實(shí)現(xiàn)
基于分布式緩存實(shí)現(xiàn)分布式鎖:Redis 和基于 Redis 的 RedLock(Redisson)
基于分布式一致性算法實(shí)現(xiàn)的分布式鎖:ZooKeeper、 Etcd
視角3:
Martin Kleppmann 在個(gè)人博客中發(fā)了一篇文章 How to do distributed locking,其中涉及了大量對(duì) Redlock 算法安全性的質(zhì)疑,Salvatore Sanfilippo(Redis 的創(chuàng)始人,也是這里 Redlock 算法的作者)隨后發(fā)表 Is Redlock safe? 回應(yīng)這些質(zhì)疑;這兩位大佬的對(duì)決一定要圍觀。
本文轉(zhuǎn)載自微信公眾號(hào)「架構(gòu)染色」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系【架構(gòu)染色】公眾號(hào)作者。