Zookeeper實現分布式鎖


1.什么是分布式鎖

         為了防止分布式系統中的多個進程之間相互干擾,我們需要一種分布式協調技術來對這些進程調度,而這種分布式協調技術的核心就是分布式鎖

2.分布式鎖應該具備的條件

  • 一個方法在同一時間只能被一個機器的一個線程執行。 
  • 高可用的獲取鎖與釋放鎖。
  • 高性能的獲取鎖與釋放鎖。
  • 具備可重入特性。
  • 具有鎖失效機制,防止死鎖。
  • 具備非阻塞特性,即沒有獲取鎖將直接返回獲取鎖失敗。    

3.redis實現分布式鎖

       分布式鎖實現的三個核心要素:加鎖、解鎖、鎖超時。

     (1)加鎖

              以雙11秒殺商品為例討論。小明對商品A進行購買操作,此時小明會使用 setnx(prodId,threadId) 命令,來對商品加鎖。若此時執行命令之后返回 1 ,則說明小明加鎖成功。小紅在同一時間做相同操作,返回 0 ,則說明小紅加鎖失敗。

     (2)解鎖

              小明購買完商品之后要立即釋放鎖,提供給包括小紅在內的其他購買者使用,小明此時執行del(prodId)命令,將鎖釋放。

     (3)鎖超時

              如果小明在購買的過程中,突然網斷了,獲取了鎖,但是沒有釋放鎖,那之后的購買者只有等待。所以為了解決這種 死鎖 的問題,小明在加鎖時,必須執行 expire(prodId,30) 給鎖設置一個超時時間,來保證即使沒有顯示的釋放鎖,這把鎖在一定時間之后也能自動釋放。

  偽代碼如下:

if(setnx(prodId,threadId) == 1){
    expire(prodId,30)
    try {
        do something ......
    } finally {
        del(prodId)
    }
}

  

4.以上偽代碼中存在三個致命問題

   (1) setnx 和 expire 的非原子性

        setnx 與 expire 是分兩步進行操作的,如果執行完setnx操作之后,還沒執行 expire 命令設置超時時間,網絡斷掉,此時造成死鎖。

        出現這個問題的根本原因在於setnx與expire是分兩步進行的,如果這兩個操作時原子性的,將很好的避免這種問題,所以redis提供了解決方案:在加鎖的同時,設置超時時間。

set(prodId,threadId,30

   (2) 誤刪操作

        小明在購買商品加鎖時設置的鎖超時時間時30s,但是30s之后小明仍然沒有購買完成,此時redis自動釋放鎖,小紅獲得了鎖,在小紅購物的過程中,小明購買完成,需要刪除鎖,誤將小紅的鎖刪除。

        為了避免這個問題,在加鎖時,小明需要將自己的線程Id當作參數傳進去。

String threadId = Thread.currentThread().getId()
set(key,threadId ,30

       在解鎖時先判斷是不是自己的鎖,如果是自己的鎖,再進行刪除鎖的操作。

if(threadId .equals(redisClient.get(key))){
    del(key)
}

  (3)同一時間兩個線程訪問同一資源

         上述情況會出現同一時間兩個線程訪問同一資源的情況。為了盡量避免這種情況,我們可以給獲得鎖的線程去開啟一個守護進程,當到達超時時間時,如果還沒有進行完自己的操作,守護進程,給該進程加部分時間,當該線程處理完自己的任務之后,會顯示的關閉掉守護進程。如果沒有處理完成,斷網了,守護進程會自動終止,到達超時時間時,該線程就將鎖釋放了。     

5.Zookeeper如何實現分布式鎖

   (1)四種Zonde節點

  • 持久節點       

   默認的節點類型。創建節點的客戶端與Zookeeper斷開連接之后,該節點依舊存在。

  • 持久順序節點

   在創建節點時,zookeeper會根據創建的時間將節點進行排序。

  • 臨時節點

   和持久節點想相反。當創建節點的客戶端與zookeeper斷開連接之后,臨時節點會被刪除。

  • 臨時順序節點

   當創建節點時,zookeeper會根據節點的創建時間的先后順序進行排序,當創建節點的客戶端與Zookeeper斷開連接之后,臨時節點會被刪除。

 

   (2)zookeeper 分布式鎖原理

           zookeeper實現分布式鎖就是應用了臨時順序節點,具體流程如下:

            ① 100名客戶在極短的時間內去訪問商品服務,進行購買商品的操作。

            ② 獲取鎖

                 zookeeper創建100個臨時順序節點,這些節點按照請求的先后順序進行排序。排名第一的 req1 優先獲取鎖,排名第二 req2 的向只比他靠前一名的 req1 注冊Watcher,排名第三的 req3 向 req2 注冊Watcher,依次類推。

            ③ 釋放鎖

        ◉正常執行完釋放鎖

            當 req1 執行完成之后,zookeper會刪除該節點,排名第二的 req2 獲得鎖,依次類推。            

        ◉客戶端崩潰釋放鎖

           當排名第一的用戶在購買時斷網,因為zookeeper為其創建的是臨時順序節點,此時排名第一的用戶獲得的鎖也將釋放。排名第二的用戶獲得鎖。

 

6.redis與zookeeper的分布式鎖比較         

分布式鎖 優點 缺點
zookeeper

1.有封裝好的框架,容易實現

2.有等待鎖的隊列,大大提高搶鎖效率

 

添加和刪除節點性能較低
redis set與del命令性能高 實現復雜,沒有等待隊列,容易出現羊群效應

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM