分布式鎖簡單實現

2021-09-24 16:06:54 字數 1790 閱讀 6637

基於zookeeper的實現方式

基於redis的實現方式

基於資料庫實現分布式鎖

基於快取,實現分布式鎖,如redis

基於zookeeper實現分布式鎖

樂觀鎖機制其實就是在資料庫表中引入乙個版本號(version)欄位來實現的。

當我們要從資料庫中讀取資料的時候,同時把這個version欄位也讀出來,如果要對讀出來的資料進行更新後寫回資料庫,則需要將version加1,同時將新的資料與新的version更新到資料表中,且必須在更新的時候同時檢查目前資料庫裡version值是不是之前的那個version,如果是,則正常更新。如果不是,則更新失敗,說明在這個過程中有其它的程序去更新過資料了。

優點:樂觀鎖的效能高於悲觀鎖,並不容易出現死鎖。

缺點:樂觀鎖只能對一張表的資料進行加鎖,如果是需要對多張表的資料操作加分布式鎖,基於版本號的樂觀鎖是辦不到的。

悲觀鎖也叫作排它鎖,當事務在運算元據時把這部分資料進行鎖定,直到操作完畢後再解鎖,其他事務操作才可操作該部分資料。這將防止其他程序讀取或修改表中的資料。

一般使用select ...for update對所選擇的資料進行加鎖處理,例如select * from user where user_name="whut" for update, 這條sql 語句鎖定了user表中所有符合檢索條件(user_name=「whut」)的記錄。本次事務提交之前(事務提交時會釋放事務過程中的鎖),外界無法修改這些記錄。

優點:是比較安全的一種實現方法。

缺點:在高併發的場景下開銷是不能容忍的。容易出現資料庫死鎖等情況。

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

(1)建立乙個目錄mylock;

(2)執行緒a想獲取鎖就在mylock目錄下建立臨時順序節點;

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

(4)執行緒b獲取所有節點,判斷自己不是最小節點,設定監聽比自己次小的節點;

(5)執行緒a處理完,刪除自己的節點,執行緒b監聽到變更事件,判斷自己是不是最小的節點,如果是則獲得鎖。

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

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

redis提供了setnx原子操作。基於redis的分布式鎖也是基於這個操作實現的,setnx是指如果有這個key就set失敗,如果沒有這個key則set成功,但是setnx不能設定超時時間。

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

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

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

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

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

delete key:刪除key

優點:效能高,實現起來較為方便

缺點:通過鎖超時機制不是十分可靠,當執行緒獲得鎖後,處理時間過長導致鎖超時,就失效了鎖的作用

分布式鎖的簡單實現

分布式鎖在分布式應用當中是要經常用到的,主要是解決分布式資源訪問衝突的問題。一開始考慮採用reentrantlock來實現,但是實際上去實現的時候,是有問題的,reentrantlock的lock和unlock要求必須是在同一執行緒進行,而分布式應用中,lock和unlock是兩次不相關的請求,因此...

Redis分布式鎖簡單實現

偽 下訂單 1 查庫存 getstock 2 判斷庫存 stock 0下單 3 下單 addorder 4 減庫存 public class redisutils setnx param key param value param seconds 過期時間,單位秒 return public sta...

簡單聊聊分布式鎖 Redis分布式鎖

單機redis分布式鎖 單機redis分布式鎖 首先咱們先聊聊單機的redis分布式鎖 第乙個最普通的實現方式,就是在 redis 裡使用 setnx 命令建立乙個 key,這樣就算加鎖。set resource name my random value nx px 30000執行這個命令就 ok。...