天天看點

分布式是什麼意思_什麼是分布式鎖?Redis實作分布式鎖詳解

分布式是什麼意思_什麼是分布式鎖?Redis實作分布式鎖詳解

在很多場景中,我們為了保證資料的最終一緻性,需要很多的技術方案來支援,比如分布式事務、分布式鎖等。那具體什麼是分布式鎖,分布式鎖應用在哪些業務場景、如何來實作分布式鎖呢?今天來探讨分布式鎖這個話題。

分布式是什麼意思_什麼是分布式鎖?Redis實作分布式鎖詳解

什麼是分布式鎖

要介紹分布式鎖,首先要提到與分布式鎖相對應的是線程鎖、程序鎖。

1.線程鎖

主要用來給方法、代碼塊加鎖。當某個方法或代碼使用鎖,在同一時刻僅有一個線程執行該方法或該代碼段。線程鎖隻在同一JVM中有效果,因為線程鎖的實作在根本上是依靠線程之間共享記憶體實作的,比如Synchronized、Lock等。

2.程序鎖

為了控制同一作業系統中多個程序通路某個共享資源,因為程序具有獨立性,各個程序無法通路其他程序的資源,是以無法通過synchronized等線程鎖實作程序鎖。

3.分布式鎖

當多個程序不在同一個系統中,用分布式鎖控制多個程序對資源的通路。

分布式鎖的由來

在傳統單機部署的情況下,可以使用Java并發處理相關的API(如ReentrantLcok或synchronized)進行互斥控制。

但是在分布式系統後,由于分布式系統多線程、多程序并且分布在不同機器上,這将使原單機并發控制鎖政策失效,為了解決這個問題就需要一種跨JVM的互斥機制來控制共享資源的通路,這就是分布式鎖的由來。

當多個程序不在同一個系統中,就需要用分布式鎖控制多個程序對資源的通路。

分布式鎖的特點

首先,為了確定分布式鎖可用,我們至少要確定鎖的實作同時滿足以下四個條件:

1、

互斥性

:任意時刻,隻能有一個用戶端擷取鎖,不能同時有兩個用戶端擷取到鎖。

2、

安全性

:鎖隻能被持有該鎖的用戶端删除,不能由其它用戶端删除。

3、

死鎖

:擷取鎖的用戶端因為某些原因(如down機等)而未能釋放鎖,其它用戶端再也無法擷取到該鎖。

4、

容錯

:當部分節點(redis節點等)down機時,用戶端仍然能夠擷取鎖和釋放鎖。

分布式鎖的具體實作

分布式是什麼意思_什麼是分布式鎖?Redis實作分布式鎖詳解
分布式鎖一般有三種實作方式:

1. 資料庫樂觀鎖;

2. 基于ZooKeeper的分布式鎖;

3.基于Redis的分布式鎖;

Redis實作分布式鎖

基于Redis指令:SET key value NX EX max-lock-time

這裡補充下: 從2.6.12版本後, 就可以使用set來擷取鎖, Lua 腳本來釋放鎖。setnx是老黃曆了,set指令nx,xx等參數, 是為了實作 setnx 的功能。

1.加鎖

public class RedisTool {

private static final String LOCK_SUCCESS = "OK";

private static final String SET_IF_NOT_EXIST = "NX";

private static final String SET_WITH_EXPIRE_TIME = "PX";

public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

if (LOCK_SUCCESS.equals(result)) {return true;}return false;}}

jedis.set(String key, String value, String nxxx, String expx, int time)

這個set()方法一共有五個形參:

第一個為key,我們使用key來當鎖,因為key是唯一的。

第二個為value,我們傳的是requestId,很多童鞋可能不明白,有key作為鎖不就夠了嗎,為什麼還要用到value?原因就是我們在上面講到可靠性時,分布式鎖要滿足第四個條件解鈴還須系鈴人,通過給value指派為requestId,我們就知道這把鎖是哪個請求加的了,在解鎖的時候就可以有依據。requestId可以使用UUID.randomUUID().toString()方法生成。

第三個為nxxx,這個參數我們填的是NX,意思是SET IF NOT EXIST,即當key不存在時,我們進行set操作;若key已經存在,則不做任何操作;

第四個為expx,這個參數我們傳的是PX,意思是我們要給這個key加一個過期的設定,具體時間由第五個參數決定。

第五個為time,與第四個參數相呼應,代表key的過期時間。

總的來說,執行上面的set()方法就隻會導緻兩種結果:1. 目前沒有鎖(key不存在),那麼就進行加鎖操作,并對鎖設定個有效期,同時value表示加鎖的用戶端。2. 已有鎖存在,不做任何操作。

2.解鎖

public class RedisTool {

private static final Long RELEASE_SUCCESS = 1L;

public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {

String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

Object result = jedis.eval(script, Collections.singletonList(lockKey),Collections.singletonList(requestId));if (RELEASE_SUCCESS.equals(result)) {return true;}return false;}}

那麼這段Lua代碼的功能是什麼呢?其實很簡單,首先擷取鎖對應的value值,檢查是否與requestId相等,如果相等則删除鎖(解鎖)。

以上就是redis實作分布式鎖詳解,除此之外,也可以使用Redission(Redis 的用戶端)內建進來實作分布式鎖,也可以使用資料庫等,具體可以參考Mike發表在優知學院官網的往期文章《阿裡P8架構師談分布式鎖的3種實作:資料庫、緩存、Zookeeper》。

覺得不錯請點贊支援下。

關注優知學院專欄

【直通BAT】進階Java架構師

,實戰架構技術幹貨第一時間送達。

----end----

以下是優知學院官網精選的Redis系列篇,感興趣不妨深入了解,讓你知其然更知其是以然,深度掌握Redis。

Redis緩存和MySQL資料一緻性方案詳解

如何解決Redis雪崩、穿透、并發等5大難題

Redis并發競争key的解決方案詳解

Redis為什麼是單線程,高并發快的3大原因詳解

Redis面試題目49道附答案