最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis分布式鎖之紅鎖的實(shí)現(xiàn)

 更新時(shí)間:2022年08月09日 11:43:40   作者:姜秀麗  
本文主要介紹了Redis分布式鎖之紅鎖的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、問(wèn)題

分布式鎖,當(dāng)我們請(qǐng)求一個(gè)分布式鎖的時(shí)候,成功了,但是這時(shí)候slave還沒有復(fù)制我們的鎖,masterDown了,我們的應(yīng)用繼續(xù)請(qǐng)求鎖的時(shí)候,會(huì)從繼任了master的原slave上申請(qǐng),也會(huì)成功。

這就會(huì)導(dǎo)致,同一個(gè)鎖被獲取了不止一次。

二、辦法

Redis中針對(duì)此種情況,引入了紅鎖的概念。

三、原理

用Redis中的多個(gè)master實(shí)例,來(lái)獲取鎖,只有大多數(shù)實(shí)例獲取到了鎖,才算是獲取成功。具體的紅鎖算法分為以下五步:

  • 獲取當(dāng)前的時(shí)間(單位是毫秒)。
  • 使用相同的key和隨機(jī)值在N個(gè)節(jié)點(diǎn)上請(qǐng)求鎖。這里獲取鎖的嘗試時(shí)間要遠(yuǎn)遠(yuǎn)小于鎖的超時(shí)時(shí)間,防止某個(gè)masterDown了,我們還在不斷的獲取鎖,而被阻塞過(guò)長(zhǎng)的時(shí)間。
  • 只有在大多數(shù)節(jié)點(diǎn)上獲取到了鎖,而且總的獲取時(shí)間小于鎖的超時(shí)時(shí)間的情況下,認(rèn)為鎖獲取成功了。
  • 如果鎖獲取成功了,鎖的超時(shí)時(shí)間就是最初的鎖超時(shí)時(shí)間進(jìn)去獲取鎖的總耗時(shí)時(shí)間。
  • 如果鎖獲取失敗了,不管是因?yàn)楂@取成功的節(jié)點(diǎn)的數(shù)目沒有過(guò)半,還是因?yàn)楂@取鎖的耗時(shí)超過(guò)了鎖的釋放時(shí)間,都會(huì)將已經(jīng)設(shè)置了key的master上的key刪除。

四、實(shí)戰(zhàn)

Redission就實(shí)現(xiàn)了紅鎖算法,使用的步驟如下:

1、引入maven

<!-- JDK 1.8+ compatible -->
<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.9.0</version>
</dependency> 

2、引入代碼

Config config1 = new Config();
config1.useSingleServer().setAddress("redis://172.0.0.1:5378").setPassword("a123456").setDatabase(0);
RedissonClient redissonClient1 = Redisson.create(config1);

Config config2 = new Config();
config2.useSingleServer().setAddress("redis://172.0.0.1:5379").setPassword("a123456").setDatabase(0);
RedissonClient redissonClient2 = Redisson.create(config2);

Config config3 = new Config();
config3.useSingleServer().setAddress("redis://172.0.0.1:5380").setPassword("a123456").setDatabase(0);
RedissonClient redissonClient3 = Redisson.create(config3);

/**
?* 獲取多個(gè) RLock 對(duì)象
?*/
RLock lock1 = redissonClient1.getLock(lockKey);
RLock lock2 = redissonClient2.getLock(lockKey);
RLock lock3 = redissonClient3.getLock(lockKey);

/**
?* 根據(jù)多個(gè) RLock 對(duì)象構(gòu)建 RedissonRedLock (最核心的差別就在這里)
?*/
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);

try {
? ? /**
? ? ?* 4.嘗試獲取鎖
? ? ?* waitTimeout 嘗試獲取鎖的最大等待時(shí)間,超過(guò)這個(gè)值,則認(rèn)為獲取鎖失敗
? ? ?* leaseTime ? 鎖的持有時(shí)間,超過(guò)這個(gè)時(shí)間鎖會(huì)自動(dòng)失效(值應(yīng)設(shè)置為大于業(yè)務(wù)處理的時(shí)間,確保在鎖有效期內(nèi)業(yè)務(wù)能處理完)
? ? ?*/
? ? boolean res = redLock.tryLock((long)waitTimeout, (long)leaseTime, TimeUnit.SECONDS);
? ? if (res) {
? ? ? ? //成功獲得鎖,在這里處理業(yè)務(wù)
? ? }
} catch (Exception e) {
? ? throw new RuntimeException("aquire lock fail");
}finally{
? ? //無(wú)論如何, 最后都要解鎖
? ? redLock.unlock();
}

3、核心源碼

public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
? ? long newLeaseTime = -1;
? ? if (leaseTime != -1) {
? ? ? ? newLeaseTime = unit.toMillis(waitTime)*2;
? ? }
? ??
? ? long time = System.currentTimeMillis();
? ? long remainTime = -1;
? ? if (waitTime != -1) {
? ? ? ? remainTime = unit.toMillis(waitTime);
? ? }
? ? long lockWaitTime = calcLockWaitTime(remainTime);
? ? /**
? ? ?* 1. 允許加鎖失敗節(jié)點(diǎn)個(gè)數(shù)限制(N-(N/2+1))
? ? ?*/
? ? int failedLocksLimit = failedLocksLimit();
? ? /**
? ? ?* 2. 遍歷所有節(jié)點(diǎn)通過(guò)EVAL命令執(zhí)行l(wèi)ua加鎖
? ? ?*/
? ? List<RLock> acquiredLocks = new ArrayList<>(locks.size());
? ? for (ListIterator<RLock> iterator = locks.listIterator(); iterator.hasNext();) {
? ? ? ? RLock lock = iterator.next();
? ? ? ? boolean lockAcquired;
? ? ? ? /**
? ? ? ? ?* ?3.對(duì)節(jié)點(diǎn)嘗試加鎖
? ? ? ? ?*/
? ? ? ? try {
? ? ? ? ? ? if (waitTime == -1 && leaseTime == -1) {
? ? ? ? ? ? ? ? lockAcquired = lock.tryLock();
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? long awaitTime = Math.min(lockWaitTime, remainTime);
? ? ? ? ? ? ? ? lockAcquired = lock.tryLock(awaitTime, newLeaseTime, TimeUnit.MILLISECONDS);
? ? ? ? ? ? }
? ? ? ? } catch (RedisResponseTimeoutException e) {
? ? ? ? ? ? // 如果拋出這類異常,為了防止加鎖成功,但是響應(yīng)失敗,需要解鎖所有節(jié)點(diǎn)
? ? ? ? ? ? unlockInner(Arrays.asList(lock));
? ? ? ? ? ? lockAcquired = false;
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? // 拋出異常表示獲取鎖失敗
? ? ? ? ? ? lockAcquired = false;
? ? ? ? }
? ? ? ??
? ? ? ? if (lockAcquired) {
? ? ? ? ? ? /**
? ? ? ? ? ? ?*4. 如果獲取到鎖則添加到已獲取鎖集合中
? ? ? ? ? ? ?*/
? ? ? ? ? ? acquiredLocks.add(lock);
? ? ? ? } else {
? ? ? ? ? ? /**
? ? ? ? ? ? ?* 5. 計(jì)算已經(jīng)申請(qǐng)鎖失敗的節(jié)點(diǎn)是否已經(jīng)到達(dá) 允許加鎖失敗節(jié)點(diǎn)個(gè)數(shù)限制 (N-(N/2+1))
? ? ? ? ? ? ?* 如果已經(jīng)到達(dá), 就認(rèn)定最終申請(qǐng)鎖失敗,則沒有必要繼續(xù)從后面的節(jié)點(diǎn)申請(qǐng)了
? ? ? ? ? ? ?* 因?yàn)?Redlock 算法要求至少N/2+1 個(gè)節(jié)點(diǎn)都加鎖成功,才算最終的鎖申請(qǐng)成功
? ? ? ? ? ? ?*/
? ? ? ? ? ? if (locks.size() - acquiredLocks.size() == failedLocksLimit()) {
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }

? ? ? ? ? ? if (failedLocksLimit == 0) {
? ? ? ? ? ? ? ? unlockInner(acquiredLocks);
? ? ? ? ? ? ? ? if (waitTime == -1 && leaseTime == -1) {
? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? failedLocksLimit = failedLocksLimit();
? ? ? ? ? ? ? ? acquiredLocks.clear();
? ? ? ? ? ? ? ? // reset iterator
? ? ? ? ? ? ? ? while (iterator.hasPrevious()) {
? ? ? ? ? ? ? ? ? ? iterator.previous();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? failedLocksLimit--;
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? /**
? ? ? ? ?* 6.計(jì)算 目前從各個(gè)節(jié)點(diǎn)獲取鎖已經(jīng)消耗的總時(shí)間,如果已經(jīng)等于最大等待時(shí)間,則認(rèn)定最終申請(qǐng)鎖失敗,返回false
? ? ? ? ?*/
? ? ? ? if (remainTime != -1) {
? ? ? ? ? ? remainTime -= System.currentTimeMillis() - time;
? ? ? ? ? ? time = System.currentTimeMillis();
? ? ? ? ? ? if (remainTime <= 0) {
? ? ? ? ? ? ? ? unlockInner(acquiredLocks);
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
? ? ? ? }
? ? }

? ? if (leaseTime != -1) {
? ? ? ? List<RFuture<Boolean>> futures = new ArrayList<>(acquiredLocks.size());
? ? ? ? for (RLock rLock : acquiredLocks) {
? ? ? ? ? ? RFuture<Boolean> future = ((RedissonLock) rLock).expireAsync(unit.toMillis(leaseTime), TimeUnit.MILLISECONDS);
? ? ? ? ? ? futures.add(future);
? ? ? ? }
? ? ? ??
? ? ? ? for (RFuture<Boolean> rFuture : futures) {
? ? ? ? ? ? rFuture.syncUninterruptibly();
? ? ? ? }
? ? }

? ? /**
? ? ?* 7.如果邏輯正常執(zhí)行完則認(rèn)為最終申請(qǐng)鎖成功,返回true
? ? ?*/
? ? return true;
}

到此這篇關(guān)于Redis分布式鎖之紅鎖的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Redis 紅鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • redis 替代php文件存儲(chǔ)session的實(shí)例

    redis 替代php文件存儲(chǔ)session的實(shí)例

    這篇文章主要介紹了redis 替代php文件存儲(chǔ)session的實(shí)例的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家掌握這樣的方法,需要的朋友可以參考下
    2017-10-10
  • 爬蟲技術(shù)之分布式爬蟲架構(gòu)的講解

    爬蟲技術(shù)之分布式爬蟲架構(gòu)的講解

    今天小編就為大家分享一篇關(guān)于爬蟲技術(shù)之分布式爬蟲架構(gòu)的講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • Redis緩存lettuce更換為Jedis的實(shí)現(xiàn)步驟

    Redis緩存lettuce更換為Jedis的實(shí)現(xiàn)步驟

    在springboot中引入spring-boot-starter-data-redis依賴時(shí),默認(rèn)使用的是lettuce,如果不想使用lettuce而是使用Jedis連接池,本文主要介紹了Redis緩存lettuce更換為Jedis的實(shí)現(xiàn)步驟,感興趣的可以了解一下
    2024-08-08
  • 淺談Redis哨兵模式的使用

    淺談Redis哨兵模式的使用

    這篇文章主要介紹了淺談Redis哨兵模式的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 聊聊redis-dump工具安裝問(wèn)題

    聊聊redis-dump工具安裝問(wèn)題

    這篇文章主要介紹了redis-dump工具安裝問(wèn)題,由于安裝redis-dump工具需要使用rvm?和gem工具所以要提前安裝,詳細(xì)的安裝過(guò)程本文給大家提到過(guò),需要的朋友可以參考下
    2022-01-01
  • CentOS7.5使用mysql_multi方式安裝MySQL5.7.28多實(shí)例(詳解)

    CentOS7.5使用mysql_multi方式安裝MySQL5.7.28多實(shí)例(詳解)

    這篇文章主要介紹了CentOS7.5使用mysql_multi方式安裝MySQL5.7.28多實(shí)例,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • 淺談Redis安全策略

    淺談Redis安全策略

    Redis 提供了諸多安全策略,比如為了保證數(shù)據(jù)安全,提供了設(shè)置密碼的功能。本文就詳細(xì)的介紹了一下Redis安全策略,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-11-11
  • Redis主從復(fù)制詳解

    Redis主從復(fù)制詳解

    今天小編就為大家分享一篇關(guān)于Redis主從復(fù)制詳解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • Redis swap空間(虛擬內(nèi)存)的使用詳解

    Redis swap空間(虛擬內(nèi)存)的使用詳解

    這篇文章主要介紹了Redis swap空間的使用示例,幫助大家更好的理解和學(xué)習(xí)使用Redis數(shù)據(jù)庫(kù),感興趣的朋友可以了解下
    2021-03-03
  • 使用Jedis面臨的非線程安全問(wèn)題詳解

    使用Jedis面臨的非線程安全問(wèn)題詳解

    網(wǎng)上都說(shuō)jedis實(shí)例是非線程安全的,常常通過(guò)JedisPool連接池去管理實(shí)例,在多線程情況下讓每個(gè)線程有自己獨(dú)立的jedis實(shí)例,但都沒有具體說(shuō)明為啥jedis實(shí)例時(shí)非線程安全的,本文就來(lái)和大家詳細(xì)說(shuō)說(shuō)
    2022-12-12

最新評(píng)論

宣化县| 浦东新区| 湘潭市| 喜德县| 忻州市| 黄梅县| 盐津县| 西城区| 和静县| 盘锦市| 孙吴县| 锡林浩特市| 临安市| 满洲里市| 荆门市| 遵义市| 大埔区| 吉安县| 香河县| 西充县| 咸阳市| 沾益县| 锡林浩特市| 西青区| 洛川县| 惠安县| 宜兰市| 新郑市| 云阳县| 家居| 策勒县| 河曲县| 西青区| 阳高县| 德惠市| 临漳县| 东乌珠穆沁旗| 临沧市| 屏南县| 乡宁县| 绥宁县|