單體時代,可以直接用本地鎖來實現對競爭資源的加鎖,分布式環境下就要用到分布式鎖了
有哪些分布式鎖的實現方案?
MySQL分布式鎖、Zookeeper分布式鎖、Redis分布式鎖
MySQL分布式鎖如何實現?
創建一張鎖表,對字段定義唯一性約束。
獲取分布式鎖的時候,向表中插入記錄,釋放的時候,刪除記錄
這樣如果有并發請求同時提交到數據庫,數據庫會保證只有一個請求能夠得到鎖。
這種屬于數據庫 IO 操作,效率不高,而且頻繁操作會增大數據庫的開銷,因此這種方式在高并發、高性能的場景中用的不多。
Zookeeper如何實現分布式鎖?
ZooKeeper 的數據節點內部結構和文件目錄類似,例如某個ZNode下有一個 lock 節點,在此lock節點下建立子節點是可以保證先后順序的,即便是兩個進程同時申請新建節點,也會按照先后順序建立兩個節點。
將Zookeeper中的某個Znode節點作為所有鎖的根目錄locks/,然后對于每一把具體的鎖,在locks/根目錄下創建一個子節點mylock。客戶端想要獲取鎖時,在對應子節點下再按順序創建一個臨時子節點,并拿到一個順序遞增序列號。
獲取鎖時,當前客戶端會檢查自己的ZNode序列號是否是最小的,如果是,則成功獲取到鎖。
如果自己創建的 ZNode 不是最小的序列號,則表示鎖已經被其他客戶端持有。此時會對前一個ZNode設置一個Watcher進行監聽,當監聽到前一個ZNode被刪除時,再檢查一遍自己的ZNode是否擁有最小序列號,此時終于獲取到鎖
Redis如何實現分布式鎖?
Redis 執行命令是單線程的,Redis 實現分布式鎖就是利用這個特性。
實現分布式鎖最簡單的一個命令:setNx(set if not exist),如果不存在則更新:
setNx?resourceName?value
加鎖了之后如果機器宕機,那我這個鎖就無法釋放,所以需要加入過期時間,而且過期時間需要和 setNx 同一個原子操作,在 Redis2.8 之前需要用 lua 腳本,但是 redis2.8 之后 redis 支持 nx 和 ex 操作是同一原子操作。
set?resourceName?value?ex?5?nx
- Redission
當然,一般生產中都是使用 Redission 客戶端,非常良好地封裝了分布式鎖的 api,而且支持 RedLock。