分佈式鎖是啥?zk還是redis?

 關於分佈式系統中應該考慮的幾個問題包括諸如最基本的分佈式鎖分佈式事務等。該篇中我們將簡單來聊聊分佈式鎖相關知識,比如常見的分佈式鎖的實現方式有哪些?redis如何設計分佈式鎖?zk如何設計分佈式鎖?以及這兩種方式哪種效率更高?

 

1.redis分佈式鎖

最常見的一種方式也被稱爲“原生方式”,即不採用任何redis相關的第三方框架的方式。

採用setnx指令的設置一個key,比如setnx mylock,這個setnx的意思就是隻有key不存在時纔會設置成功,相當於誰先創建成功誰就獲得這把鎖,然後當前線程執行完畢後就執行del mylock指令刪除該key即釋放鎖,此時其它線程就可以獲取鎖了。這是redis中最常見的一種做法。

不過顯然僅僅這樣還是不行的,比如如果在釋放鎖之前發生了異常或者當前服務宕機,將會導致鎖無法釋放,這樣其它線程就永遠不可能獲取這把鎖了,這就是我們常說的死鎖

所以一般的做法就是我們在設置key的時候加上一個過期時間setnx mylock 30 比如設置該key的過期時間爲expire 30 30s這樣在30s後就會自動刪除該key釋放鎖

但是這樣其實還不夠,試想如果當前線程在30s過期時間內業務還沒執行完,但是鎖已經釋放,而此時其它線程已經搶佔到了鎖如果當前線程剛好執行完然後去刪除key的話就會有大問題,因爲此時的key也就是“鎖”已經不屬於你了,你會把原本屬於其它線程的鎖給釋放掉,很明顯接下來就全亂套了,你爲什麼要刪別人鎖啊啊。。。

因此,我們在設置key加鎖的時候一般要帶上一個標識,這個標識可以放到value中,用來標識當前鎖所屬的線程,釋放鎖刪除key的時候根據value判斷下當前鎖是否屬於你。

綜上所述,有沒有發現redis實現分佈式鎖真的是又“簡單”又“複雜”,簡單到一條指令就可以搞定,複雜的是你需要考慮各種可能出現的異常情況。

因此一般情況下都是採用框架來做,比如redisson

redis鎖的原生方式大致如下圖:

 

2.zk實現分佈式鎖

zk實現分佈式鎖的原理很簡單實現也很方便,zk採用的是創建臨時節點node的方式實現的,即誰創建某個指定的臨時節點node成功,誰就獲取到了這把鎖;其它線程來創建節點就會失敗也就無法獲取鎖,然後通過註冊watch監聽事件來監聽這個節點。釋放鎖就是刪除該節點node,一旦該節點刪除就會通知其它註冊過監聽事件的線程(服務宕機也會自動刪除該臨時節點,所以不用擔心死鎖問題),其它線程就會來重新創建節點搶佔鎖,這就是原生zk實現分佈式鎖的基本原理。

當然,一般實際情況中都會採用成熟框架的方式創建分佈式鎖,比如curator,其原理是與原生框架略有區別,是通過創建臨時順序節點的方式實現的,即所有線程都可以創建一個節點,根據創建順序依次排序其中第一號最小節點client1獲取鎖,其它線程創建的節點依次對上一個節點註冊監聽事件,比如client2對client1註冊監聽事件,client3對client2註冊監聽事件,當上一個節點刪除時,下一個節點會成爲最小的“一號”節點,獲取鎖成功。比如client1刪除了節點,那麼client2接收到通知,此時client2稱爲了最小節點因此client2就獲取到了鎖,依次類推。

zk分佈式鎖大致原理如下圖:

 

 

其實要做選擇的話,看公司的場景,如果公司是以redis爲主的可以選用redis做分佈式鎖,如果公司使用了zookeeper框架,個人覺得可以考慮zookeeper做分佈式鎖!

 

關注微信公衆號“蝦米聊吧”,獲取更多技術知識乾貨喲~

           掃碼關注微信公衆號

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章