分布式鎖
在單機系統中,如果多線程對一個共享資源訪問時,可以用鎖處理。
在分布式系統中,多個服務對同一個共享的資源訪問時,例如同一用戶對于某個接口未返回時不能重復調用,由于服務不在同一機器或不能共享內存,不能共享之前的鎖,即自己的鎖只對自己有效并不影響別的 ,因此需要一個可以分布式鎖的能力。
分布式鎖能力有幾種解決方案:
- 通過數據庫實現分布式鎖
- 基于緩存Redis實現分布式鎖
- 基于Zookeeper實現分布式鎖
1. 通過數據庫實現分布式鎖
具體的實現方法可以在數據庫中創建一個表,包括調用方法名、參數、調用者、調用時間等字段,在調用時在不表中插入數據,表示成功獲取鎖,釋放鎖時刪除記錄。
該種方式實現起來不復雜,但是有一些缺點:
- 分布式鎖的性能受制于數據庫的性能;
- 沒有鎖失效機制,如果某次成功插入數據后,服務器宕機,導致鎖一直沒有釋放
- 不具備鎖阻塞特性,如果獲取鎖失敗,需要制定獲取邏輯,例如循環獲取
2. 基于redis實現
redis實現分布式鎖的方式就是,通過插入key-value,當key不存在時,增加k-v表示成功獲取鎖,如果k存在,表示獲取失敗。
其優點是,redis基于內存存儲性能較高,而且redis支持set k-v時附帶超時時間,即鎖時間到期會自動釋放,避免死鎖相關問題
但redis同樣不具備鎖阻塞特性。
3. 基于Zookeeper
ZooKeeper是一個為分布式應用提供一致性服務的開源組件,它內部是一個分層的文件系統目錄樹結構,規定同一個目錄下只能有一個唯一文件名。
- 創建一個目錄mylock;
- 線程A想獲取鎖就在mylock目錄下創建臨時順序節點;
- 獲取mylock目錄下所有的子節點,然后獲取比自己小的兄弟節點,如果不存在,則說明當前線程順序號最小,獲得鎖;
- 線程B獲取所有節點,判斷自己不是最小節點,設置監聽比自己次小的節點;
- 線程A處理完,刪除自己的節點,線程B監聽到變更事件,判斷自己是不是最小的節點,如果是則獲得鎖。
Zookeeper具備高可用、可重入、阻塞鎖特性。