redis的opsForValue 作為鎖實現(xiàn)功能和Redisson區(qū)別

一庵寞、前言
分布式鎖是一種用于協(xié)調(diào)分布式系統(tǒng)中多個節(jié)點之間對共享資源進行訪問控制的機制。它可以確保在分布式環(huán)境下墙杯,同一時間只有一個節(jié)點能夠獲取到鎖,并且其他節(jié)點需要等待釋放鎖后才能獲取光酣。

以下是使用分布式鎖的幾個常見場景和原因:

避免資源沖突:當多個節(jié)點需要同時對共享資源進行讀寫操作時,使用分布式鎖可以確保同一時間只有一個節(jié)點能夠執(zhí)行寫操作脉课,避免數(shù)據(jù)沖突和一致性問題救军。

防止重復(fù)處理:在某些業(yè)務(wù)場景中,可能會出現(xiàn)重復(fù)處理的問題倘零,例如訂單支付唱遭、秒殺等。使用分布式鎖可以確保同一時間只有一個節(jié)點能夠處理該任務(wù)呈驶,避免重復(fù)處理和產(chǎn)生臟數(shù)據(jù)拷泽。

控制資源并發(fā):某些資源的并發(fā)操作會導(dǎo)致性能問題,如數(shù)據(jù)庫的并發(fā)寫操作袖瞻。使用分布式鎖可以限制對資源的并發(fā)訪問司致,提高系統(tǒng)的穩(wěn)定性和性能。

避免死鎖:在分布式環(huán)境下聋迎,由于網(wǎng)絡(luò)延遲等原因脂矫,可能會發(fā)生死鎖的情況。使用分布式鎖可以避免死鎖問題的發(fā)生霉晕,確保資源的正確釋放庭再。
二捞奕、使用redisTemplate.opsForValue().setIfAbsent
1獲取鎖:

客戶端通過在Redis中設(shè)置一個特定的鍵,作為鎖的標識佩微,并設(shè)置過期時間以避免死鎖情況缝彬。這個操作可以通過Redis的SETNX命令來實現(xiàn)。如果SETNX命令返回1哺眯,表示鎖獲取成功,客戶端可以繼續(xù)執(zhí)行相應(yīng)的業(yè)務(wù)邏輯扒俯;如果返回0奶卓,表示鎖已經(jīng)被其他客戶端持有,客戶端需要等待或進行重試操作撼玄。
可以通過Redis的SET命令設(shè)置鎖的過期時間夺姑,以防止鎖一直被持有而導(dǎo)致死鎖。設(shè)置過期時間可以保證即使持有鎖的客戶端發(fā)生異常退出掌猛,鎖也會在過期時間后自動釋放盏浙。
2釋放鎖:

客戶端完成業(yè)務(wù)操作后,通過DEL命令刪除鎖的鍵荔茬,即可釋放鎖废膘。只有持有鎖的客戶端才能刪除鎖,以避免誤刪其他客戶端的鎖慕蔚。
下面是一個示例:

@Component
public class DistributedLock {
    private static final String LOCK_KEY = "my_lock";
    private static final long EXPIRE_TIME = 30000; // 鎖的過期時間丐黄,單位為毫秒
    private static final long WAIT_TIME = 1000; // 獲取鎖時的等待時間,單位為毫秒
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    public boolean acquireLock() throws InterruptedException {
        long start = System.currentTimeMillis();
        while (true) {
            Boolean success = redisTemplate.opsForValue().setIfAbsent(LOCK_KEY, "locked", EXPIRE_TIME, TimeUnit.MILLISECONDS);
            if (success != null && success) {
                return true;
            }
            
            long current = System.currentTimeMillis();
            if (current - start > WAIT_TIME) {
                return false;
            }
            
            Thread.sleep(100); // 等待一段時間后進行重試
        }
    }
    
    public void releaseLock() {
        redisTemplate.delete(LOCK_KEY);
    }
}

在上述代碼中孔飒,acquireLock方法嘗試獲取分布式鎖灌闺,如果成功獲取,則返回true坏瞄;如果超過等待時間仍未獲取到鎖桂对,則返回false。releaseLock方法用于釋放鎖鸠匀。
使用setIfAbsent的缺點
使用redisTemplate.opsForValue().setIfAbsent()方法實現(xiàn)分布式鎖存在以下缺點:

可靠性問題:使用redisTemplate.opsForValue().setIfAbsent()方法實現(xiàn)分布式鎖時蕉斜,需要手動編寫代碼來處理鎖的獲取和釋放,容易出現(xiàn)人為的錯誤狮崩,如忘記釋放鎖蛛勉、鎖的過期時間設(shè)置不正確等。而Redisson框架提供了更加可靠的分布式鎖實現(xiàn)睦柴,內(nèi)部封裝了各種功能的鎖诽凌,并提供了易于使用的API,能夠確保鎖的可靠性和正確性坦敌。

功能限制:redisTemplate.opsForValue().setIfAbsent()方法只能實現(xiàn)簡單的鎖功能侣诵,無法支持更復(fù)雜的功能痢法,如可重入鎖、公平鎖杜顺、紅鎖和讀寫鎖等财搁。而Redisson框架提供了豐富的分布式鎖實現(xiàn)方式,可以根據(jù)實際需求選擇適用的鎖類型躬络。

性能問題:redisTemplate.opsForValue().setIfAbsent()方法實現(xiàn)分布式鎖時尖奔,每次都需要與Redis服務(wù)器進行通信,可能會造成較高的網(wǎng)絡(luò)開銷和延遲穷当。而Redisson框架通過內(nèi)部的優(yōu)化和封裝提茁,能夠提供更高效的分布式鎖實現(xiàn),減少與Redis服務(wù)器的通信次數(shù)和網(wǎng)絡(luò)開銷馁菜。

可拓展性問題:使用redisTemplate.opsForValue().setIfAbsent()方法實現(xiàn)分布式鎖時茴扁,隨著業(yè)務(wù)的發(fā)展和變化,可能需要添加更多的功能和特性汪疮,而手動編寫的代碼可能無法滿足新的需求峭火。而Redisson框架提供了豐富的鎖實現(xiàn),同時也支持自定義鎖的擴展智嚷,能夠更好地適應(yīng)業(yè)務(wù)的變化和拓展卖丸。

三、使用redisson實現(xiàn)分布式鎖
通過Redisson框架可以方便地實現(xiàn)分布式鎖纤勒。Redisson是一個基于Redis的分布式Java對象和服務(wù)框架坯苹,提供了豐富的分布式鎖的實現(xiàn)方式。

要使用Redisson實現(xiàn)分布式鎖摇天,需要完成以下步驟:

1 引入Redisson依賴:在項目的pom.xml文件中添加Redisson的依賴粹湃。

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.14.0</version>
</dependency>

2 創(chuàng)建RedissonClient對象:在Spring Boot中,可以通過Redisson的Spring支持來創(chuàng)建RedissonClient對象泉坐。

@Configuration
public class RedissonConfig {
    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        return Redisson.create(config);
    }
}

在上述代碼中为鳄,創(chuàng)建了一個RedissonClient對象,并配置了連接Redis的地址腕让。

3 實現(xiàn)分布式鎖:
使用RedissonClient對象獲取RLock對象孤钦,RLock是Redisson提供的分布式鎖接口。
通過RLock對象的lock方法來獲取鎖纯丸,并在獲取鎖成功后執(zhí)行業(yè)務(wù)邏輯偏形。
通過RLock對象的unlock方法來釋放鎖。
下面是一個示例:

@Service
public class DistributedLockService {
    @Autowired
    private RedissonClient redissonClient;
    
    public void executeWithLock() {
        RLock lock = redissonClient.getLock("my_lock");
        try {
            lock.lock();
            // 執(zhí)行業(yè)務(wù)邏輯...博客原文:https://blog.csdn.net/qq_27471405/article/details/134109185
        } finally {
            lock.unlock();
        }
    }
}

在上述代碼中觉鼻,executeWithLock方法通過redissonClient獲取了一個名為"my_lock"的鎖俊扭,并通過lock方法獲取鎖。在獲取鎖成功后坠陈,可以執(zhí)行業(yè)務(wù)邏輯萨惑。最后捐康,通過unlock方法釋放鎖。

Redisson還提供了其他一些功能強大的分布式鎖實現(xiàn)方式庸蔼,如可重入鎖解总、公平鎖、紅鎖姐仅、讀寫鎖等花枫。這些鎖的實現(xiàn)方式更加靈活和強大,可以根據(jù)實際需求進行選擇和使用萍嬉。

使用Redisson實現(xiàn)分布式鎖時乌昔,需要確保Redis服務(wù)器的可用性和穩(wěn)定性,以避免單點故障導(dǎo)致的鎖失效或鎖的不穩(wěn)定情況壤追。此外,還需要根據(jù)具體的應(yīng)用場景和需求供屉,合理設(shè)置鎖的過期時間行冰,避免鎖的長時間占用。

  1. 可重入鎖(Reentrant Lock):
    可重入鎖是指同一個線程可以多次獲得同一個鎖伶丐,而不會發(fā)生死鎖悼做。Redisson的可重入鎖實現(xiàn)是基于Redis的分布式鎖的一種特例。
@Service
public class ReentrantLockService {
    @Autowired
    private RedissonClient redissonClient;
    
    public void executeWithReentrantLock() {
        RLock lock = redissonClient.getLock("my_lock");
        try {
            lock.lock();
            // 執(zhí)行業(yè)務(wù)邏輯...小小魚兒小小林的博客測試
            executeWithReentrantLock();
        } finally {
            lock.unlock();
        }
    }
}

在上述代碼中哗魂,使用redissonClient獲取了一個名為"my_lock"的可重入鎖肛走,并通過lock方法獲取鎖。在獲取鎖成功后录别,可以執(zhí)行業(yè)務(wù)邏輯朽色,包括遞歸調(diào)用executeWithReentrantLock方法。最后组题,通過unlock方法釋放鎖葫男。

  1. 公平鎖(Fair Lock):
    公平鎖是指按照線程請求鎖的順序來分配鎖。Redisson的公平鎖實現(xiàn)可以保證多個線程按照先后順序獲取鎖崔列。
@Service
public class FairLockService {
    @Autowired
    private RedissonClient redissonClient;
    
    public void executeWithFairLock() {
        RLock lock = redissonClient.getFairLock("my_lock");
        try {
            lock.lock();
            // 執(zhí)行業(yè)務(wù)邏輯...小小魚兒小小林的博客測試
        } finally {
            lock.unlock();
        }
    }
}

在上述代碼中梢褐,使用redissonClient獲取了一個名為"my_lock"的公平鎖,并通過lock方法獲取鎖赵讯。在獲取鎖成功后盈咳,可以執(zhí)行業(yè)務(wù)邏輯。最后边翼,通過unlock方法釋放鎖鱼响。

  1. 紅鎖(Red Lock):
    紅鎖是指在多個Redis節(jié)點上獲取鎖,以提高分布式系統(tǒng)的可靠性和容錯性讯私。Redisson的紅鎖實現(xiàn)是基于Redis的分布式鎖的一種優(yōu)化方式热押。
@Service
public class RedLockService {
    @Autowired
    private RedissonClient redissonClient;
    
    public void executeWithRedLock() {
        RLock lock1 = redissonClient.getLock("lock1");
        RLock lock2 = redissonClient.getLock("lock2");
        RLock lock3 = redissonClient.getLock("lock3");
        
        RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
        try {
            redLock.lock();
            // 執(zhí)行業(yè)務(wù)邏輯...
        } finally {
            redLock.unlock();
        }
    }
}

在上述代碼中西傀,使用redissonClient分別獲取了名為"lock1"、"lock2"和"lock3"的鎖桶癣,并通過RedissonRedLock將這些鎖組合成紅鎖拥褂。在獲取紅鎖成功后,可以執(zhí)行業(yè)務(wù)邏輯牙寞。最后饺鹃,通過unlock方法釋放紅鎖。

  1. 讀寫鎖(ReadWrite Lock):
    讀寫鎖是指在多線程環(huán)境下间雀,對于讀操作可以并行進行悔详,對于寫操作必須互斥進行。Redisson的讀寫鎖實現(xiàn)提供了讀鎖和寫鎖兩種操作惹挟。
@Service
public class ReadWriteLockService {
    @Autowired
    private RedissonClient redissonClient;
    
    public void readWithReadWriteLock() {
        RReadWriteLock rwLock = redissonClient.getReadWriteLock("my_lock");
        RLock readLock = rwLock.readLock();
        try {
            readLock.lock();
            // 執(zhí)行讀操作...
        } finally {
            readLock.unlock();
        }
    }
    
    public void writeWithReadWriteLock() {
        RReadWriteLock rwLock = redissonClient.getReadWriteLock("my_lock");
        RLock writeLock = rwLock.writeLock();
        try {
            writeLock.lock();
            // 執(zhí)行寫操作...
        } finally {
            writeLock.unlock();
        }
    }
}

在上述代碼中茄螃,使用redissonClient獲取了一個名為"my_lock"的讀寫鎖,并通過readLock方法獲取讀鎖连锯,通過writeLock方法獲取寫鎖归苍。在獲取鎖成功后,可以執(zhí)行相應(yīng)的讀操作或?qū)懖僮髟瞬馈W詈笃雌ㄟ^unlock方法釋放鎖。

四摇展、遇到redis單點故障怎么辦
當使用Redisson實現(xiàn)分布式鎖時吻氧,如果遇到Redis服務(wù)器的單點故障,可以采取以下解決方案:

1 Redis Sentinel(哨兵模式):Redis Sentinel是Redis官方提供的高可用性解決方案咏连,它通過監(jiān)控Redis主節(jié)點和從節(jié)點的狀態(tài)盯孙,實現(xiàn)自動故障轉(zhuǎn)移和故障恢復(fù)。在使用Redisson時捻勉,可以配置Redis Sentinel來實現(xiàn)高可用性的Redis集群镀梭,在主節(jié)點故障時,Redis Sentinel會自動將從節(jié)點切換為主節(jié)點踱启,從而保證分布式鎖的可用性报账。

2 Redis Cluster(集群模式):Redis Cluster是Redis官方提供的分布式解決方案,通過將數(shù)據(jù)分散到多個節(jié)點上進行存儲和訪問埠偿,實現(xiàn)高可用性和橫向擴展透罢。使用Redisson時,可以配置Redis Cluster來搭建分布式鎖的集群冠蒋,當某個節(jié)點出現(xiàn)故障時羽圃,其他節(jié)點仍然可以正常工作,確保分布式鎖的可用性抖剿。

3 使用RedLock算法:RedLock算法是由Redis官方提出的一種多實例鎖機制朽寞,通過在多個獨立的Redis實例之間獲取鎖识窿,確保鎖的可靠性。在使用Redisson時脑融,可以使用RedLock算法來實現(xiàn)分布式鎖喻频,通過協(xié)調(diào)多個Redis實例之間的鎖獲取和釋放,即使部分實例發(fā)生故障肘迎,仍然可以保證鎖的可用性甥温。

4 引入其他高可用的中間件:除了Redis本身的高可用性解決方案,也可以考慮引入其他高可用的中間件妓布,如ZooKeeper姻蚓、etcd等。在使用Redisson時匣沼,可以將這些中間件作為分布式鎖的協(xié)調(diào)中心狰挡,用于進行鎖的獲取和釋放操作,以保證分布式鎖的可用性释涛。

以上解決方案都需要在配置和部署時做相應(yīng)的工作圆兵,如正確配置Redis Sentinel或Redis Cluster、合理設(shè)計Redis實例的數(shù)量和分布枢贿、選擇合適的RedLock算法實現(xiàn)等。同時刀脏,還需要在代碼實現(xiàn)中考慮異常處理和重試機制局荚,以應(yīng)對可能出現(xiàn)的故障和異常情況。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末愈污,一起剝皮案震驚了整個濱河市耀态,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌暂雹,老刑警劉巖首装,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異杭跪,居然都是意外死亡仙逻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門涧尿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來系奉,“玉大人,你說我怎么就攤上這事姑廉∪绷粒” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵桥言,是天一觀的道長萌踱。 經(jīng)常有香客問我葵礼,道長,這世上最難降的妖魔是什么并鸵? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任鸳粉,我火速辦了婚禮,結(jié)果婚禮上能真,老公的妹妹穿的比我還像新娘赁严。我一直安慰自己,他們只是感情好粉铐,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布疼约。 她就那樣靜靜地躺著,像睡著了一般蝙泼。 火紅的嫁衣襯著肌膚如雪程剥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天汤踏,我揣著相機與錄音织鲸,去河邊找鬼。 笑死溪胶,一個胖子當著我的面吹牛搂擦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哗脖,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼瀑踢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了才避?” 一聲冷哼從身側(cè)響起橱夭,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桑逝,沒想到半個月后棘劣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡楞遏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年茬暇,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橱健。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡而钞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拘荡,到底是詐尸還是另有隱情臼节,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站网缝,受9級特大地震影響巨税,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜粉臊,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一草添、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扼仲,春花似錦远寸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至矗愧,卻和暖如春灶芝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唉韭。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工夜涕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人属愤。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓女器,卻偏偏與公主長得像,于是被迫代替她去往敵國和親住诸。 傳聞我的和親對象是個殘疾皇子晓避,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容