Redis的setNX分布式鎖超時(shí)時(shí)間失效 -1問題及解決
Redis setNX分布式鎖超時(shí)時(shí)間失效 -1
使用SETNX加鎖
加鎖的思路:
如果 key 不存在,將 key 設(shè)置為 value,如果 key 已存在,則 SETNX 不做任何動(dòng)作。
使用 RedisTemplate 操作Redis
? ? @Autowired ? ? private RedisTemplate redisTemplate; ? ? ? @RequestMapping("/setNx") ? ? public String setNx() { ? ? ? ? String key = "redis_nx_test"; ? ? ? ? String value = "1"; ? ? ? ? ? boolean res = redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), value.getBytes()); ? ? ? ? log.info("setNX:{}", res); ? ? ? ? if (res) { ? ? ? ? ? ? redisTemplate.getConnectionFactory().getConnection().expire(key.getBytes(), 50); ? ? ? ? ? ? log.info("設(shè)置過期時(shí)間"); ? ? ? ? } ? ? ? ? ? return "success"; ? ? }
解決死鎖
考慮一種情況,如果進(jìn)程獲得鎖后,斷開了與 Redis 的連接(可能是進(jìn)程掛掉,或者網(wǎng)絡(luò)中斷),如果沒有有效的釋放鎖的機(jī)制,那么其他進(jìn)程都會(huì)處于一直等待的狀態(tài),即出現(xiàn)“死鎖”。
目前考慮是使用定時(shí)任務(wù)進(jìn)行掃描處理超時(shí)時(shí)間為 -1的key
@Scheduled(initialDelay = 1000,fixedDelay = 1000*60*30) ? ? public void deleteExceptionKey(){ ? ? ? ? String key = "redis_nx_test"; ? ? ? ?? ? ? ? ? //返回 -2 ? 表示這個(gè)key已過期,已不存在 ? ? ? ? //返回 -1 ? 表示這個(gè)key沒有設(shè)置有效期 ? ? ? ? //返回0以上的值 ? 表示是這個(gè)key的剩余有效時(shí)間 ? ? ? ? Long l = redisTemplate.opsForValue().getOperations().getExpire(key); ? ? ? ? log.info("Expire:{}", l); ? ? ? ? if(l == -1){ ? ? ? ? ? ?Boolean b = ?redisTemplate.delete(key); ? ? ? ? ? ? log.info("刪除key:{},{}", key,b); ? ? ? ? } ? ? }
Redis分布式鎖,超時(shí)問題的處理
分布式鎖超時(shí)問題解決方案,主要是基于redission。Redisson是架設(shè)在Redis基礎(chǔ)上的一個(gè)Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory Data Grid)。充分的利用了Redis鍵值數(shù)據(jù)庫提供的一系列優(yōu)勢(shì),基于Java實(shí)用工具包中常用接口,為使用者提供了一系列具有分布式特性的常用工具類。
redis實(shí)現(xiàn)分布式鎖,主要是通過SETNX命令,設(shè)置一組 key,value。在同一時(shí)刻只能有一個(gè)線程設(shè)置成功,該線程獲得了分布式鎖。
分布式可能會(huì)出現(xiàn)的超時(shí)問題
1、誤刪除別人的鎖
A獲取鎖后,事務(wù)執(zhí)行超時(shí)。鎖到期自動(dòng)釋放,B線程獲取到鎖。A完成事務(wù)后,釋放鎖時(shí),把B的鎖釋放了。
解決方案:
每個(gè)線程在獲取鎖式,在寫key-value時(shí),將自己生成的一個(gè)獨(dú)一無二的id寫入value。先校驗(yàn)value,再刪除鎖。這兩個(gè)操作要保證原子性,可以采用Lua腳本。
(如果沒有保證原子性,會(huì)出現(xiàn)A校驗(yàn)完value,鎖失效。B寫入key-value。A刪除B寫入的鎖。)
2、A到期自動(dòng)釋放鎖后,B獲得鎖。出現(xiàn)兩個(gè)鎖并行的情況
A獲取鎖后,開啟一個(gè)守護(hù)線程,定期為A刷新鎖的時(shí)間。這樣A就是一直保持鎖的情況。在redission源碼中有相應(yīng)的程序。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解基于redis實(shí)現(xiàn)的四種常見的限流策略
限流算法在分布式領(lǐng)域是一個(gè)經(jīng)常被提起的話題,當(dāng)系統(tǒng)的處理能力有限時(shí), 如何阻止計(jì)劃外的請(qǐng)求繼續(xù)對(duì)系統(tǒng)施壓,這是一個(gè)需要重視的問題。除了控制流量,限流還有一個(gè)應(yīng)用目的是控制用戶行為,避免垃圾請(qǐng)求2021-06-06基于Redis無序集合如何實(shí)現(xiàn)禁止多端登錄功能
這篇文章主要給你大家介紹了關(guān)于基于Redis無序集合如何實(shí)現(xiàn)禁止多端登錄功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12解析高可用Redis服務(wù)架構(gòu)分析與搭建方案
我們按照由簡(jiǎn)至繁的步驟,搭建一個(gè)最小型的高可用的Redis服務(wù)。 本文通過四種方案給大家介紹包含每種方案的優(yōu)缺點(diǎn)及詳細(xì)解說,具體內(nèi)容詳情跟隨小編一起看看吧2021-06-06基于Redis位圖實(shí)現(xiàn)系統(tǒng)用戶登錄統(tǒng)計(jì)
這篇文章主要介紹了基于Redis位圖實(shí)現(xiàn)系統(tǒng)用戶登錄統(tǒng)計(jì),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11