日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

Redis系列教程(八):分布式锁的由来、及Redis分布式锁的实现详解

發(fā)布時(shí)間:2024/7/5 数据库 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis系列教程(八):分布式锁的由来、及Redis分布式锁的实现详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


在很多場(chǎng)景中,我們?yōu)榱吮WC數(shù)據(jù)的最終一致性,需要很多的技術(shù)方案來(lái)支持,比如分布式事務(wù)、分布式鎖等。那具體什么是分布式鎖,分布式鎖應(yīng)用在哪些業(yè)務(wù)場(chǎng)景、如何來(lái)實(shí)現(xiàn)分布式鎖呢?今天來(lái)探討分布式鎖這個(gè)話題。

什么是分布式鎖

要介紹分布式鎖,首先要提到與分布式鎖相對(duì)應(yīng)的是線程鎖、進(jìn)程鎖。

1.線程鎖

主要用來(lái)給方法、代碼塊加鎖。當(dāng)某個(gè)方法或代碼使用鎖,在同一時(shí)刻僅有一個(gè)線程執(zhí)行該方法或該代碼段。線程鎖只在同一JVM中有效果,因?yàn)榫€程鎖的實(shí)現(xiàn)在根本上是依靠線程之間共享內(nèi)存實(shí)現(xiàn)的,比如Synchronized、Lock等。

2.進(jìn)程鎖

為了控制同一操作系統(tǒng)中多個(gè)進(jìn)程訪問(wèn)某個(gè)共享資源,因?yàn)檫M(jìn)程具有獨(dú)立性,各個(gè)進(jìn)程無(wú)法訪問(wèn)其他進(jìn)程的資源,因此無(wú)法通過(guò)synchronized等線程鎖實(shí)現(xiàn)進(jìn)程鎖。

3.分布式鎖

當(dāng)多個(gè)進(jìn)程不在同一個(gè)系統(tǒng)中,用分布式鎖控制多個(gè)進(jìn)程對(duì)資源的訪問(wèn)。

分布式鎖的由來(lái)

在傳統(tǒng)單機(jī)部署的情況下,可以使用Java并發(fā)處理相關(guān)的API(如ReentrantLcok或synchronized)進(jìn)行互斥控制。

但是在分布式系統(tǒng)后,由于分布式系統(tǒng)多線程、多進(jìn)程并且分布在不同機(jī)器上,這將使原單機(jī)并發(fā)控制鎖策略失效,為了解決這個(gè)問(wèn)題就需要一種跨JVM的互斥機(jī)制來(lái)控制共享資源的訪問(wèn),這就是分布式鎖的由來(lái)。

當(dāng)多個(gè)進(jìn)程不在同一個(gè)系統(tǒng)中,就需要用分布式鎖控制多個(gè)進(jìn)程對(duì)資源的訪問(wèn)。

分布式鎖的特點(diǎn)

首先,為了確保分布式鎖可用,我們至少要確保鎖的實(shí)現(xiàn)同時(shí)滿足以下四個(gè)條件:

1、互斥性:任意時(shí)刻,只能有一個(gè)客戶端獲取鎖,不能同時(shí)有兩個(gè)客戶端獲取到鎖。

2、安全性:鎖只能被持有該鎖的客戶端刪除,不能由其它客戶端刪除。

3、死鎖:獲取鎖的客戶端因?yàn)槟承┰?#xff08;如down機(jī)等)而未能釋放鎖,其它客戶端再也無(wú)法獲取到該鎖。

4、容錯(cuò):當(dāng)部分節(jié)點(diǎn)(redis節(jié)點(diǎn)等)down機(jī)時(shí),客戶端仍然能夠獲取鎖和釋放鎖。

分布式鎖的具體實(shí)現(xiàn)


分布式鎖一般有三種實(shí)現(xiàn)方式:

1. 數(shù)據(jù)庫(kù)樂(lè)觀鎖;

2. 基于ZooKeeper的分布式鎖;

3.基于Redis的分布式鎖;


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

基于Redis命令:SET key value NX EX max-lock-time

這里補(bǔ)充下: 從2.6.12版本后, 就可以使用set來(lái)獲取鎖, Lua 腳本來(lái)釋放鎖。setnx是老黃歷了,set命令nx,xx等參數(shù), 是為了實(shí)現(xiàn) setnx 的功能。

1.加鎖

public class RedisTool {

private static final String LOCK_SUCCESS = “OK”;

private static final String SET_IF_NOT_EXIST = “NX”;

private static final String SET_WITH_EXPIRE_TIME = “PX”;

/**

* 嘗試獲取分布式鎖

* @param jedis Redis客戶端

* @param lockKey 鎖

* @param requestId 請(qǐng)求標(biāo)識(shí)

* @param expireTime 超期時(shí)間

* @return 是否獲取成功

*/

public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {return true;}return false;}

}

jedis.set(String key, String value, String nxxx, String expx, int time)

這個(gè)set()方法一共有五個(gè)形參:

第一個(gè)為key,我們使用key來(lái)當(dāng)鎖,因?yàn)閗ey是唯一的。

第二個(gè)為value,我們傳的是requestId,很多童鞋可能不明白,有key作為鎖不就夠了嗎,為什么還要用到value?原因就是我們?cè)谏厦嬷v到可靠性時(shí),分布式鎖要滿足第四個(gè)條件解鈴還須系鈴人,通過(guò)給value賦值為requestId,我們就知道這把鎖是哪個(gè)請(qǐng)求加的了,在解鎖的時(shí)候就可以有依據(jù)。requestId可以使用UUID.randomUUID().toString()方法生成。

第三個(gè)為nxxx,這個(gè)參數(shù)我們填的是NX,意思是SET IF NOT EXIST,即當(dāng)key不存在時(shí),我們進(jìn)行set操作;若key已經(jīng)存在,則不做任何操作;

第四個(gè)為expx,這個(gè)參數(shù)我們傳的是PX,意思是我們要給這個(gè)key加一個(gè)過(guò)期的設(shè)置,具體時(shí)間由第五個(gè)參數(shù)決定。

第五個(gè)為time,與第四個(gè)參數(shù)相呼應(yīng),代表key的過(guò)期時(shí)間。

總的來(lái)說(shuō),執(zhí)行上面的set()方法就只會(huì)導(dǎo)致兩種結(jié)果:1. 當(dāng)前沒有鎖(key不存在),那么就進(jìn)行加鎖操作,并對(duì)鎖設(shè)置個(gè)有效期,同時(shí)value表示加鎖的客戶端。2. 已有鎖存在,不做任何操作。

2.解鎖

public class RedisTool {

private static final Long RELEASE_SUCCESS = 1L;

/**

* 釋放分布式鎖

* @param jedis Redis客戶端

* @param lockKey 鎖

* @param requestId 請(qǐng)求標(biāo)識(shí)

* @return 是否釋放成功

*/

public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {

String script = “if redis.call(‘get’, KEYS[1]) == ARGV[1] then return redis.call(‘del’, KEYS[1]) else return 0 end”;
Object
result = jedis.eval(script,
Collections.singletonList(lockKey),Collections.singletonList(requestId));if
(RELEASE_SUCCESS.equals(result)) {return true;}return false;}

}

那么這段Lua代碼的功能是什么呢?其實(shí)很簡(jiǎn)單,首先獲取鎖對(duì)應(yīng)的value值,檢查是否與requestId相等,如果相等則刪除鎖(解鎖)。

以上就是redis實(shí)現(xiàn)分布式鎖詳解,除此之外,也可以使用Redission(Redis 的客戶端)集成進(jìn)來(lái)實(shí)現(xiàn)分布式鎖,也可以使用數(shù)據(jù)庫(kù)等,具體可以參考:

阿里P8架構(gòu)師談:分布式鎖的3種實(shí)現(xiàn)(數(shù)據(jù)庫(kù)、緩存、Zookeeper)

你可能也喜歡:

  • Java多線程系列(十一):ReentrantReadWriteLock的實(shí)現(xiàn)原理與鎖獲取詳解
  • Redis系列教程(二):詳解Redis的存儲(chǔ)類型、集群架構(gòu)、以及應(yīng)用場(chǎng)景
  • Redis系列教程(三):如何解決Redis緩存雪崩、緩存穿透、緩存并發(fā)等5大難題
  • Redis系列教程(五):Redis哨兵、復(fù)制、集群的設(shè)計(jì)原理,以及區(qū)別
  • Redis系列教程(九):Redis的內(nèi)存回收原理,及內(nèi)存過(guò)期淘汰策略詳解
  • Redis系列教程(六):Redis緩存和MySQL數(shù)據(jù)一致性方案詳解

  • 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的Redis系列教程(八):分布式锁的由来、及Redis分布式锁的实现详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。