1. 程式人生 > 資料庫 >分散式鎖三種實現方式及對比

分散式鎖三種實現方式及對比

分散式鎖三種實現方式:

1. 基於資料庫實現分散式鎖;

2. 基於快取(Redis等)實現分散式鎖;

3. 基於Zookeeper實現分散式鎖;

一, 基於資料庫實現分散式鎖

1. 悲觀鎖

利用select … where … for update 排他鎖

注意: 其他附加功能與實現一基本一致,這裡需要注意的是“where name=lock ”,name欄位必須要走索引,否則會鎖表。有些情況下,比如表不大,mysql優化器會不走這個索引,導致鎖表問題。

2. 樂觀鎖

所謂樂觀鎖與前邊最大區別在於基於CAS思想,是不具有互斥性,不會產生鎖等待而消耗資源,操作過程中認為不存在併發衝突,只有update version失敗後才能覺察到。我們的搶購、秒殺就是用了這種實現以防止超賣。

通過增加遞增的版本號欄位實現樂觀鎖

分散式鎖三種實現方式及對比分散式鎖三種實現方式及對比

二, 基於快取(Redis等)實現分散式鎖

1. 使用命令介紹:

(1)SETNX

SETNX key val:當且僅當key不存在時,set一個key為val的字串,返回1;若key存在,則什麼都不做,返回0。

(2)expire

expire key timeout:為key設定一個超時時間,單位為second,超過這個時間鎖會自動釋放,避免死鎖。

(3)delete

delete key:刪除key

在使用Redis實現分散式鎖的時候,主要就會使用到這三個命令。

2. 實現思想:

(1)獲取鎖的時候,使用setnx加鎖,並使用expire命令為鎖新增一個超時時間,超過該時間則自動釋放鎖,鎖的value值為一個隨機生成的UUID,通過此在釋放鎖的時候進行判斷。

(2)獲取鎖的時候還設定一個獲取的超時時間,若超過這個時間則放棄獲取鎖。

(3)釋放鎖的時候,通過UUID判斷是不是該鎖,若是該鎖,則執行delete進行鎖釋放。

三, 基於Zookeeper實現分散式鎖

ZooKeeper是一個為分散式應用提供一致性服務的開源元件,它內部是一個分層的檔案系統目錄樹結構,規定同一個目錄下只能有一個唯一檔名。基於ZooKeeper實現分散式鎖的步驟如下:

(1)建立一個目錄mylock;
(2)執行緒A想獲取鎖就在mylock目錄下建立臨時順序節點;
(3)獲取mylock目錄下所有的子節點,然後獲取比自己小的兄弟節點,如果不存在,則說明當前執行緒順序號最小,獲得鎖;

(4)執行緒B獲取所有節點,判斷自己不是最小節點,設定監聽比自己次小的節點;
(5)執行緒A處理完,刪除自己的節點,執行緒B監聽到變更事件,判斷自己是不是最小的節點,如果是則獲得鎖。

這裡推薦一個Apache的開源庫Curator,它是一個ZooKeeper客戶端,Curator提供的InterProcessMutex是分散式鎖的實現,acquire方法用於獲取鎖,release方法用於釋放鎖。

優點:具備高可用、可重入、阻塞鎖特性,可解決失效死鎖問題。

缺點:因為需要頻繁的建立和刪除節點,效能上不如Redis方式。

四,對比

資料庫分散式鎖實現

缺點:

1.db操作效能較差,並且有鎖表的風險

2.非阻塞操作失敗後,需要輪詢,佔用cpu資源;

3.長時間不commit或者長時間輪詢,可能會佔用較多連線資源

Redis(快取)分散式鎖實現

缺點:

1.鎖刪除失敗 過期時間不好控制

2.非阻塞,操作失敗後,需要輪詢,佔用cpu資源;

ZK分散式鎖實現

缺點:效能不如redis實現,主要原因是寫操作(獲取鎖釋放鎖)都需要在Leader上執行,然後同步到follower。

總之:ZooKeeper有較好的效能和可靠性。

從理解的難易程度角度(從低到高)資料庫 > 快取 > Zookeeper

從實現的複雜性角度(從低到高)Zookeeper >= 快取 > 資料庫

從效能角度(從高到低)快取 > Zookeeper >= 資料庫

從可靠性角度(從高到低)Zookeeper > 快取 > 資料庫

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。