分布式鎖是什麼東西?看了這個你就懂了

引子

很久很久以前,那會我還是一個剛剛接觸java分佈式開發的小菜鳥,有一次接到一個小需求:每天定時為一些用戶發送消息。

聽完需求,一合計,這個簡單,分分鐘就搞定了,不就是一個定時任務嘛。然而當我把功能上到測試環境卻測試不通過,因為每一次發送消息的時候都會給一個人一次性發送3條一模一樣的消息。因為這個bug我第一次接觸到了分佈式鎖的概念,今天我們就來一起分析一下分佈式鎖。

什麼是分佈式鎖

分佈式鎖是控制分佈式系統或不同系統之間共同訪問共享資源的一種鎖實現,如果不同的系統或同一個系統的不同主機之間共享了某個資源時,往往需要互斥來防止彼此干擾來保證一致性。

下圖展示了分佈式鎖在工作中的基本流程:

分佈式鎖是什麼東西?看了這個你就懂了

分佈式鎖系統流程

那麼一個好的分佈式鎖需要具備哪些特性呢?

  • 互斥性:任意時刻,只能有一個客戶端獲取鎖,不能同時有兩個客戶端獲取到鎖。

  • 安全性:鎖只能被持有該鎖的客戶端刪除,不能由其它其它客戶端刪除。

  • 死鎖:獲取鎖的客戶端因為某些原因(如down機等)而未能釋放鎖,其它客戶端再也無法獲取到該鎖。

  • 容錯:當部分節點(redis節點等)down機時,客戶端仍然能夠獲取鎖和釋放鎖。

  • 高效:分佈式鎖往往會成為性能的瓶頸,分佈式鎖的性能將會大大的影響系統的性能。

所以選擇一個好的分佈式鎖控制中心就是尤為關鍵了,目前比較常用的有以下幾種方案:

  • 基於數據庫實現

  • 基於緩存實現

  • 基於zookeeper實現

下面我們就一一分析這三種實現方式以及他們各自的特點。

基於數據庫實現

在這個方案中,需要在數據庫中創建一張分佈式鎖信息表,其中一個字段設置為唯一主鍵,獲取鎖的時候就插入數據,釋放鎖的時候就刪除這條數據,這個唯一主鍵中存放的就是分佈式鎖的唯一標識。

該方案的特點:

  • 依賴於數據庫,實現方式簡單。

  • 無法做到鎖的超時釋放,如果出現死鎖將會一直持續下去。

基於緩存實現

常用的緩存系統有:redis,memcache,tair等。我們以redis為例介紹一下依賴於緩存的分佈式鎖是如何實現的。

我們可以把分佈式鎖的唯一標識作為redis存儲的key。當客戶端需要獲取鎖的時候,就用鎖的key到redis中get一下值。如果存在值,就表示該鎖不可用,獲取失敗;如果獲取不到值,表示該鎖可用,獲取成功。獲取到鎖以後,需要向緩存中寫入任意值(比如寫入1),如果需要也可以設置超時時間。

該方案的特點:

  • 有些緩存系統並不能夠很好的提供具有原子性的操作。

  • 具有失效時間,如果出現死鎖,能夠自動的釋放。

  • 鎖的失效時間需要小心設置,過長或果斷都可能引起問題。

基於zookeeper實現

客戶端需要獲取鎖的時候,在zookeeper上的與鎖唯一表示對應的節點的目錄下,生成一個唯一的瞬時有序節點。 判斷是否獲取鎖的方式很簡單,只需要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除即可。同時,其可以避免服務宕機導致的鎖無法釋放,而產生的死鎖問題。

該方案的特點:

  • 當發生宕機的時候,鎖會第一時間就被釋放。

  • 網絡不穩定的時候可能會出現鎖被錯誤釋放的問題。

總結

上面幾種方案,各有各的特點,在方案的選擇上需要根據實際系統業務來選擇。


分享到:


相關文章: