9、Zookeeper分佈式鎖原理淺析

瞭解Zookeeper的我們都知道,Zookeeper是一種分佈式協調服務,在分佈式應用中,主要用來實現分佈式服務的註冊與發現以及分佈式鎖,本文我們簡單介紹一下使用Zookeeper實現分佈式鎖的簡單原理。

使用Zookeeper實現分佈式鎖,主要是基於Zookeeper的臨時順序節點來實現的,因此首先我們先簡單瞭解一下Zookeeper的Znode類型。
在這裏插入圖片描述
1、Zookeeper的Znode類型

Znode分爲四種類型:

  • 持久化節點(PERSISTENT)

Zookeeper默認的節點類型,該類型的節點創建之後,若客戶端與服務端斷開連接之前沒有執行delete操作,該節點會永久存儲於服務端;

  • 持久化順序節點(PERSISTENT_SEQUENTIAL)

該類型的節點創建之後,若客戶端與服務端斷開連接之前沒有執行delete操作,該節點會永久存儲於服務端,同時該類型的節點創建之後,Zookeeper會爲該類型的節點在節點名稱的基礎上增加一個單調遞增的編號;

在這裏插入圖片描述

  • 臨時節點(EPHEMERAL)

該類型的節點創建完成之後,若客戶端與服務端斷開連接之前沒有執行delete操作,Zookeeper會自動刪除該類型的節點;
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

  • 臨時順序節點

該類型的節點創建完成之後,若客戶端與服務端斷開連接之前沒有執行delete操作,Zookeeper會自動刪除該類型的節點,同時該類型的節點創建之後,Zookeeper會爲該類型的節點在節點名稱的基礎上增加一個單調遞增的編號;

2、什麼是分佈式鎖

在分佈式系統當中,爲了防止多個進程(或線程)在對臨界資源進行寫操作時,造成資源信息的不一致或髒數據的情況發生,需要一個分佈式協調技術來對這些分佈式的進程(或線程)進行協調,保證多個分佈式的進程(或線程)對同一臨界資源進行寫操作都是同步且有序的,這樣的一種分佈式協調技術我們就稱之爲分佈式鎖。

  • 應用場景舉例

比如在我們某些電商平臺的秒殺活動中,對商品庫存進行更新時,就會經常要用到分佈式鎖。
在這裏插入圖片描述
如上圖,假設我們現在有一個商品A,它的總庫存是100,客戶端發出了4個秒殺請求,每個訂單的數量是100個,4個請求到達應用集羣后,邏輯處理分別被負載分配到了商品服務A、商品服務B、商品服務C、商品服務D進行處理。
在這裏插入圖片描述
按照正常的業務邏輯,商品庫存爲100,那麼當商品服務A執行完畢並進行商品庫存扣減之後,庫存就變爲0,服務B、C、D執行庫存檢測時就應該得到庫存爲0,直接返回庫存不足即可。

但是假設我們對商品的庫存檢查和扣減服務沒有做同步處理,那麼就有可能出現多個服務同時執行庫存扣減的可能性,從而會造成庫存的多扣或少扣,對業務造成影響,如果這種情況在電商平臺出現,那是相當恐怖的事情。

同時,除了秒殺場景外,賬戶充值,支付場景中,也都需要用到分佈式鎖。

  • 分佈式鎖需要具備的條件
  1. 在分佈式環境下,一個方法同一時刻只能被一臺機器上的一個線程執行;
  2. 高可用的獲取鎖,釋放鎖;
  3. 高性能的獲取鎖,釋放鎖;
  4. 具備可重入特性(可理解爲重新進入,由多於一個任務併發使用,而不必擔心數據錯誤);
  5. 具備鎖失效機制,避免死鎖;
  6. 具備非阻塞特性,即沒有獲取到鎖將直接返回獲取鎖失敗;

3、Zookeeper分佈式鎖原理淺析

在對Zookeeper的節點類型有了初步瞭解之後,咱們就可以簡單的介紹一下使用Zookeeper如何來實現分佈式鎖。

Zookeeper 分佈式鎖應用了其臨時順序節點的特性。具體如何實現呢?讓我們來看一看詳細步驟:

  • 獲取鎖

首先在Zookeeper中創建一個持久節點ParentLock,當第一個客戶端要獲取鎖時,在ParentLock節點下創建一個臨時順序節點Lock1;
在這裏插入圖片描述
接下來客戶端1會獲取ParentLock下的所有臨時順序子節點並進行排序,然後與自身創建的Lock1比較,判斷Lock1是不是最小的(最靠前的),如果是最靠前的,則獲取鎖成功;
在這裏插入圖片描述
此時,假設又有一個客戶端2前來獲取鎖,則在ParentLock下創建一個臨時順序節點Lock2;
在這裏插入圖片描述
接下來客戶端2會獲取ParentLock下的所有臨時順序子節點並進行排序,然後與自身創建的Lock2比較,判斷Lock2是不是最小的(最靠前的),結果發現Lock2不是最小的;

於是,Lock2向排序比它靠前的第一個節點Lock1註冊一個Watcher,用於監聽Lock1是否存在,此時意味着客戶端2搶鎖失敗,客戶端2進入等待狀態;
在這裏插入圖片描述
此時,假設現在又有一個客戶端3前來獲取鎖,則在ParentLock下創建一個臨時順序節點Lock3;
在這裏插入圖片描述
接下來客戶端3將獲取ParentLock下的所有臨時順序節點並排序,與自身創建的節點Lock3比較,判斷Lock3是不是最小的(最靠前的),結果發現Lock3不是最小的;

於是,Lock3向比它靠前的第一個節點Lock2註冊一個Watcher,用於監聽Lock2是否存在,此時意味着Lock3也搶鎖失敗,進入阻塞狀態;
在這裏插入圖片描述
這樣的話,客戶端1獲取到了鎖,客戶端2監聽了Lock1、客戶端3監聽了Lock2;

  • 客戶端崩潰釋放鎖(避免死鎖)

假設由於網絡原因或者其他物理原因,導致客戶端1與Zookeeper失去連接,根據臨時節點的特性,Zookeeper會自動刪除相關聯的節點Lock1。
在這裏插入圖片描述
Lock1刪除之後,因爲客戶端2在Lock1上註冊了Watcher,因此Lock1刪除之後,客戶端2會立即收到通知,這時客戶端2會再次獲取ParentLock下的所有臨時順序子節點並進行排序,然後與自身創建的Lock2比較,判斷Lock2是不是最小的(最靠前的),結果發現Lock2是最小的,因此客戶端2獲取鎖成功;
在這裏插入圖片描述
客戶端2崩潰同理;

  • 顯示釋放(客戶端任務執行完畢,主動釋放鎖)

當客戶端2執行完任務之後,調用delete方法刪除Lock2節點,因爲客戶端3在Lock2上註冊了Watcher,因此Lock2刪除之後,客戶端3會立即收到通知,這時客戶端3會再次獲取ParentLock下的所有臨時順序子節點並進行排序,然後與自身創建的Lock3比較,判斷Lock3是不是最小的(最靠前的),結果發現Lock3是最小的,因此客戶端3獲取鎖成功;
在這裏插入圖片描述
在這裏插入圖片描述

4、小結

本文簡單介紹了Zookeeper的節點類型,分佈式鎖的概念及應用場景,使用Zookeeper實現分佈式鎖的簡單原理,望對幫助理解Zookeeper實現分佈式鎖有些許幫助。

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