分布式鎖 使用Redis實現分布式鎖

2021-08-28 11:10:43 字數 2745 閱讀 3447

關於分布式鎖的實現,我的前一篇文章講解了如何使用zookeeper實現分布式鎖。關於分布式鎖的背景此處不再做贅述,我們直接討論下如何使用redis實現分布式鎖。

關於redis,筆主不打算做長篇大論的介紹,只介紹下redis優秀的特性。

支援豐富的資料型別,如string、list、map、set、zset等。

支援資料持久化,rdb和aof兩種方式

支援集群工作模式,分割槽容錯性強

單執行緒,順序處理命令

支援事務

支援發布與訂閱

redis實現分布式鎖使用了setnx命令,我們可以參考redis官方對此命令的介紹。

當然,redis實現分布式鎖也利用了單執行緒順序處理命令的特性。**實現也是比較簡單的,筆主使用了springboot進行開發,springboot提供了操作redis的工具類redistemplate。

首先,我們需要封裝乙個公共的redis訪問工具類。該類需要注入redistemplate例項和valueoperations例項,使用valueoperations例項是因為redis實現的分布式鎖使用了最簡單的string型別。另外,我們需要封裝3個方法,分別是setifobsent (string key, string value)、 expire (string key, long timeout, timeunit unit) 、delete (string key) ,分別對應redis的setnx、expire、del命令。以下是redis訪問工具類的具體實現:

/**

* redis訪問工具類

* @author zhaoheng

* @date 2023年8月10日

*/@component

public class redisdao

/*** 為key設定失效時間

* @param key 鍵

* @param timeout 時間大小

* @param unit 時間單位

*/public boolean expire (string key, long timeout, timeunit unit)

/*** 刪除key

* @param key 鍵

*/public void delete (string key)

}

完成了redis訪問工具類的實現,現在需要考慮的是如何去模擬競爭分布式鎖。因為redis本身就是支援分布式集群的,所以只需要模擬出多執行緒處理業務場景。這裡筆主採用執行緒池來模擬,以下是測試類的具體實現:

@restcontroller

public class testcontroller catch (interruptedexception e)

} else

}});

} }}

通過上面這段**,可能會產生以下幾個疑問:

執行緒如果獲取分布式鎖失敗,為什麼不嘗試重新獲取鎖?

執行緒獲取分布式鎖成功後,設定了鎖的失效時間,這個失效時間長短如何確定?

執行緒業務處理結束後,為什麼要做刪除鎖的操作?

針對這幾個疑問,我們可以來討論下。

第一,redis的setnx命令,如果key已經存在,則不會做任何操作,所以setnx實現的分布式鎖並不是可重入鎖。當然,也可以自己通過**實現重試n次或者直至獲取到分布式鎖為止。但是,這不能保證競爭的公平性,某個執行緒會因為一直等待鎖而阻塞。因此,redis實現的分布式鎖更適用於對共享資源一寫多讀的場景。

第二,分布式鎖必須設定失效時間,而且失效時間必須大於業務處理所需的時間(保證資料一致性)。所以,在測試階段盡可能準確的**出業務正常處理所需的時間,設定失效時間是防止因為業務處理過程的某些原因導致死鎖的情況。

第三,業務處理結束,必須要做刪除鎖的操作。

筆主上面設定分布式鎖和為鎖設定失效時間是通過兩個操作步驟完成的,更合理的方式應該是把設定分布式鎖和為鎖設定失效時間通過乙個操作完成。要麼都成功,要麼都失敗。實現**如下:

/**

* redis訪問工具類

*/@component

public class redisdao catch (exception e) finally

return flag; }

/*** 查詢key的失效時間

* @param key 鍵

* @param timeunit 時間單位

* @return

*/public long ttl (string key, timeunit timeunit)

}/**

* 單元測試類

*/@runwith(springrunner.class)

@springboottest

@autowired

private redisdao redisdao;

@test

public void testdistributelock () 距離失效還有{}s", key, ttl);

} }}

執行單元測試類,結果如下:

2019-05-15 13:07:10.827 - 設定分布式鎖成功

2019-05-15 13:07:10.838 - mydistributelock距離失效還有19s

通過執行結果可以知道,在設定分布式鎖的同時為鎖設定了失效時間。

至此,使用redis實現分布式鎖介紹完畢。

由於筆主水平有限,筆誤或者不當之處還請批評指正。

使用Redis實現分布式鎖

網上大部分建議都是使用setnx,這個本身沒有什麼問題,因為低版本的redis中,只有這個命令可以互斥的set乙個key。但是隨著redis版本的公升高,提供了更多的命令來更好的滿足我們的需求。set keyvalue ex seconds px milliseconds nx xx 這可和你所知道...

使用redis 實現分布式鎖

在有些需要高可用的場景中,保證併發量的情況下需要使用分布式鎖來做控制,保證應用的可靠性。我們知道jdk提供了一些常用的鎖比如reentrantlock,reentrantreadwritelock,synchronized。對於這些鎖的實現這裡就不詳細介紹了,在使用過程中這些鎖鎖的是物件,在單伺服器...

使用redis實現分布式鎖

一.redis命令講解 setnx 命令 setnx的含義就是set if not exists,其主要有兩個引數 setnx key,value 該方法是原子的,如果key不存在,則設定當前key成功,返回1 如果當前key已經存在,則設定當前key失敗,返回0。get 命令 get key 獲取...