分布式鎖原理詳解(圖文全面總結(jié))
分布式鎖
要理解分布式鎖,核心點是在于要理解共享資源訪問的問題。
比如:一個資源變量A,在單體應用中,如果有多個線程同時來競爭該資源A,可以通過Synchronized、或者ReentrantLcok上鎖來解決資源共享的問題。
但是,在分布式系統(tǒng)后,由于分布式系統(tǒng)是分布在不同機器上,布式系統(tǒng)中競爭共享資源的最小粒度從線程升級成了進程,這將使原單機并發(fā)控制鎖策略失效。
圖片
為了解決這個問題,就需要一種跨服務,跨JVM的鎖機制,來控制共享資源的訪問,這就是分布式鎖。
分布式鎖的實現(xiàn)
首先為了確保分布式鎖可用,我們至少要確保鎖的實現(xiàn)同時滿足以下四個條件:
圖片
1.互斥性
任意時刻只能有一個客戶端獲取鎖,不能同時有兩個客戶端獲取到鎖。
2.安全性
鎖只能被持有該鎖的客戶端刪除,不能由其它客戶端刪除。
3.死鎖
獲取鎖的客戶端因為某些原因,比如:down機等,而未能釋放鎖,其它客戶端再也無法獲取到該鎖。
4.容錯
當部分節(jié)點down機時,客戶端仍然能夠獲取鎖和釋放鎖。
常見的分布式鎖的實現(xiàn)有:Redis分布式鎖、Zookeeper分布式鎖等方式來實現(xiàn)分布式鎖。
如下所示:
import redis.clients.jedis.Jedis;
public class RedisDistributedLock {
private Jedis jedis;
private String lockKey;
private String lockValue; // 唯一標識,如UUID
private int expireTime; // 鎖的過期時間,單位毫秒
public RedisDistributedLock(Jedis jedis, String lockKey, String lockValue, int expireTime) {
this.jedis = jedis;
this.lockKey = lockKey;
this.lockValue = lockValue;
this.expireTime = expireTime;
}
public boolean tryLock() {
// 嘗試獲取鎖
String result = jedis.set(lockKey, lockValue, "NX", "PX", expireTime);
return "OK".equals(result);
}
}
單實例的Redis存在單點故障問題,推薦使用Redis集群、或哨兵模式以增加可用性。
分布式鎖的應用場景
1.共享資源競爭
如果涉及到分布式環(huán)境(多機器)的資源競爭,多個進程同時操作共享資源,則需要分布式鎖。
原因剛才已經(jīng)講過了,因為共享資源已經(jīng)跨越到不同的服務器進程上了,java的鎖已經(jīng)鎖不住了。
2.效率性
使用分布式鎖可以避免不同節(jié)點重復相同的工作。
3.業(yè)務場景
在電商業(yè)務里,最常見的場景:扣減庫存,以及在高并發(fā)的場景下,阻止流量打到后邊等等。