分布式鎖的實現 3種常見方式

2021-10-14 14:43:12 字數 1993 閱讀 5928

分布式鎖的實現核心思路:找乙個公共區來生產和存放鎖。

because:既然是分布式,在單機上建立的例項物件(包括鎖物件),也只能作用於本機上,無法保證分布式中多台伺服器的一致性,所以此時的鎖一定要放在乙個公共的區域去建立,各個分布式服務都去訪問這個公共區域。 

最常見的公共區域有:資料庫,redis和zookepper。具體分析如下:

一:資料庫

方法1:

1:在資料庫中建立一張儲存分布式鎖的表,例如:lock_record. 主要的兩個字段:第乙個主鍵id,第二個鎖名lock_name(唯一型別)

2:在程式中實現上鎖的時候,先去建立這個鎖。如果建立失敗,說明此鎖已經存在(因為lock_name是唯一的),被占用,其他的請求阻塞等待。

3:如果建立成功,拿到鎖了,就可以執行請求。待執行完畢,釋放鎖(刪除此條記錄),其他請求可以重複2和3操作。

缺點:1:訪問資料庫成為了瓶頸,效率較低。

2:如果處理請求**現異常,不能釋放鎖,其他請求一直進不來,所以在程式中需要設計乙個超時處理,超時了,進行鎖的釋放(刪除資料庫中此條記錄)。

方法2:悲觀鎖

利用select … where … for update 排他鎖

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

方法3:樂觀鎖

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

通過增加遞增的版本號字段實現樂觀鎖

2:redis

核心思路:

上鎖:通過setnx指令設定鎖值(設定成功返回1,失敗返回0);

防止死鎖:通過expire指令設定過期時間(很重要,防止程式處理異常,不能釋放鎖);

釋放鎖:通過delete指令刪除key,拿到鎖的請求執行完之後要釋放鎖,讓其他請求能拿到鎖。

but:有個嚴重的問題,你知道? 集群下,redis主節點突然掛了,怎麼辦?

主節點駕崩了,還沒有還得及交出玉璽(鎖),此時諸侯(從節點)已經上位直接拿了玉璽。就導致玉璽被兩人所持有,不安全產生了。

為了解決上述問題:redis官方推出redisson高效能的分布式鎖實現。

核心思想:

1:建立「有序臨時節點+watch監聽」

2:每個請求(執行緒)都會在規定根節點下建立乙個臨時節點,建立完畢後,獲取所有的節點進行排序,比較自己是不是最小的節點。

3:如果是最小的節點,拿到鎖,執行請求,最後釋放鎖(刪除自己建立的臨時節點)。

4:如果不是最小的節點,會監聽前乙個節點,當它的前乙個節點釋放鎖時,他會獲得鎖。 依次類推!

簡述分布式鎖的3種實現方式

目錄 1 分布式鎖 2 實現方式 2.1 資料庫實現 2.2 redis實現 2.3 zookeeper實現 作為分布式鎖,我覺得至少得 1.資源唯一且能非同步多執行緒訪問 2.能改變狀態 加鎖 開鎖 資料庫 你可以設定字段唯一,可以建立 state 字段 redis 的key唯一,能設定value...

分布式鎖的三種實現方式 常見分布式鎖實現方式

0x01 基於mysql實現分布式鎖 基於分布式鎖的實現,首先肯定是想單獨分離出一台mysql資料庫,所有服務要想操作檔案 共享資源 那麼必須先在mysql資料庫中插入乙個標誌,插入標誌的服務就持有了鎖,並對檔案進行操作,操作完成後,主動刪除標誌進行鎖釋放,其與服務會一直查詢資料庫,看是否標誌有被占...

分布式鎖實現方式

1 資料庫的唯一索引實現 獲得鎖時向表中插入一條記錄,釋放鎖時刪除這條記錄。唯一索引可以保證該記錄只被插入一次,那麼就可以用這個記錄是否存在來判斷是否存於鎖定狀態。缺點 2 redis的setnx指令實現 使用 setnx set if not exist 指令插入乙個鍵值對,如果 key 已經存在...