Java架構-阿里架構師手把手帶你實現基於Zookeeper、Redis的分佈式鎖

在分佈式系統中,分佈式鎖是爲了解決多實例之間的同步問題。例如master選舉,可以獲取分佈式鎖的就是master,獲取失敗的就是slave。又或者可以獲取鎖的實例可以完成特定的操做。程序員

在分佈式系統中,分佈式鎖是爲了解決多實例之間的同步問題。例如master選舉,可以獲取分佈式鎖的就是master,獲取失敗的就是slave。又或者可以獲取鎖的實例可以完成特定的操做。redis

目前比較經常使用的分佈式鎖實現有兩種,基於zookeeper實現和基於redis實現。zookeeper和redis也是生產環境中常常用到的第三方組件。下面我會分析它們的實現原理。算法

小編最近將收集的Java程序員進階架構師的資料作了一些整理,資料適合1-5年的Java開發者,須要的朋友能夠領取 https://w.url.cn/s/AnCuiWo安全

分佈式鎖實現要求網絡

實現一個分佈式鎖至少要知足下面三點要求:架構

互斥,在任什麼時候候同一個鎖只能由一個客戶端持有。dom

不會死鎖,就算持有的客戶端異常崩潰也不會影響後續客戶端加鎖。異步

誰加鎖誰解鎖,加鎖和解鎖都必須是同一個客戶端。分佈式

zookeeper分佈式鎖性能

在講解zookeeper的分佈式鎖以前有兩個概念須要明確:

臨時節點:生命週期和連接週期一致。例如客戶端連接A建立了臨時節點NodeA,若是連接A關閉或者網絡異常斷開,那麼NodeA也會跟着消失。

順序節點:節點名稱按照順序從小到大建立,例如先建立了000000001,那麼接着建立的節點就會分配000000002。

zookeeper的分佈式鎖實現原理就是利用臨時順序節點,大概流程爲:

每一個客戶端對某個功能加鎖時,在zookeeper指定目錄下生成一個惟一的臨時順序節點。

全部臨時節點中序號最小的節點即爲當前鎖的持有者。

釋放鎖時將本身持有的臨時節點刪除便可。

例如,對於加鎖過程,全部的客戶端都在/lock目錄下面建立臨時節點,若是發現本身建立的臨時節點是/lock目錄中最小的節點,那麼就獲取鎖成功,不然就watch比本身小的節點中的最大節點。

監控比本身小的節點中的最大節點是爲了不「驚羣」效應,避免一個鎖釋放把全部等待的客戶端喚醒,可是隻有一個客戶端能獲取鎖。

對於釋放鎖,只須要把本身建立的臨時順序節點刪除便可。整個過程流程圖以下: file

優勢:鎖安全性高,zookeeper數據不易丟失。用戶使用簡單。

缺點:性能消耗比較高。由於須要動態產生和刪除臨時節點,當集羣負載比較高時臨時節點消失會有時間差(通常在一分鐘範圍內)。

redis分佈式鎖

redis的分佈式鎖實現比zookeeper分佈式鎖實現複雜,也分爲redis單實例和多實例(master-master)實現方式。

須要特別指出的是redis若是是master-slave這種結構部署時,獲取和釋放鎖都只能向master請求,和單實例的實現原理基本同樣,不然主從切換時會出現多人拿到同一把鎖的狀況。

例如:

客戶端A在master拿到了鎖。

master節點在把A建立的key寫入slave以前宕機了。(主從同步是異步操做)

slave變成了master節點。

B也獲得了和A還持有的相同的鎖,由於slave尚未A持有鎖的信息。

redis單實例實現方案

經過下面命令得到鎖:

SET resource_name my_random_value NX PX 30000

這個命令的做用是隻有這個key不存在時纔會設置這個key的值(NX的做用,即not exist),超時時間設置爲30000毫秒(PX的做用),這個key的值設置爲my_random_value。這個值必須在全部獲取鎖請求的客戶端裏面保持惟一。

key值的超時時間,也叫作「鎖有效時間」。這是鎖的自動釋放時間。

這套實現方案在非分佈式的、單點的、保證永不宕機的環境是適用的。

redis集羣實現方案(Redlock算法)

在分佈式版本的算法裏咱們假設有N個redis master節點,這些節點徹底獨立,不用任何的複製或者分佈式協調算法來同步數據。

這裏假設N=5,一個客戶端獲取鎖的過程以下:

獲取當前以毫秒爲單位的時間。

輪詢用相同的key在N個節點上面請求鎖。(每一個請求的超時時間設置的短一些,爲了一個master節點不用時,快速請求下一個master)。

若是在超過一半master節點上面成功獲取鎖(這裏是3個),客戶端計算第二步請求鎖花費的時間,若是小於鎖釋放時間,則認爲獲取鎖成功。

若是鎖獲取成功了,那麼如今 鎖自動釋放時間=最初鎖釋放時間-請求鎖花費的時間

若是獲取鎖失敗了(成功的鎖不超過master數量的通常 或者 請求耗時>鎖釋放時間),那麼客戶端都會在每一個master節點上面釋放鎖。

獲取鎖成功的節點數須要超過master節點數量的一半才認爲是獲取鎖成功的思路應該是借鑑了zookeeper的paxos算法。

還有一個須要指出的點是,當一個客戶端獲取失敗時應該隨時延時後再進行重試,避免多個客戶端同時重試又同時失敗。

優勢:性能高

缺點:單實例會有單點問題,多實例主從切換會致使數據丟失,master-master集羣模式實現複雜。

看大佬給你講解基於Zookeeper、Redis的分佈式鎖

file

file

相關文章
相關標籤/搜索