在分佈式系統中,分佈式鎖是爲了解決多實例之間的同步問題。例如master選舉,可以獲取分佈式鎖的就是master,獲取失敗的就是slave。又或者可以獲取鎖的實例可以完成特定的操做。redis
目前比較經常使用的分佈式鎖實現有兩種,基於zookeeper實現和基於redis實現。zookeeper和redis也是生產環境中常常用到的第三方組件。下面我會分析它們的實現原理。算法
分佈式鎖實現要求安全
實現一個分佈式鎖至少要知足下面三點要求:網絡
zookeeper分佈式鎖dom
在講解zookeeper的分佈式鎖以前有兩個概念須要明確:異步
zookeeper的分佈式鎖實現原理就是利用臨時順序節點,大概流程爲:分佈式
例如,對於加鎖過程,全部的客戶端都在/lock目錄下面建立臨時節點,若是發現本身建立的臨時節點是/lock目錄中最小的節點,那麼就獲取鎖成功,不然就watch比本身小的節點中的最大節點。性能
監控比本身小的節點中的最大節點是爲了不「驚羣」效應,避免一個鎖釋放把全部等待的客戶端喚醒,可是隻有一個客戶端能獲取鎖。大數據
對於釋放鎖,只須要把本身建立的臨時順序節點刪除便可。整個過程流程圖以下:cdn
優勢:鎖安全性高,zookeeper數據不易丟失。用戶使用簡單。
缺點:性能消耗比較高。由於須要動態產生和刪除臨時節點,當集羣負載比較高時臨時節點消失會有時間差(通常在一分鐘範圍內)。
redis分佈式鎖
redis的分佈式鎖實現比zookeeper分佈式鎖實現複雜,也分爲redis單實例和多實例(master-master)實現方式。
須要特別指出的是redis若是是master-slave這種結構部署時,獲取和釋放鎖都只能向master請求,和單實例的實現原理基本同樣,不然主從切換時會出現多人拿到同一把鎖的狀況。
例如:
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,一個客戶端獲取鎖的過程以下:
獲取鎖成功的節點數須要超過master節點數量的一半才認爲是獲取鎖成功的思路應該是借鑑了zookeeper的paxos算法。
還有一個須要指出的點是,當一個客戶端獲取失敗時應該隨時延時後再進行重試,避免多個客戶端同時重試又同時失敗。
優勢:性能高
缺點:單實例會有單點問題,多實例主從切換會致使數據丟失,master-master集羣模式實現複雜。
看大佬給你講解基於Zookeeper、Redis的分佈式鎖