国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Redis從入門到進(jìn)階】第 7 講:基于 Redis 實(shí)現(xiàn)分布式鎖

這篇具有很好參考價(jià)值的文章主要介紹了【Redis從入門到進(jìn)階】第 7 講:基于 Redis 實(shí)現(xiàn)分布式鎖。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

本文已收錄于專欄
??《Redis從入門到進(jìn)階》??

專欄前言

?? 本專欄開啟,目的在于幫助大家更好的掌握學(xué)習(xí)Redis,同時(shí)也是為了記錄我自己學(xué)習(xí)Redis的過程,將會(huì)從基礎(chǔ)的數(shù)據(jù)類型開始記錄,直到一些更多的應(yīng)用,如緩存擊穿還有分布式鎖等。希望大家有問題也可以一起溝通,歡迎一起學(xué)習(xí),對(duì)于專欄內(nèi)容有錯(cuò)還望您可以及時(shí)指點(diǎn),非常感謝大家 ??。

1.什么是分布式鎖?

??鎖這個(gè)東西,大家都知道,在我們 jvm 內(nèi)部多個(gè)線程競(jìng)爭(zhēng)同一個(gè)資源時(shí),我們利用jvm提供的synchronized 或者一些其他的鎖可以幫助我們讓線程對(duì)資源的串行使用。但這種方法并不適合現(xiàn)在企業(yè)廣泛使用的分布式架構(gòu)。因?yàn)樵谶@種集群模式下,jvm內(nèi)部的鎖無(wú)法被其他jvm內(nèi)部感知到,那這樣肯定無(wú)法滿足我們的要求,因?yàn)殒i肯定是要被大家都能感知到的,所以分布式鎖應(yīng)用而生。以前的鎖競(jìng)爭(zhēng)對(duì)象是線程之間,而分布式系統(tǒng)中競(jìng)爭(zhēng)共享資源的單位從線程升級(jí)為了進(jìn)程。

2. 分布式鎖的條件

??那么作為一個(gè)分布式鎖,它應(yīng)該具備哪些條件呢?

  1. 可見性:多個(gè)進(jìn)程之間均可以看見該鎖,且可以嘗試獲取該鎖
  2. 互斥性:鎖最基本的特性,同一時(shí)間只能保證鎖被一個(gè)進(jìn)程持有
  3. 高可用性:也可以理解為容錯(cuò)性,當(dāng)提供鎖的服務(wù)結(jié)點(diǎn)產(chǎn)生故障時(shí),程序不會(huì)因?yàn)槭氐綇?qiáng)烈影響
  4. 高性能:鎖的釋放和添加本身十分消耗性能,我們應(yīng)選擇性能較好的鎖

3.常見的分布式鎖

??我們一般常見的分布式鎖,有以下三種:

  1. MySQLMySQL自帶鎖機(jī)制,但由于其性能一般,所以作為分布式鎖比較少見
  2. RedisRedis是分布式鎖一種非常常見的實(shí)現(xiàn)方式,我們可以利用setnx這個(gè)方法,如果插入成功表示鎖獲取成功,否則獲取失敗。利用這個(gè)機(jī)制完成互斥,從而實(shí)現(xiàn)分布式鎖,而且Redis存儲(chǔ)在內(nèi)存中本身就符合高性能特點(diǎn)。
  3. ZookeeperZookeeper也是企業(yè)開發(fā)中較好的一種實(shí)現(xiàn)分布式鎖的方案,以后有機(jī)會(huì)講解。

4.Redis 實(shí)現(xiàn)分布式鎖

基于Redis實(shí)現(xiàn)分布式鎖,我們使用兩個(gè)方法:

  • 1.獲取鎖
    【Redis從入門到進(jìn)階】第 7 講:基于 Redis 實(shí)現(xiàn)分布式鎖
    該指令會(huì)插入一個(gè)結(jié)構(gòu)為lock:thread01的鎖,且超時(shí)時(shí)間為100秒,返回值為OK說明獲取鎖成功,失敗則返回false,該方法不會(huì)進(jìn)行阻塞。

  • 2.釋放鎖
    【Redis從入門到進(jìn)階】第 7 講:基于 Redis 實(shí)現(xiàn)分布式鎖
    通過手動(dòng)刪除該鎖來(lái)進(jìn)行釋放,或者可以等待TTL讓該鎖自動(dòng)過期

核心思路:
??利用RedisSETNX方法,當(dāng)多個(gè)進(jìn)程同時(shí)競(jìng)爭(zhēng)該鎖時(shí),都會(huì)調(diào)用該方法獲取鎖,只有一個(gè)進(jìn)程成功能成功獲取成功,此時(shí)Redis將會(huì)生成該鎖,其他進(jìn)程獲取失敗。那么獲取鎖成功的進(jìn)程將會(huì)去執(zhí)行業(yè)務(wù),最后刪除該鎖,這樣就將鎖釋放了。如果想讓獲取鎖失敗的進(jìn)程重新獲取,可以手動(dòng)休眠一段時(shí)間后重新獲取。

下面是一個(gè)簡(jiǎn)單的使用StringRedisTemplate實(shí)現(xiàn)分布式鎖的代碼:

public class DistributedLock {
    
    private StringRedisTemplate redisTemplate;
    private String lockKey;
    private String lockValue;
    private long lockTimeout;
   	//構(gòu)造方法
    public DistributedLock(StringRedisTemplate redisTemplate, String lockKey, String lockValue, long lockTimeout) {
        this.redisTemplate = redisTemplate;
        //key
        this.lockKey = lockKey;
        //value
        this.lockValue = lockValue;
        //過期時(shí)間
        this.lockTimeout = lockTimeout;
    }
  
    public boolean tryLock() {
        // 嘗試獲取鎖
        Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, lockTimeout, TimeUnit.MILLISECONDS);
        return result != null && result;
    }
    
    public void unlock() {
        // 釋放鎖
        redisTemplate.delete(lockKey);
    }
}

5. 分布式鎖誤刪問題

??上面的邏輯看上去完美無(wú)缺,但還是存在很嚴(yán)重的問題,考慮下面一個(gè)場(chǎng)景:
邏輯說明
??線程A持有鎖執(zhí)行業(yè)務(wù)的時(shí)候發(fā)生了堵塞,導(dǎo)致他的鎖TTL到期自動(dòng)釋放了,此時(shí)線程B成功獲取到鎖了,因?yàn)榫€程A已經(jīng)釋放該鎖了。這時(shí)候線程A阻塞完畢后繼續(xù)執(zhí)行完業(yè)務(wù),然后刪除該鎖,線程B執(zhí)行完業(yè)務(wù)時(shí)突然發(fā)現(xiàn)——woc 我鎖呢? 它的鎖被線程A誤刪了,這就是分布式鎖誤刪問題。
解決方案
??上訴問題的產(chǎn)生主要原因,還是因?yàn)槊總€(gè)線程并不知道該鎖是不是自己的,那我們可以在刪除鎖的時(shí)候去加以判斷,如果該鎖不屬于自己,則不刪除該鎖。如果該鎖是自己的且還未到期,再進(jìn)行刪除鎖。我們這里標(biāo)識(shí)一把鎖的時(shí)候同時(shí)存入線程的ID,一般在同一個(gè)jvm中線程的標(biāo)識(shí)一般不相同,但我們這是在集群模式下,所以也有可能出現(xiàn)ThreadID重復(fù)的情況,所以我們可以考慮在前面拼接上一個(gè)UUID

【Redis從入門到進(jìn)階】第 7 講:基于 Redis 實(shí)現(xiàn)分布式鎖
private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";
@Override
public boolean tryLock(long timeoutSec) {
    // 獲取線程標(biāo)識(shí)
    String threadId = ID_PREFIX + Thread.currentThread().getId();
    // 獲取鎖
    Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);
    return Boolean.TRUE.equals(success);
}

@Override
public void unlock() {
    // 獲取當(dāng)前線程的標(biāo)識(shí)
    String threadId = ID_PREFIX + Thread.currentThread().getId();
    // 獲取鎖中的標(biāo)識(shí)
    String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);
    // 判斷標(biāo)識(shí)是否一致
    if (threadId.equals(id)) {
        // 釋放鎖
        stringRedisTemplate.delete(KEY_PREFIX + name);
    }
}

6. 分布式鎖原子性問題

??在進(jìn)行區(qū)分鎖的處理后,那么是不是一定不會(huì)產(chǎn)生問題呢?
??考慮一種更加極端的情況,當(dāng)線程 A判斷完標(biāo)識(shí)發(fā)現(xiàn)一致后,準(zhǔn)備釋放鎖的時(shí)候又突然出現(xiàn)了阻塞情況(比如JVM垃圾揮手),鎖又到期了,線程B進(jìn)來(lái)拿了一把鎖,因?yàn)榫€程A已經(jīng)判斷完標(biāo)識(shí),所以它一刪鎖又把B的鎖給刪掉了,這就又產(chǎn)生了誤刪的問題。
??解決的方案需要我們使用Lua腳本,來(lái)保證拿鎖、判斷標(biāo)識(shí)、刪鎖三個(gè)操作是一個(gè)原子性操作,而Lua腳本可以同時(shí)執(zhí)行多條Redis指令并且保證原子性,Lua腳本是一門腳本語(yǔ)言,有興趣可以自行了解一下。
【Redis從入門到進(jìn)階】第 7 講:基于 Redis 實(shí)現(xiàn)分布式鎖文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-425650.html

到了這里,關(guān)于【Redis從入門到進(jìn)階】第 7 講:基于 Redis 實(shí)現(xiàn)分布式鎖的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 自定義注解,基于redis實(shí)現(xiàn)分布式鎖

    自定義注解,基于redis實(shí)現(xiàn)分布式鎖

    1.1、注解的基礎(chǔ)知識(shí) 實(shí)現(xiàn)自定義注解其實(shí)很簡(jiǎn)單,格式基本都差不多。也就參數(shù)可能變一變。 @Retention:取值決定了注解在什么時(shí)候生效,一般都是取運(yùn)行時(shí),也就是RetentionPolicy.RUNTIME。 @Target:決定了這個(gè)注解可以使用在哪些地方,可以取方法,字段,類等。 注解這就定義

    2024年02月08日
    瀏覽(20)
  • Redis進(jìn)階:分布式鎖問題

    Redis進(jìn)階:分布式鎖問題

    單機(jī)單體中的鎖機(jī)制在分布式集群系統(tǒng)中失效; 單純的Java API并不能提供分布式鎖的能力,為了解決這個(gè)問題就需要一種跨JVM的互斥機(jī)制來(lái)控制共享資源的訪問; 1.2.1 分布式鎖主流的實(shí)現(xiàn)方案 基于數(shù)據(jù)庫(kù)實(shí)現(xiàn)分布式鎖; 基于 緩存(Redis等),性能最高 ; 基于Zookeeper,可靠

    2024年02月08日
    瀏覽(18)
  • 一種基于springboot、redis的分布式任務(wù)引擎的實(shí)現(xiàn)(一)

    ?總體思路是,主節(jié)點(diǎn)接收到任務(wù)請(qǐng)求,將根據(jù)任務(wù)情況拆分成多個(gè)任務(wù)塊,將任務(wù)塊標(biāo)識(shí)的主鍵放入redis。發(fā)送redis消息,等待其他節(jié)點(diǎn)運(yùn)行完畢,結(jié)束處理。接收到信息的節(jié)點(diǎn)注冊(cè)本節(jié)點(diǎn)信息到redis、開啟多線程、獲取任務(wù)塊、執(zhí)行任務(wù)、結(jié)束處理。 1、主節(jié)點(diǎn)接收任務(wù)請(qǐng)求

    2024年02月11日
    瀏覽(20)
  • 基于 Redis + Lua 腳本實(shí)現(xiàn)分布式鎖,確保操作的原子性

    基于 Redis + Lua 腳本實(shí)現(xiàn)分布式鎖,確保操作的原子性

    1.加鎖的Lua腳本: lock.lua 2.解鎖的Lua腳本: unLock.lua 3.將資源文件放在資源文件夾下 4.Java中調(diào)用lua腳本 1)獲取文件方式 2)lua字符串方式 5.jedis調(diào)用Lua腳本實(shí)現(xiàn)分布式重試鎖 1)引入jedis依賴 2)jedis調(diào)用lua

    2024年02月07日
    瀏覽(28)
  • Zookeeper 和 Redis 哪種更好? 為什么使用分布式鎖? 1. 利用 Redis 提供的 第二種,基于 ZK 實(shí)現(xiàn)分布式鎖的落地方案 對(duì)于 redis 的分布式鎖而言,它有以下缺點(diǎn):

    關(guān)于這個(gè)問題,我們 可以從 3 個(gè)方面來(lái)說: 為什么使用分布式鎖? 使用分布式鎖的目的,是為了保證同一時(shí)間只有一個(gè) JVM 進(jìn)程可以對(duì)共享資源進(jìn)行操作。 根據(jù)鎖的用途可以細(xì)分為以下兩類: 允許多個(gè)客戶端操作共享資源,我們稱為共享鎖 這種鎖的一般是對(duì)共享資源具有

    2024年01月16日
    瀏覽(24)
  • Redis實(shí)戰(zhàn)案例14-分布式鎖的基本原理、不同實(shí)現(xiàn)方法對(duì)比以及基于Redis進(jìn)行實(shí)現(xiàn)思路

    Redis實(shí)戰(zhàn)案例14-分布式鎖的基本原理、不同實(shí)現(xiàn)方法對(duì)比以及基于Redis進(jìn)行實(shí)現(xiàn)思路

    基于數(shù)據(jù)庫(kù)的分布式鎖:這種方式使用數(shù)據(jù)庫(kù)的特性來(lái)實(shí)現(xiàn)分布式鎖。具體流程如下: 獲取鎖:當(dāng)一個(gè)節(jié)點(diǎn)需要獲得鎖時(shí),它嘗試在數(shù)據(jù)庫(kù)中插入一個(gè)特定的唯一鍵值(如唯一約束的主鍵),如果插入成功,則表示獲得了鎖。 釋放鎖:當(dāng)節(jié)點(diǎn)完成任務(wù)后,通過刪除該唯一鍵

    2024年02月13日
    瀏覽(49)
  • Asynq: 基于Redis實(shí)現(xiàn)的Go生態(tài)分布式任務(wù)隊(duì)列和異步處理庫(kù)

    Asynq: 基于Redis實(shí)現(xiàn)的Go生態(tài)分布式任務(wù)隊(duì)列和異步處理庫(kù)

    Asynq [1] 是一個(gè)Go實(shí)現(xiàn)的分布式任務(wù)隊(duì)列和異步處理庫(kù),基于redis,類似Ruby的 sidekiq [2] 和Python的 celery [3] 。Go生態(tài)類似的還有 machinery [4] 和goworker 同時(shí)提供一個(gè)WebUI asynqmon [5] ,可以源碼形式安裝或使用Docker image, 還可以和Prometheus集成 docker run --rm --name asynqmon -p 8080:8080 hibiken/as

    2024年02月14日
    瀏覽(22)
  • Redis從基礎(chǔ)到進(jìn)階篇(四)----性能調(diào)優(yōu)、分布式鎖與緩存問題

    Redis從基礎(chǔ)到進(jìn)階篇(四)----性能調(diào)優(yōu)、分布式鎖與緩存問題

    目錄 一、Redis 集群演變 1.1?Replication+Sentinel*高可用 1.2?Proxy+Replication+Sentinel(僅僅了解) 1.3?Redis Cluster 集群 (重點(diǎn)) 1.3.1?Redis-cluster架構(gòu)圖 1.3.2?工作原理 1.3.3?主從切換 1.3.4 副本漂移 1.3.5 分片漂移 二、Redis版本歷史(增加了解) 三、Redis 5.0 源碼清單 (對(duì)源碼感興趣的,看一下

    2024年02月09日
    瀏覽(23)
  • 在Spring中,可以使用不同的方式來(lái)實(shí)現(xiàn)分布式鎖,例如基于數(shù)據(jù)庫(kù)、Redis、ZooKeeper等

    在Spring中,可以使用不同的方式來(lái)實(shí)現(xiàn)分布式鎖,例如基于數(shù)據(jù)庫(kù)、Redis、ZooKeeper等

    在Spring中,可以使用不同的方式來(lái)實(shí)現(xiàn)分布式鎖,例如基于數(shù)據(jù)庫(kù)、Redis、ZooKeeper等。下面是兩種常見的實(shí)現(xiàn)方式: 使用Redis實(shí)現(xiàn)分布式鎖: 使用自定義注解實(shí)現(xiàn)本地鎖: 以上是兩種常見的在Spring中實(shí)現(xiàn)分布式鎖的方式。第一種方式使用Redis作為分布式鎖的存儲(chǔ)介質(zhì),通過

    2024年03月17日
    瀏覽(24)
  • 基于Redis的分布式限流詳解

    基于Redis的分布式限流詳解

    Redis除了能用作緩存外,還有很多其他用途,比如分布式鎖,分布式限流,分布式唯一主鍵等,本文將和大家分享下基于Redis分布式限流的各種實(shí)現(xiàn)方案。 用最簡(jiǎn)單的話來(lái)說: 外部請(qǐng)求是不可控的,而我們系統(tǒng)的負(fù)載是有限的,如果沒有限流機(jī)制,一旦外部請(qǐng)求超過系統(tǒng)承載

    2024年02月04日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包