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