主頁(yè) > 知識(shí)庫(kù) > 詳解redis分布式鎖的這些坑

詳解redis分布式鎖的這些坑

熱門(mén)標(biāo)簽:十堰營(yíng)銷(xiāo)電銷(xiāo)機(jī)器人哪家便宜 魔獸2青云地圖標(biāo)注 山東外呼銷(xiāo)售系統(tǒng)招商 貴州電銷(xiāo)卡外呼系統(tǒng) 超呼電話(huà)機(jī)器人 宿遷便宜外呼系統(tǒng)平臺(tái) 日本中國(guó)地圖標(biāo)注 北京400電話(huà)辦理收費(fèi)標(biāo)準(zhǔn) 鄭州人工智能電銷(xiāo)機(jī)器人系統(tǒng)

一、白話(huà)分布式

什么是分布式,用最簡(jiǎn)單的話(huà)來(lái)說(shuō),就是為了較低單個(gè)服務(wù)器的壓力,將功能分布在不同的機(jī)器上面,本來(lái)一個(gè)程序員可以完成一個(gè)項(xiàng)目:需求->設(shè)計(jì)->編碼->測(cè)試

但是項(xiàng)目多的時(shí)候,一個(gè)人也扛不住,這就需要不同的人進(jìn)行分工合作了

這就是一個(gè)簡(jiǎn)單的分布式協(xié)同工作了;

二、分布式鎖

首先看一個(gè)問(wèn)題,如果說(shuō)某個(gè)環(huán)節(jié)被終止或者別侵占,就會(huì)發(fā)生不可知的事情

這就會(huì)出現(xiàn),設(shè)計(jì)好的或者設(shè)計(jì)的半成品會(huì)被破壞,導(dǎo)致后面環(huán)節(jié)出錯(cuò);

這時(shí)候,我們就需要引入分布式鎖的概念;

何為分布式鎖

當(dāng)在分布式模型下,數(shù)據(jù)只有一份(或有限制),此時(shí)需要利用鎖的技術(shù)控制某一時(shí)刻修改數(shù)據(jù)的進(jìn)程數(shù)。

用一個(gè)狀態(tài)值表示鎖,對(duì)鎖的占用和釋放通過(guò)狀態(tài)值來(lái)標(biāo)識(shí)。

分布式鎖的條件

  • 可以保證在分布式部署的應(yīng)用集群中,同一個(gè)方法在同一時(shí)間只能被一臺(tái)機(jī)器上的一個(gè)線(xiàn)程執(zhí)行。
  • 這把鎖要是一把可重入鎖(避免死鎖)
  • 這把鎖最好是一把阻塞鎖
  • 這把鎖最好是一把公平鎖
  • 有高可用的獲取鎖和釋放鎖功能
  • 獲取鎖和釋放鎖的性能要好

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

分布式鎖的實(shí)現(xiàn)由很多種,文件鎖、數(shù)據(jù)庫(kù)、redis等等,比較多,在實(shí)踐中,還是redis做分布式鎖性能會(huì)高一些;

三、redis實(shí)現(xiàn)分布式鎖

首先看兩個(gè)命令:

setnx:將 key 的值設(shè)為 value,當(dāng)且僅當(dāng) key 不存在。 若給定的 key 已經(jīng)存在,則 SETNX 不做任何動(dòng)作。 SETNX 是SET if Not eXists的簡(jiǎn)寫(xiě)。

127.0.0.1:6379> set lock "unlock"
OK
127.0.0.1:6379> setnx lock "unlock"
(integer) 0
127.0.0.1:6379> setnx lock "lock"
(integer) 0
127.0.0.1:6379>

expire:EXPIRE key seconds

為給定 key 設(shè)置生存時(shí)間,當(dāng) key 過(guò)期時(shí)(生存時(shí)間為 0 ),它會(huì)被自動(dòng)刪除

127.0.0.1:6379> expire lock 10
(integer) 1
127.0.0.1:6379> ttl lock
8
127.0.0.1:6379> get lock
(nil)

基于分布式鎖的流程:

這就是一個(gè)簡(jiǎn)單的分布式鎖的實(shí)現(xiàn)流程,具體代碼實(shí)現(xiàn)也很簡(jiǎn)單,就不贅述了;

四、redis實(shí)現(xiàn)分布式鎖問(wèn)題

如果出現(xiàn)了這么一個(gè)問(wèn)題:如果setnx是成功的,但是expire設(shè)置失敗,那么后面如果出現(xiàn)了釋放鎖失敗的問(wèn)題,那么這個(gè)鎖永遠(yuǎn)也不會(huì)被得到,業(yè)務(wù)將被鎖死?

解決的辦法:使用set的命令,同時(shí)設(shè)置鎖和過(guò)期時(shí)間

set參數(shù):

set key value [EX seconds] [PX milliseconds] [NX|XX]

EX seconds:設(shè)置失效時(shí)長(zhǎng),單位秒

PX milliseconds:設(shè)置失效時(shí)長(zhǎng),單位毫秒

NX:key不存在時(shí)設(shè)置value,成功返回OK,失敗返回(nil)

XX:key存在時(shí)設(shè)置value,成功返回OK,失敗返回(nil)

實(shí)踐:

127.0.0.1:6379> set unlock "234" EX 100 NX
(nil)
127.0.0.1:6379> 
127.0.0.1:6379> set test "111" EX 100 NX
OK

這樣就完美的解決了分布式鎖的原子性。

五、用鎖遇到過(guò)哪些問(wèn)題?又是如何解決的?未關(guān)閉資源

由于當(dāng)前線(xiàn)程 獲取到redis 鎖,處理完業(yè)務(wù)后未及時(shí)釋放鎖,導(dǎo)致其它線(xiàn)程會(huì)一直嘗試獲取鎖阻塞,例如:用Jedis客戶(hù)端會(huì)報(bào)如下的錯(cuò)誤信息

1redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

redis線(xiàn)程池已經(jīng)沒(méi)有空閑線(xiàn)程來(lái)處理客戶(hù)端命令。使用原生方法記得關(guān)閉!

解決的方法也很簡(jiǎn)單,只要我們細(xì)心一點(diǎn),拿到鎖的線(xiàn)程處理完業(yè)務(wù)及時(shí)釋放鎖

B的鎖被A給釋放了

我們知道Redis實(shí)現(xiàn)鎖的原理在于 SETNX命令。當(dāng) key不存在時(shí)將 key的值設(shè)為 value ,返回值為 1;若給定的 key已經(jīng)存在,則 SETNX不做任何動(dòng)作,返回值為 0 。

SETNX key value

我們來(lái)設(shè)想一下這個(gè)場(chǎng)景:A、B兩個(gè)線(xiàn)程來(lái)嘗試給key myLock加鎖,A線(xiàn)程先拿到鎖(假如鎖3秒后過(guò)期),B線(xiàn)程就在等待嘗試獲取鎖,到這一點(diǎn)毛病沒(méi)有。

那如果此時(shí)業(yè)務(wù)邏輯比較耗時(shí),執(zhí)行時(shí)間已經(jīng)超過(guò)redis鎖過(guò)期時(shí)間,這時(shí)A線(xiàn)程的鎖自動(dòng)釋放(刪除key),B線(xiàn)程檢測(cè)到myLock這個(gè)key不存在,執(zhí)行 SETNX命令也拿到了鎖。

但是,此時(shí)A線(xiàn)程執(zhí)行完業(yè)務(wù)邏輯之后,還是會(huì)去釋放鎖(刪除key),這就導(dǎo)致B線(xiàn)程的鎖被A線(xiàn)程給釋放了。

為避免上邊的情況,一般我們?cè)诿總€(gè)線(xiàn)程加鎖時(shí)要帶上自己獨(dú)有的value值來(lái)標(biāo)識(shí),只釋放指定value的key,否則就會(huì)出現(xiàn)釋放鎖混亂的場(chǎng)景

一般我們可以設(shè)置value為業(yè)務(wù)前綴_當(dāng)前線(xiàn)程ID或者uuid,只有當(dāng)前value相同的才可以釋放鎖

鎖過(guò)期了,業(yè)務(wù)還沒(méi)執(zhí)行完

redis分布式鎖過(guò)期,而業(yè)務(wù)邏輯沒(méi)執(zhí)行完的場(chǎng)景,不過(guò),這里換一種思路想問(wèn)題,把redis鎖的過(guò)期時(shí)間再弄長(zhǎng)點(diǎn)不就解決了嗎?

那還是有問(wèn)題,我們可以在加鎖的時(shí)候,手動(dòng)調(diào)長(zhǎng)redis鎖的過(guò)期時(shí)間,可這個(gè)時(shí)間多長(zhǎng)合適?業(yè)務(wù)邏輯的執(zhí)行時(shí)間是不可控的,調(diào)的過(guò)長(zhǎng)又會(huì)影響操作性能。

要是redis鎖的過(guò)期時(shí)間能夠自動(dòng)續(xù)期就好了。

為了解決這個(gè)問(wèn)題我們使用redis客戶(hù)端redisson,redisson很好的解決了redis在分布式環(huán)境下的一些棘手問(wèn)題,它的宗旨就是讓使用者減少對(duì)Redis的關(guān)注,將更多精力用在處理業(yè)務(wù)邏輯上。

redisson對(duì)分布式鎖做了很好封裝,只需調(diào)用API即可。

RLock lock = redissonClient.getLock("stockLock");

redisson在加鎖成功后,會(huì)注冊(cè)一個(gè)定時(shí)任務(wù)監(jiān)聽(tīng)這個(gè)鎖,每隔10秒就去查看這個(gè)鎖,如果還持有鎖,就對(duì)過(guò)期時(shí)間進(jìn)行續(xù)期。默認(rèn)過(guò)期時(shí)間30秒。這個(gè)機(jī)制也被叫做:“看門(mén)狗”

redis主從復(fù)制的坑

redis高可用最常見(jiàn)的方案就是主從復(fù)制(master-slave),這種模式也給redis分布式鎖挖了一坑。

redis cluster集群環(huán)境下,假如現(xiàn)在A客戶(hù)端想要加鎖,它會(huì)根據(jù)路由規(guī)則選擇一臺(tái)master節(jié)點(diǎn)寫(xiě)入key mylock,在加鎖成功后,master節(jié)點(diǎn)會(huì)把key異步復(fù)制給對(duì)應(yīng)的slave節(jié)點(diǎn)。

如果此時(shí)redis master節(jié)點(diǎn)宕機(jī)從節(jié)點(diǎn)復(fù)制失敗,為保證集群可用性,會(huì)進(jìn)行主備切換,slave變?yōu)榱藃edis master。B客戶(hù)端在新的master節(jié)點(diǎn)上加鎖成功,而A客戶(hù)端也以為自己還是成功加了鎖的。另外如果主從復(fù)制延遲同樣也會(huì)造成加鎖和解鎖延遲的問(wèn)題。

此時(shí)就會(huì)導(dǎo)致同一時(shí)間內(nèi)多個(gè)客戶(hù)端對(duì)一個(gè)分布式鎖完成了加鎖,導(dǎo)致各種臟數(shù)據(jù)的產(chǎn)生。

畢竟redis是保持的AP而非CP,如果要追求強(qiáng)一致性可以使用zookeeper分布式鎖。

以上就是詳解redis分布式鎖的這些坑的詳細(xì)內(nèi)容,更多關(guān)于redis分布式鎖的這些坑的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:
  • 基于Redis實(shí)現(xiàn)分布式鎖的方法(lua腳本版)
  • SpringBoot之使用Redis實(shí)現(xiàn)分布式鎖(秒殺系統(tǒng))
  • 詳解Redis 分布式鎖遇到的序列化問(wèn)題
  • 詳解RedisTemplate下Redis分布式鎖引發(fā)的系列問(wèn)題
  • redisson分布式鎖的用法大全
  • php基于redis的分布式鎖實(shí)例詳解
  • Redis分布式鎖升級(jí)版RedLock及SpringBoot實(shí)現(xiàn)方法
  • 利用redis實(shí)現(xiàn)分布式鎖,快速解決高并發(fā)時(shí)的線(xiàn)程安全問(wèn)題
  • 詳解基于redis實(shí)現(xiàn)分布式鎖

標(biāo)簽:吉安 朝陽(yáng) 江蘇 北京 楊凌 果洛 臺(tái)州 大慶

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《詳解redis分布式鎖的這些坑》,本文關(guān)鍵詞  詳解,redis,分布式,鎖,的,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《詳解redis分布式鎖的這些坑》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于詳解redis分布式鎖的這些坑的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章