redis分布式锁 在集群模式下如何实现_收藏慢慢看系列:简洁实用的Redis分布式锁用法...
在微服務(wù)中很多情況下需要使用到分布式鎖功能,而目前比較常見的方案是通過Redis來實(shí)現(xiàn)分布式鎖,網(wǎng)上關(guān)于分布式鎖的實(shí)現(xiàn)方式有很多,早期主要是基于Redisson等客戶端,但在Spring Boot2.x以上版本中使用Redis時(shí),其客戶端庫(kù)已經(jīng)默認(rèn)使用lettuce。
所以本文將直接介紹在Spring Boot2.x以上項(xiàng)目中快速使用Redis分布式鎖的功能的方法,希望能夠更新你的知識(shí)庫(kù)!
Redis分布式鎖原理概述
實(shí)際上Redis服務(wù)本身并不提供分布式鎖這樣的機(jī)制,但是作為全局Key-Value存儲(chǔ)系統(tǒng),客戶端可以利用Redis提供的基本功能并通過一定的算法設(shè)計(jì)來實(shí)現(xiàn)分布式鎖功能。目前已有不少博客文章及代碼庫(kù)描述了如何使用Redis來實(shí)現(xiàn)分布式鎖,但是許多實(shí)現(xiàn)相對(duì)比較簡(jiǎn)單,安全性也比較低。在Redis的官方文檔中推薦了一種叫做RedLock的算法來實(shí)現(xiàn)基于Redis的分布式鎖功能,現(xiàn)階段已存在基于該算法的多種語言版本的Redis客戶端實(shí)現(xiàn)庫(kù)。其中Java領(lǐng)域最為知名的是Redisson庫(kù)。但由于Redisson不僅實(shí)現(xiàn)了分布式鎖功能,還額外實(shí)現(xiàn)了一套R(shí)edis分布式數(shù)據(jù)結(jié)構(gòu),因此會(huì)顯得比較重,加上最新的基于Spring Boot.2.x以上版本使用Redis時(shí),其客戶端庫(kù)已經(jīng)默認(rèn)使用了lettuce(比Redisson、Jedis線程更安全、更輕量級(jí)的一種Java Redis客戶端庫(kù))的封裝,所以為了更加符合微服務(wù)場(chǎng)景下的使用,在實(shí)踐中往往會(huì)選擇基于RedLock算法自行實(shí)現(xiàn)分布式鎖。
本案例也將演示如何RedLock算法來實(shí)現(xiàn)Redis分布式鎖功能,不過在此之前讓我們先來看看RedLock算法是如何運(yùn)行的,示意圖如下:
以上就是實(shí)現(xiàn)Redis分布式鎖官方推薦的RedLock算法邏輯,它是一種多節(jié)點(diǎn)Redis的分布式鎖算法,可以有效防止單節(jié)點(diǎn)故障問題。其執(zhí)行步驟說明如下:
- 首先Redis客戶端獲取當(dāng)前系統(tǒng)時(shí)間,以毫秒為單位;
- 然后客戶端會(huì)順序地嘗試向Redis集群中的每個(gè)節(jié)點(diǎn)獲取鎖,其具體步驟是使用相同的鍵Key名和隨機(jī)值;在向每個(gè)Redis節(jié)點(diǎn)獲取鎖的過程中,客戶端會(huì)以比鎖過期時(shí)間小得多的時(shí)間來設(shè)定超時(shí)機(jī)制,例如鎖的整個(gè)超時(shí)時(shí)間為10秒,集群有5個(gè)節(jié)點(diǎn),那么每個(gè)節(jié)點(diǎn)獲取鎖的超時(shí)時(shí)間可能會(huì)被限制在5~50毫秒之間,這是為了防止在某個(gè)節(jié)點(diǎn)不可用的情況下,客戶端等待時(shí)間過長(zhǎng),造成性能阻塞;
- 之后隨著各節(jié)點(diǎn)獲取鎖結(jié)果的反饋,Redis客戶端會(huì)對(duì)獲取情況進(jìn)行判斷,如果獲取各節(jié)點(diǎn)鎖的總時(shí)間小于鎖的超時(shí)時(shí)間設(shè)置,并且成功獲取鎖的節(jié)點(diǎn)數(shù)目大于N/2+1個(gè)(例如5個(gè)節(jié)點(diǎn)至少要有3個(gè)節(jié)點(diǎn)成功獲取鎖),滿足上述條件的情況下,Redis客戶端才會(huì)認(rèn)為獲取鎖成功,否則就會(huì)認(rèn)為鎖獲取失敗,并依次釋放掉各個(gè)節(jié)點(diǎn)的鎖信息;
- 獲取鎖成功后即可以安全地執(zhí)行操作,完成后再依次釋放各節(jié)點(diǎn)鎖持有的鎖信息;
實(shí)現(xiàn)上述算法的Redis客戶端可以基本上保證分布式鎖的有效性及安全性的幾個(gè)基本特性要求:
- 互斥:任何時(shí)刻只能有一個(gè)Redis客戶端獲取鎖;
- 無死鎖:即使鎖定資源的服務(wù)崩潰或者分區(qū),仍然能釋放鎖);
- 容錯(cuò)性:只要多數(shù)redis節(jié)點(diǎn)(一半以上)在使用,Redis客戶端就可以獲取和釋放鎖;
Spring Boot集成使用方式
通過前面內(nèi)容的描述,相信你對(duì)實(shí)現(xiàn)Redis分布式鎖的基本算法應(yīng)該有了一定的認(rèn)識(shí)和理解。而在實(shí)踐的過程中可以依據(jù)該算法自行定制實(shí)現(xiàn),但實(shí)際上Spring早就提供了基于該算法的Redis的分布式鎖的實(shí)現(xiàn)。其具體使用步驟如下:
1)在工程pom.xml文件中引入Spring Integration依賴,代碼如下:
<!-- spring integration -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<!-- spring integration與redis結(jié)合,實(shí)現(xiàn)redis分布式鎖 -->
<dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-redis</artifactId>
</dependency>目前Spring所提供的分布式鎖相關(guān)的代碼被遷移在Spring Integration子項(xiàng)目中,所以這里引入其相關(guān)依賴。
2)編寫RedisLock的配置類,代碼如下:
@Configuration
public class RedisLockConfiguration {@Beanpublic RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {return new RedisLockRegistry(redisConnectionFactory, "payment");}
}以上配置代碼加載的前提在于應(yīng)用已經(jīng)集成了Redis服務(wù)訪問鏈接信息,具體Spring Boot項(xiàng)目集成Redis訪問的方式比較簡(jiǎn)單可以參考其他資料。
3)分布式鎖的具體使用方式,代碼片段如下:
/*** 引入Redis分布式鎖依賴組件*/
@Autowired
private RedisLockRegistry redisLockRegistry;@Override
public UnifiedPayBO unifiedPay(UnifiedPayDTO unifiedPayDTO) {...//創(chuàng)建Redis分布式鎖Lock lock = redisLockRegistry.obtain(redisLockPrefix + unifiedPayDTO.getOrderId());try { //嘗試獲取鎖boolean isLock = lock.tryLock(1, TimeUnit.SECONDS);if (isLock) {//執(zhí)行業(yè)務(wù)邏輯...}} catch (InterruptedException e) {e.printStackTrace();} finally {//釋放分布式鎖lock.unlock();}...
}上述代碼為訂單防重時(shí)使用Redis分布鎖的示例代碼,通過依賴注入RedisLockRegistry實(shí)例來實(shí)現(xiàn)分布式鎖的相關(guān)操作,例如obtain()方法創(chuàng)建鎖、tryLock()持有鎖及unlock()釋放鎖等。
寫在最后:
歡迎大家關(guān)注我新開通的公眾號(hào)【風(fēng)平浪靜如碼】,海量Java相關(guān)文章,學(xué)習(xí)資料都會(huì)在里面更新,整理的資料也會(huì)放在里面。
覺得寫的還不錯(cuò)的就點(diǎn)個(gè)贊,加個(gè)關(guān)注唄!點(diǎn)關(guān)注,不迷路,持續(xù)更新!!!
總結(jié)
以上是生活随笔為你收集整理的redis分布式锁 在集群模式下如何实现_收藏慢慢看系列:简洁实用的Redis分布式锁用法...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 昼锦堂画是谁画的啊?
- 下一篇: redis hash删除所有key_一文