溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么用Redis鎖

發(fā)布時間:2021-10-19 16:24:58 來源:億速云 閱讀:141 作者:iii 欄目:編程語言

這篇文章主要介紹“怎么用Redis鎖”,在日常操作中,相信很多人在怎么用Redis鎖問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么用Redis鎖”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習吧!

1 本地鎖

常用的即 synchronize 或 Lock 等 JDK 自帶的鎖,只能鎖住當前進程,僅適用于單體架構(gòu)服務(wù)。 而在分布式多服務(wù)實例場景下必須使用分布式鎖

怎么用Redis鎖

2 分布式鎖

2.1 分布式鎖的原理

廁所占坑理論

可同時去一個地方“占坑”:

  • 占到,就執(zhí)行邏輯

  • 否則等待,直到釋放鎖

可通過自旋方式自旋

“占坑”可以去Redis、DB、任何所有服務(wù)都能訪問的地方。

怎么用Redis鎖

2.2 分布式鎖演進

一階段

// 占分布式鎖,去redis占坑
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");
if(lock) {
	//加鎖成功... 執(zhí)行業(yè)務(wù)
	Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();
	redisTemplate . delete( key: "lock");//fH?ti
	return dataF romDb ;
} else {
	// 加鎖失敗,重試。synchronized()
	// 休眠100ms重試
	// 自旋
	return getCatalogJsonFromDbwithRedisLock();
}
關(guān)注公眾號:麒麟改bug,可獲取Redis實戰(zhàn)學(xué)習筆記一份。

怎么用Redis鎖

問題場景

  • setnx占好了坑,但是業(yè)務(wù)代碼異?;虺绦蛟趫?zhí)行過程中宕機,即沒有執(zhí)行成功刪除鎖邏輯,導(dǎo)致死鎖

解決方案:設(shè)置鎖的自動過期,即使沒有刪除,會自動刪除。

階段二

怎么用Redis鎖

// 1. 占分布式鎖,去redis占坑
Boolean lock = redisTemplate.opsForValue().setIfAbsent( "lock", "110")
if(lock) {
	// 加鎖成功...執(zhí)行業(yè)務(wù)
	
	// 突然斷電
	
	// 2. 設(shè)置過期時間
	redisTemplate.expire("lock", timeout: 30, TimeUnit.SECONDS) ;
	Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();
	//刪除鎖
	redisTemplate. delete( key; "lock");
	return dataFromDb;
} else {
	// 加鎖失敗...重試。 synchronized ()
	// 休眠100ms重試
	// 自旋的方式
	return getCatalogJsonF romDbWithRedisLock();
}

問題場景

  • setnx設(shè)置好,正要去設(shè)置過期時間,宕機,又死鎖

解決方案:設(shè)置過期時間和占位必須是原子操作。redis支持使用setNxEx命令

階段三

怎么用Redis鎖

// 1. 分布式鎖占坑
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "110", 300, TimeUnit.SECONDS);
if(lock)(
	// 加鎖成功,執(zhí)行業(yè)務(wù)
	
	// 2. 設(shè)置過期時間,必須和加鎖一起作為原子性操作
	// redisTemplate. expire( "lock", з0, TimeUnit.SECONDS);
	Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();
	// 刪除鎖
	redisTemplate.delete( key: "lock")
	return dataFromDb;
else {
	// 加鎖失敗,重試
	// 休眠100ms重試
	// 自旋
	return getCatalogJsonFromDbithRedislock()
}

階段四

怎么用Redis鎖

已經(jīng)拿到了 lockvalue ,有了 UUID,但是過期了現(xiàn)在!其他人拿到所鎖設(shè)置了新值,于是 if 后將別人的鎖刪了??!也就是刪除鎖不是原子操作。

Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();
String lockValue = redisTemplate.opsForValue().get("lock");
if(uuid.equals(lockValue)) {
	// 刪除我自己的鎖
	redisTemplate.delete("lock");
}

問題場景

  • 如果正好判斷是當前值,正要刪除鎖時,鎖已過期,別人已設(shè)置成功新值。那刪除的就是別人的鎖.

  • 解決方案

刪除鎖必須保證原子性。使用redis+Lua腳本。

階段五

  • 確保加鎖/解鎖都是原子操作

String script = 
	"if redis.call('get', KEYS[1]) == ARGV[1] 
		then return redis.call('del', KEYS[1]) 
	else 
		return 0 
	end";
	
	關(guān)注公眾號:麒麟改bug,可獲取Redis實戰(zhàn)學(xué)習筆記一份。

保證加鎖【占位+過期時間】和刪除鎖【判斷+刪除】的原子性。 更難的事情,鎖的自動續(xù)期。

到此,關(guān)于“怎么用Redis鎖”的學(xué)習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習,快去試試吧!若想繼續(xù)學(xué)習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI