分布式環境下的解決方案 分布式鎖

2021-08-20 03:47:10 字數 1656 閱讀 8381

分布式鎖,也就是在多程序情況下的鎖。

需要有儲存鎖的空間,並且鎖的空間是可以訪問到的。

鎖需要被唯一標識。

鎖要有至少兩種狀態。

儲存空間:

鎖是乙個抽象的概念,鎖的實現,需要依存於乙個可以儲存鎖的空間。在多執行緒中是記憶體,在多程序中是記憶體或者磁碟。更重要的是,這個空間是可以被訪問到的。多執行緒中,不同的執行緒都可以訪問到堆中的成員變數;在多程序中,不同的程序可以訪問到共享記憶體中的資料或者儲存在磁碟中的檔案。但是在分布式環境中,不同的主機很難訪問對方的記憶體或磁碟。這就需要乙個都能訪問到的外部空間來作為儲存空間。

最普遍的外部儲存空間就是資料庫了,事實上也確實有基於資料庫做分布式鎖(行鎖、version樂觀鎖),如quartz集群架構中就有所使用。除此以外,還有各式快取如redis、tair、memcached、mongodb,當然還有專門的分布式協調服務zookeeper,甚至是另一台主機。只要可以儲存資料、鎖在其中可以被多主機訪問到,那就可以作為分布式鎖的儲存空間。

唯一標識:

不同的共享資源,必然需要用不同的鎖進行保護,因此相應的鎖必須有唯一的標識。在多執行緒環境中,鎖可以是乙個物件,那麼對這個物件的引用便是這個唯一標識。多程序環境中,訊號量在共享記憶體中也是由引用來作為唯一的標識。但是如果不在記憶體中,失去了對鎖的引用,如何唯一標識它呢?上文提到的有名訊號量,便是用硬碟中的檔名作為唯一標識。因此,在分布式環境中,只要給這個鎖設定乙個名稱,並且保證這個名稱是全域性唯一的,那麼就可以作為唯一標識。

至少兩種狀態:

為了給臨界區加鎖和解鎖,需要儲存兩種不同的狀態。如reentrantlock中的status,0表示沒有執行緒競爭,大於0表示有執行緒競爭;訊號量大於0表示可以進入臨界區,小於等於0則表示需要被阻塞。因此只要在分布式環境中,鎖的狀態有兩種或以上:如有鎖、沒鎖;存在、不存在等等,均可以實現。

資料庫:去判斷某個欄位的狀態 來判斷是否能得到鎖。

redis:根據 setnx 命令 來判斷, 如果返回1 則獲取到了鎖,否則就是沒獲取到,死鎖,鎖的有效期的問題點:

zookeeper : 1、通過註冊臨時節點的方式,能註冊成功會返回節點的名稱,就是獲取到了鎖,

2、去建立最小臨時有序節點,通過一系列的判斷,當註冊的節點是最小節點時就獲取到了鎖。臨時節點消失也就意味著鎖釋放。

通過了解分布式鎖 跟 普通 的鎖的相同點之後,其實自己就可以實現乙個簡單的分布式鎖,但為什麼要用redis或者是 zookeeper這樣複雜的中介軟體呢?

可重入:執行緒中的可重入,指的是外層函式獲得鎖之後,內層也可以獲得鎖,reentrantlock和synchronized都是可重入鎖;衍生到分布式環境中,一般仍然指的是執行緒的可重入,在絕大多數分布式環境中,都要求分布式鎖是可重入的。

驚群效應(herd effect):在分布式鎖中,驚群效應指的是,在有多個請求等待獲取鎖的時候,一旦占有鎖的執行緒釋放之後,如果所有等待的方都同時被喚醒,嘗試搶占鎖。但是這樣的情況會造成比較大的開銷,那麼在實現分布式鎖的時候,應該盡量避免驚群效應的產生。

公平鎖和非公平鎖:不同的需求,可能需要不同的分布式鎖。非公平鎖普遍比公平鎖開銷小。但是業務需求如果必須要鎖的競爭者按順序獲得鎖,那麼就需要實現公平鎖。

阻塞鎖和自旋鎖:針對不同的使用場景,阻塞鎖和自旋鎖的效率也會有所不同。阻塞鎖會有上下文切換,如果併發量比較高且臨界區的操作耗時比較短,那麼造成的效能開銷就比較大了。但是如果臨界區操作耗時比較長,一直保持自旋,也會對cpu造成更大的負荷。

分布式鎖解決方案

分布式鎖三種實現方式 1.基於資料庫實現分布式鎖 2.基於快取 redis等 實現分布式鎖 3.基於zookeeper實現分布式鎖 1.悲觀鎖 利用select where for update 排他鎖 注意 其他附加功能與實現一基本一致,這裡需要注意的是 where name lock name欄...

zk分布式鎖解決方案

思路 加鎖時,在指定路徑建立臨時節點 臨時節點避免死鎖 於是只有乙個執行緒能建立成功 等待時,其他建立節點失敗的執行緒,會watch指定路徑的刪除事件,一旦事件觸發,說明臨時節點被刪除,執行緒可以繼續去獲取鎖 解鎖時,當前執行緒刪除它建立的節點 public class zookeeperdistr...

分布式 分布式鎖

本質是利用redis的setnx 方法的特性來加鎖,setnx 即key不存在則設定key,否則直接返回false,要求在分布式系統中使用同乙個redis服務,以下提供兩種解決方案 1 直接使用redistemplate 這其實並不能完全保證高併發下的安全問題,因為可能在鎖過期之後該執行緒尚未執行完...