各種分布式鎖的實(shí)現(xiàn)以及redis和zookeeper分布式鎖對(duì)比

注:根據(jù)本人理解叁执,一切分布式協(xié)調(diào)相關(guān)的實(shí)現(xiàn),都需要引入一個(gè)第三者舶掖,如分布式注冊(cè)中心需要依賴(lài)zookeeper球昨、eureka,分布式緩存需要依賴(lài)redis眨攘、memcache等
關(guān)于分布式鎖的概念和應(yīng)用場(chǎng)景本文不作解釋?zhuān)旅鏁?huì)簡(jiǎn)述三種分布式鎖的實(shí)現(xiàn)方式
以下所有實(shí)現(xiàn)方式的demo git地址

jdk的實(shí)現(xiàn)方式

思路:另啟一個(gè)服務(wù)主慰,利用jdk并發(fā)工具來(lái)控制唯一資源嚣州,如在服務(wù)中維護(hù)一個(gè)concurrentHashMap,其他服務(wù)對(duì)某個(gè)key請(qǐng)求鎖時(shí)共螺,通過(guò)該服務(wù)暴露的端口该肴,以網(wǎng)絡(luò)通信的方式發(fā)送消息,服務(wù)端解析這個(gè)消息藐不,將concurrentHashMap中的key對(duì)應(yīng)值設(shè)為true匀哄,分布式鎖請(qǐng)求成功,demo中寫(xiě)了一個(gè)基于netty通信的分布式鎖雏蛮,當(dāng)然你想用java的bio涎嚼、nio或者整合dubbo、spring cloud feign來(lái)實(shí)現(xiàn)通信也沒(méi)問(wèn)題
缺點(diǎn):demo中的鎖寫(xiě)的非常簡(jiǎn)單挑秉,但是要考慮可用性法梯、可靠性、效率犀概、擴(kuò)展性的話立哑,編碼難度會(huì)比較高

redis的實(shí)現(xiàn)方式

原理:利用redis的setnx的特性,能夠保證同一時(shí)間內(nèi)只有一個(gè)請(qǐng)求能夠?qū)ο嗤膋ey執(zhí)行setnx指令姻灶,我們可以理解為只有一個(gè)請(qǐng)求能夠搶到這個(gè)鎖铛绰,由于redis是單線程的,可以非常簡(jiǎn)單地實(shí)現(xiàn)這個(gè)功能产喉。但是這里的鎖的概念與我們平時(shí)鎖理解的有一點(diǎn)區(qū)別捂掰,如mysql中的互斥鎖,行數(shù)據(jù)被鎖定以后镊叁,其他任何線程都無(wú)法對(duì)其進(jìn)行刪改操作尘颓,但是redis里只保證setnx的操作有這個(gè)特性,其他請(qǐng)求依然可以在key被鎖住的情況下晦譬,執(zhí)行del和set等操作,下面是redis分布式鎖的各種實(shí)現(xiàn)方式和缺點(diǎn)互广,按照時(shí)間的發(fā)展排序:

  • 1敛腌、直接setnx
    直接利用setnx,執(zhí)行完業(yè)務(wù)邏輯后調(diào)用del釋放鎖惫皱,簡(jiǎn)單粗暴
    缺點(diǎn):如果setnx成功像樊,還沒(méi)來(lái)得及釋放,服務(wù)掛了旅敷,那么這個(gè)key永遠(yuǎn)都不會(huì)被獲取到
  • 2生棍、setnx設(shè)置一個(gè)過(guò)期時(shí)間
    為了改正第一個(gè)方法的缺陷,我們用setnx獲取鎖媳谁,然后用expire對(duì)其設(shè)置一個(gè)過(guò)期時(shí)間涂滴,如果服務(wù)掛了友酱,過(guò)期時(shí)間一到自動(dòng)釋放
    缺點(diǎn):setnx和expire是兩個(gè)方法,不能保證原子性柔纵,如果在setnx之后缔杉,還沒(méi)來(lái)得及expire,服務(wù)掛了搁料,還是會(huì)出現(xiàn)鎖不釋放的問(wèn)題
  • 3或详、set nx px
    redis官方為了解決第二種方式存在的缺點(diǎn),在2.8版本為set指令添加了擴(kuò)展參數(shù)nx和ex郭计,保證了setnx+expire的原子性霸琴,使用方法:
    set key value ex 5 nx
    缺點(diǎn)
    ①如果在過(guò)期時(shí)間內(nèi),事務(wù)還沒(méi)有執(zhí)行完昭伸,鎖提前被自動(dòng)釋放沈贝,其他的線程還是可以拿到鎖
    ②上面所說(shuō)的那個(gè)缺點(diǎn)還會(huì)導(dǎo)致當(dāng)前的線程釋放其他線程占有的鎖
  • 4、加一個(gè)事務(wù)id
    上面所說(shuō)的第一個(gè)缺點(diǎn)勋乾,沒(méi)有特別好的解決方法宋下,只能把過(guò)期時(shí)間盡量設(shè)置的長(zhǎng)一點(diǎn),并且最好不要執(zhí)行耗時(shí)任務(wù)
    第二個(gè)缺點(diǎn)辑莫,可以理解為當(dāng)前線程有可能會(huì)釋放其他線程的鎖学歧,那么問(wèn)題就轉(zhuǎn)換為保證線程只能釋放當(dāng)前線程持有的鎖,即setnx的時(shí)候?qū)alue設(shè)為任務(wù)的唯一id各吨,釋放的時(shí)候先get key比較一下value是否與當(dāng)前的id相同枝笨,是則釋放,否則拋異辰已眩回滾横浑,其實(shí)也是變相地解決了第一個(gè)問(wèn)題
    缺點(diǎn):get key和將value與id比較是兩個(gè)步驟,不能保證原子性
  • 5屉更、set nx px + 事務(wù)id + lua
    我們可以用lua來(lái)寫(xiě)一個(gè)getkey并比較的腳本徙融,jedis/luttce/redisson對(duì)lua腳本都有很好的支持
    缺點(diǎn):集群環(huán)境下,對(duì)master節(jié)點(diǎn)申請(qǐng)了分布式鎖瑰谜,由于redis的主從同步是異步進(jìn)行的欺冀,master在內(nèi)存中寫(xiě)入了nx之后直接返回,客戶(hù)端獲取鎖成功萨脑,此時(shí)master節(jié)點(diǎn)掛了隐轩,并且數(shù)據(jù)還沒(méi)來(lái)得及同步,另一個(gè)節(jié)點(diǎn)被升級(jí)為master渤早,這樣其他的線程依然可以獲取鎖
  • 6职车、redlock
    為了解決上面提到的redis集群中的分布式鎖問(wèn)題,redis的作者antirez的提出了red lock的概念,假設(shè)集群中所有的n個(gè)master節(jié)點(diǎn)完全獨(dú)立悴灵,并且沒(méi)有主從同步扛芽,此時(shí)對(duì)所有的節(jié)點(diǎn)都去setnx,并且設(shè)置一個(gè)請(qǐng)求過(guò)期時(shí)間re和鎖的過(guò)期時(shí)間le称勋,同時(shí)re必須小于le(可以理解胸哥,不然請(qǐng)求3秒才拿到鎖,而鎖的過(guò)期時(shí)間只有1秒也太蠢了)赡鲜,此時(shí)如果有n / 2 + 1個(gè)節(jié)點(diǎn)成功拿到鎖空厌,此次分布式鎖就算申請(qǐng)成功
    缺點(diǎn):可靠性還沒(méi)有被廣泛驗(yàn)證,并且嚴(yán)重依賴(lài)時(shí)間银酬,好的分布式系統(tǒng)應(yīng)該是異步的嘲更,并不能以時(shí)間為擔(dān)保,程序暫停揩瞪、系統(tǒng)延遲等都可能會(huì)導(dǎo)致時(shí)間錯(cuò)誤(網(wǎng)上還有很多人都對(duì)這個(gè)方法提出了質(zhì)疑赋朦,比如full gc發(fā)生的鎖的正確性問(wèn)題,但是antirez都一一作出了解答李破,感興趣的同學(xué)可以參考一下這位同學(xué)的文章

基于zookeeper實(shí)現(xiàn)的分布式鎖

  • 1宠哄、利用臨時(shí)節(jié)點(diǎn)特性
    zookeeper的臨時(shí)節(jié)點(diǎn)有兩個(gè)特性,一是節(jié)點(diǎn)名稱(chēng)不能重復(fù)嗤攻,二是會(huì)隨著客戶(hù)端退出而銷(xiāo)毀毛嫉,因此直接將key作為節(jié)點(diǎn)名稱(chēng),能夠成功創(chuàng)建的客戶(hù)端則獲取成功妇菱,失敗的客戶(hù)端監(jiān)聽(tīng)成功的節(jié)點(diǎn)的刪除事件
    缺點(diǎn):所有客戶(hù)端監(jiān)聽(tīng)同一個(gè)節(jié)點(diǎn)承粤,但是同時(shí)只有一個(gè)節(jié)點(diǎn)的事件觸發(fā)是有效的,造成資源的無(wú)效調(diào)度
  • 2闯团、利用順序臨時(shí)節(jié)點(diǎn)特性
    zookeeper的順序臨時(shí)節(jié)點(diǎn)擁有臨時(shí)節(jié)點(diǎn)的特性辛臊,同時(shí),在一個(gè)父節(jié)點(diǎn)下創(chuàng)建創(chuàng)建的子臨時(shí)順序節(jié)點(diǎn)房交,會(huì)根據(jù)節(jié)點(diǎn)創(chuàng)建的先后順序彻舰,用一個(gè)32位的數(shù)字作為后綴,我們可以用key創(chuàng)建一個(gè)根節(jié)點(diǎn)涌萤,然后每次申請(qǐng)鎖的時(shí)候在其下創(chuàng)建順序節(jié)點(diǎn)淹遵,接著獲取根節(jié)點(diǎn)下所有的順序節(jié)點(diǎn)并排序,獲取順序最小的節(jié)點(diǎn)负溪,如果該節(jié)點(diǎn)的名稱(chēng)與當(dāng)前添加的名稱(chēng)相同,則表示能夠獲取鎖济炎,否則監(jiān)聽(tīng)根節(jié)點(diǎn)下面的處于當(dāng)前節(jié)點(diǎn)之前的節(jié)點(diǎn)的刪除事件川抡,如果監(jiān)聽(tīng)生效,則回到上一步重新判斷順序,直到獲取鎖崖堤。

總結(jié)

  • 基于jdk的并發(fā)工具自己實(shí)現(xiàn)的鎖
    優(yōu)點(diǎn):不需要引入中間件侍咱,架構(gòu)簡(jiǎn)單
    缺點(diǎn):編寫(xiě)一個(gè)可靠、高可用密幔、高效率的分布式鎖服務(wù)楔脯,難度較大
  • redis set px nx + 唯一id + lua腳本
    優(yōu)點(diǎn):redis本身的讀寫(xiě)性能很高,因此基于redis的分布式鎖效率比較高
    缺點(diǎn):依賴(lài)中間件胯甩,分布式環(huán)境下可能會(huì)有節(jié)點(diǎn)數(shù)據(jù)同步問(wèn)題昧廷,可靠性有一定的影響,如果發(fā)生則需要人工介入
  • 基于redis的redlock
    優(yōu)點(diǎn):可以解決redis集群的同步可用性問(wèn)題
    缺點(diǎn):依賴(lài)中間件偎箫,并沒(méi)有被廣泛驗(yàn)證木柬,維護(hù)成本高,需要多個(gè)獨(dú)立的master節(jié)點(diǎn)淹办;需要同時(shí)對(duì)多個(gè)節(jié)點(diǎn)申請(qǐng)鎖眉枕,降低了一些效率
  • 基于zookeeper的分布式鎖
    優(yōu)點(diǎn):不存在redis的超時(shí)、數(shù)據(jù)同步(zookeeper是同步完以后才返回)怜森、主從切換(zookeeper主從切
    換的過(guò)程中服務(wù)是不可用的)的問(wèn)題速挑,可靠性很高
    缺點(diǎn):依賴(lài)中間件,保證了可靠性的同時(shí)犧牲了一部分效率(但是依然很高)

沒(méi)有絕對(duì)完美的實(shí)現(xiàn)方式副硅,具體要選擇哪一種分布式鎖姥宝,需要結(jié)合每一種鎖的優(yōu)缺點(diǎn)和業(yè)務(wù)特點(diǎn)而定

redis分布式鎖最佳事件

直接用redisson實(shí)現(xiàn)的分布式鎖,兼容單機(jī)想许、哨兵伶授、集群,利用hash + redis訂閱監(jiān)聽(tīng)實(shí)現(xiàn)重入鎖和鎖的等待流纹。利用list + zSet實(shí)現(xiàn)公平鎖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末糜烹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子漱凝,更是在濱河造成了極大的恐慌疮蹦,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茸炒,死亡現(xiàn)場(chǎng)離奇詭異愕乎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)壁公,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)感论,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人紊册,你說(shuō)我怎么就攤上這事比肄。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵芳绩,是天一觀的道長(zhǎng)掀亥。 經(jīng)常有香客問(wèn)我,道長(zhǎng)妥色,這世上最難降的妖魔是什么搪花? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮嘹害,結(jié)果婚禮上撮竿,老公的妹妹穿的比我還像新娘。我一直安慰自己吼拥,他們只是感情好倚聚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著凿可,像睡著了一般惑折。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枯跑,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天惨驶,我揣著相機(jī)與錄音,去河邊找鬼敛助。 笑死粗卜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的纳击。 我是一名探鬼主播续扔,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼焕数!你這毒婦竟也來(lái)了纱昧?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤堡赔,失蹤者是張志新(化名)和其女友劉穎识脆,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體善已,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡灼捂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了换团。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悉稠。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖艘包,靈堂內(nèi)的尸體忽然破棺而出偎球,到底是詐尸還是另有隱情洒扎,我是刑警寧澤辑甜,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布衰絮,位于F島的核電站,受9級(jí)特大地震影響磷醋,放射性物質(zhì)發(fā)生泄漏猫牡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一邓线、第九天 我趴在偏房一處隱蔽的房頂上張望淌友。 院中可真熱鬧,春花似錦骇陈、人聲如沸震庭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)器联。三九已至,卻和暖如春婿崭,著一層夾襖步出監(jiān)牢的瞬間拨拓,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工氓栈, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渣磷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓授瘦,卻偏偏與公主長(zhǎng)得像醋界,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子提完,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348