阿里面試官:Redis的分布式鎖和Zookeeper的有啥區(qū)別?為啥要用它?
在分布式鎖的實(shí)現(xiàn)方案中,通常就是數(shù)據(jù)庫、Redis 以及 Zookeeper 這三種,關(guān)于分布式鎖的多種實(shí)現(xiàn)方式及原理我們這里不展開了。
圖片
本文主要聚焦 Redis 的分布式鎖和Zookeeper 的分布式鎖之間的區(qū)別,以及如何選擇。
其實(shí)在功能上,Redis 的分布式鎖和 ZK 的分布式鎖都能實(shí)現(xiàn)我們想要的功能,鎖的互斥、重入等等。他們主要有以下幾個(gè)區(qū)別:
性能區(qū)別
在性能方面,Redis 是基于內(nèi)存存儲(chǔ)的,而 ZK 是基于磁盤存儲(chǔ)的,所以,在性能上,Redis 要比 ZK 更好一些。
自動(dòng)釋放
ZK 的鎖的實(shí)現(xiàn)原理是基于客戶端和服務(wù)端的連接來保證的,一旦連接斷了,鎖就會(huì)被自動(dòng)釋放。而 Redis 的鎖是需要自己主動(dòng)加鎖和解鎖的,除非達(dá)到了超時(shí)時(shí)間,否則不會(huì)自動(dòng)釋放。
所以,ZK 的分布式鎖可以更好的應(yīng)對(duì)客戶端崩潰的情況,一旦客戶端崩潰,鎖就會(huì)釋放,而 Redis 實(shí)現(xiàn)的分布式鎖,一旦客戶端崩潰了,就沒有人去進(jìn)行釋放了,只能等超時(shí)。
鎖能自動(dòng)釋放有啥好處?除了提升并發(fā)度以外,還有個(gè)好處就是可以減少死鎖發(fā)生的概率。因?yàn)殒i釋放了,所以就不會(huì)出現(xiàn)死鎖了。
一致性&可用性要求(CAP)
我們分別介紹過關(guān)于 Redis和 Zookeeper 的 CAP 的實(shí)現(xiàn)情況,我們知道ZK 是一個(gè) CP 的系統(tǒng),也就是他是保證強(qiáng)一致性的,而 Redis 是一個(gè) AP 的系統(tǒng),它是保證可用性的。
ZK 會(huì)犧牲可用性來保證數(shù)據(jù)的一致性,即出現(xiàn)部分節(jié)點(diǎn)宕機(jī)后,集群中少于一半的節(jié)點(diǎn)后,或者集群正在進(jìn)行 master 選舉時(shí),都會(huì)拒絕新的寫請(qǐng)求,導(dǎo)致無法加鎖。
而Redis 會(huì)犧牲一致性性來保證可用性,即 Redis 的集群中在做數(shù)據(jù)同步時(shí),如果出現(xiàn)網(wǎng)絡(luò)延遲,那么即使多個(gè)節(jié)點(diǎn)上面的數(shù)據(jù)不一樣,客戶端也可以正常的進(jìn)行寫入和讀取。
那么,在使用 ZK 的分布式鎖的時(shí)候,不會(huì)存在鎖丟失的情況,也就是說不太會(huì)出現(xiàn)因?yàn)殒i丟失而導(dǎo)致并發(fā)的情況。但是,可能會(huì)出現(xiàn)短暫的無法加鎖的情況。
而在使用 Redis 的分布式鎖的時(shí)候,除非集群都掛了,要不然不太會(huì)出現(xiàn)無法加鎖的情況。但是可能會(huì)出現(xiàn)鎖丟失的情況,或者說是重復(fù)加鎖的情況,我們介紹 RedLock 的時(shí)候提到的單點(diǎn)故障的問題。(詳見我八股文中關(guān)于《什么是RedLock,他解決了什么問題》)
做個(gè)總結(jié)
Redis 實(shí)現(xiàn)的分布式鎖、性能更好,可用性更高。ZK 實(shí)現(xiàn)的分布式鎖可以自動(dòng)釋放,減少死鎖出現(xiàn)的概率,并且他的一致性更有保障。
所以,如果你的分布式鎖使用場景,對(duì)性能要求更高,可以犧牲一點(diǎn)一致性,那么就選擇 Redis的分布式鎖。而如果你的場景對(duì)性能要求沒那么高,但是對(duì)一致性要求非常高,那么則可以選擇 Zookeeper
But
凡事都有個(gè) but,下面就是一些經(jīng)驗(yàn)之談了。
其實(shí),如果你對(duì)可用性的要求高的話,用 Redis 也行,因?yàn)橛袀€(gè) RedLock,他的機(jī)制和 zk 很像,都是通過半數(shù)以上提交這種方式來避免因?yàn)閱吸c(diǎn)問題而導(dǎo)致鎖重復(fù)的。
但是,RedLock 其實(shí)我也不建議大家用,并且 ZK的分布式鎖我其實(shí)也不建議大家用。就直接用 Redis 就好了。(詳見我的八股文中《Redisson 中為什么要廢棄 RedLock,該用啥?》)
為啥呢?因?yàn)橐话銇碚f,我們?cè)谟梅植际芥i的時(shí)候,對(duì)性能要求肯定很高的,如果不高的話,你直接用數(shù)據(jù)庫的悲觀鎖就好了。沒必要用分布式鎖。
而且,往往我們?cè)谟梅植际芥i的時(shí)候,同時(shí)會(huì)伴隨著冪等性判斷、以及數(shù)據(jù)庫兜底的唯一性約束的校驗(yàn)。所以,即使出現(xiàn)了極端情況,因?yàn)?Redis 的一致性沒保證好,導(dǎo)致重復(fù)加鎖了,我們也能在后續(xù)的環(huán)節(jié)中識(shí)別并防止并發(fā)。
而 Redis 的不可用的問題其實(shí)可以通過哨兵、集群等運(yùn)維手段來解決的,所以,發(fā)生的概率本來就極低。所以說,日常開發(fā)的時(shí)候,只要我們把冪等判斷、唯一性約束做好,對(duì)賬最好,用 Redis 是最簡單,高效的辦法。
而且,Redis 作為一個(gè)緩存框架,很多應(yīng)用都會(huì)直接依賴,直接用SETNX 或者 Redisson 加鎖不要太方便。而 Zookeeper,很多都是中間件在使用他, 真正的業(yè)務(wù)應(yīng)用依賴的很少的,多引入一個(gè)底層中間件,對(duì)系統(tǒng)來說也會(huì)提升復(fù)雜度,減少整體的穩(wěn)定性的。
除非你真的完全接受不了不一致性,完全不能接受重復(fù)加鎖,有很愿意依賴 zookeeper,那當(dāng)我沒說,我認(rèn)為這種情況少之又少。