您好,登錄后才能下訂單哦!
在一個分布式系統中,如何保證一個操作,同一時間只有一個線程可以執行,這就是分布式鎖的使用場景,同一時間,只有一個線程可以獲得鎖的使用權。
實現一個分布式鎖,可以有以下3種方法。
1、在MySQL中,使用悲觀鎖"select from t where id = for update"可以對行數據進行加鎖,來實現分布式鎖。
2、同一個時間內,只會有一個線程加鎖成功,其他線程必須等待。
3、數據庫要保證是全局的,每一把鎖所對應的行數據也是唯一的。
1、實現簡單,方便。
1、基于數據庫的悲觀鎖,性能比較差。
2、等待中的線程是自旋的或者等待狀態,需要等待持有鎖的線程處理完,多個線程再一起去競爭同一把鎖。
3、異常無法處理,當持有鎖的線程還沒有釋放鎖,意外退出,鎖資源將無法釋放,應用程序將無法繼續進行。
1、使用redis的setnx命令,可以模擬分布式鎖,setnx保證操作一個key值,如果沒有則返回true,如果存在則返回false。
2、為了解決程序意外退出導致無法釋放鎖資源,需要給key增加一個超時時間。
3、redis提供了帶參數的命令,可以保證設置key值和設置超時時間這2個操作的原子性
SET key value [EX seconds] [PX milliseconds] [NX|XX]
4、假如有如下情況:
A獲取了鎖,設置了超時時間為10秒,但是A執行了15秒,在10秒的時候鎖失效了。
B在11秒的時候獲取了鎖,執行了5秒,那么A在15秒的時候會誤刪掉B的鎖。
為了解決以上問題,每個加鎖的線程都需要設置自己的value值,當刪除的時候也要校驗是自己的鎖,才可以刪除。
1、實現簡單,方便。
2、基于redis的高性能,效率高。
1、無法解決超時鎖失效問題,邏輯處理的時間超過了設置的超時時間,那么這個時候就會導致,另一個也可以拿到鎖繼續執行。
為了解決這個問題,一般的方法是啟動一個守護線程,時刻監控失效時間,當鎖時間超過一定的執行時間比例之后,自動續約一定的時間,當然這個總時間是有最大閾值限制的。
2、等待中的線程是自旋的后者等待狀態,需要等待持有鎖的線程處理完,多個線程再一起去競爭同一把鎖。
1、使用臨時節點實現分布式鎖,第一個創建臨時節點成功的線程,獲取鎖成功。
2、其他創建臨時節點的線程會失敗,那么監聽鎖的臨時節點。
3、當鎖釋放的時候,刪除臨時節點,會通知到監聽的線程,收到通知的線程繼續嘗試創建臨時鎖節點,誰創建成功誰獲得鎖。
解決了鎖失效問題,通知機制可以完美解決,即使創建臨時節點的線程掛掉,臨時節點會自動刪除。
1、當有大量線程,等待鎖資源的時候,鎖資源釋放會涉及到大量的通知,并且大量的線程需要一起競爭鎖資源。
1、在一個目錄下,各個線程創建順序的臨時節點,節點編號1、2、3、4、5等。
2、目錄下創建的節點最小的線程獲取鎖。
3、等待鎖資源的線程,不再一起全部監聽鎖節點,而是只監聽比自己小的上一個節點。
4、當監聽的比自己小的鎖節點被刪除后,繼續改為監聽上一個比自己小的節點。
4、當鎖釋放的時候,只需要通知監聽鎖節點的一個獲幾個線程,避免了大量的通知。
zookeeper實現的樂觀鎖,是比較合理的分布式鎖方式,感興趣的朋友可以用代碼實現一下。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。