redisson使用lock導(dǎo)致死鎖問(wèn)題解決
1、背景
我們是做物聯(lián)網(wǎng)設(shè)備的公司,設(shè)備初始化會(huì)向設(shè)備發(fā)送API接口下發(fā)agora license,當(dāng)時(shí)當(dāng)時(shí)一個(gè)環(huán)境的全部agora設(shè)備都下發(fā)出現(xiàn)了問(wèn)題,具體表現(xiàn)為:
- 當(dāng)前的線程池告警持續(xù)觸發(fā)拒絕策略(調(diào)度線程處理任務(wù)),導(dǎo)致運(yùn)維要求我們進(jìn)行排查
- 線程池資源告警則增加資源,環(huán)境中agora微服務(wù)已經(jīng)增加到了6臺(tái),但是仍然線程的隊(duì)列容量穩(wěn)步上升,增加資源并不能解決問(wèn)題
- 因?yàn)槿蝿?wù)隊(duì)列容量較多,導(dǎo)致大量agora設(shè)備下發(fā)agora都是在初始化的5-6h以后了,涉及設(shè)備面廣,影響較大
2、排查方式
- 使用 jstack 1查看當(dāng)前的線程池開(kāi)頭的線程狀態(tài)與堆棧
- 發(fā)現(xiàn)全部的線程池的線程狀態(tài)都是WATING狀態(tài),查看堆棧,都是在等待Redisson的鎖釋放
- 查看了下對(duì)應(yīng)線程池設(shè)計(jì)的流程,發(fā)現(xiàn)在下發(fā)license時(shí)確實(shí)會(huì)tongguolock方法加鎖
- 查看 騰訊云 日志,發(fā)現(xiàn)同一臺(tái)設(shè)備在日志中頻繁向設(shè)備下發(fā)agora license,10s一次,正常流程應(yīng)當(dāng)至少2min才初始化下發(fā)一次
經(jīng)過(guò)邏輯分析后發(fā)現(xiàn)原因:
多個(gè)設(shè)備出故障頻繁注冊(cè)+redisson.lock() 強(qiáng)制等待鎖釋放造成線程池資源耗盡
以設(shè)備20252025為例,當(dāng)下發(fā)設(shè)備license時(shí),第一次會(huì)創(chuàng)建一個(gè)20252025的鎖,但是這個(gè)設(shè)備也有其他在線程池的進(jìn)程進(jìn)行下發(fā),因?yàn)槭褂玫氖莑ock,是無(wú)限期等待鎖,所以線程池資源來(lái)利用不起來(lái),導(dǎo)致觸發(fā)拒絕策略
redisson創(chuàng)建分布式鎖的lua腳本是
-- Lua 腳本(原子執(zhí)行)
if (redis.call('exists', KEYS[1]) == 0) then
redis.call('hset', KEYS[1], ARGV[2], 1);
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
redis.call('hincrby', KEYS[1], ARGV[2], 1);
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
return redis.call('pttl', KEYS[1]);可以看到value值(Value)的結(jié)構(gòu): 鎖的值存儲(chǔ)的是一個(gè)字符串(String),內(nèi)容為鎖 持有者的唯一標(biāo)識(shí)符和可重入計(jì)數(shù),格式為: :: ·UUID:Redisson客戶端實(shí)例的唯一標(biāo)識(shí)符(每個(gè)客戶端啟動(dòng)時(shí)生成) ·ThreadID:持有鎖的線程ID(支持可重入鎖 同一線程多次加鎖) ·Count:鎖的可重入次數(shù)(初始為1,每次重入加1,釋放時(shí)減1)
uuid為啥不變 猜測(cè)是服務(wù)pod沒(méi)被殺 自己拉起來(lái)時(shí)候 這個(gè)客戶端id不變導(dǎo)致的
在某一次的k8s滾動(dòng)更新時(shí),可能因?yàn)槲丛趯?duì)應(yīng)時(shí)間內(nèi)執(zhí)行完線程池任務(wù)(如最后30s等待關(guān)閉時(shí)間內(nèi),雖然沒(méi)有新任務(wù)進(jìn),但是進(jìn)程1在最后1s釋放了鎖,進(jìn)程2在此時(shí)拿到了鎖),導(dǎo)致finally代碼塊的解鎖邏輯并未執(zhí)行,導(dǎo)致該鎖一直被占用,新pod啟動(dòng)后又給redLock續(xù)期導(dǎo)致該鎖一直沒(méi)有被釋放
因?yàn)檫@兩個(gè)原因?qū)е戮€上出現(xiàn)問(wèn)題
3、解決方式
- 不能使用lock方法而是tryLock,等待一段時(shí)間后釋放掉鎖;并依據(jù)業(yè)務(wù)重要程度業(yè)務(wù)補(bǔ)救(如本次獲取不到鎖,很可能是因?yàn)楫?dāng)前有正在下發(fā)的任務(wù),顧不需要延時(shí)任務(wù)或者持久化這種補(bǔ)救代碼邏輯)且下發(fā)邏輯暫時(shí)不需要考慮Java代碼層面冪等,數(shù)據(jù)庫(kù)主鍵會(huì)保證冪等性
- 推廣一下,其他組件如ReentrantLock也有l(wèi)ock和trylock方法,在開(kāi)發(fā)時(shí)也盡量使用tryLock
到此這篇關(guān)于redisson使用lock導(dǎo)致死鎖問(wèn)題解決的文章就介紹到這了,更多相關(guān)redisson使用lock導(dǎo)致死鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java基于接口實(shí)現(xiàn)模擬動(dòng)物聲音代碼實(shí)例
這篇文章主要介紹了Java基于接口實(shí)現(xiàn)模擬動(dòng)物聲音代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
Java根據(jù)模板實(shí)現(xiàn)excel導(dǎo)出標(biāo)準(zhǔn)化
這篇文章主要為大家詳細(xì)介紹了Java如何根據(jù)模板實(shí)現(xiàn)excel導(dǎo)出標(biāo)準(zhǔn)化,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下2024-03-03
idea插件之如何使用JarEditor編輯Java JAR文件
JarEditor是一款用于在IntelliJIDEA中直接編輯JAR文件的插件,支持反編譯查看和編輯.class文件,并提供即時(shí)編譯與保存功能,通過(guò)JarEditor,用戶可以在IDE內(nèi)一站式完成JAR文件的編輯、管理和打包操作,提高開(kāi)發(fā)效率,但在生產(chǎn)環(huán)境中使用前,請(qǐng)確保備份并測(cè)試修改2025-01-01
快速搭建一個(gè)SpringBoot項(xiàng)目(純小白搭建教程)
本文主要介紹了快速搭建一個(gè)SpringBoot項(xiàng)目,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
基于Java的電梯系統(tǒng)實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了基于Java的電梯系統(tǒng)實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
java觀察者模式實(shí)現(xiàn)和java觀察者模式演化
觀察者模式是經(jīng)典設(shè)計(jì)模式中很常用的一種,平常我們看到的監(jiān)聽(tīng)器,基本上都是采用這種設(shè)計(jì)模式實(shí)現(xiàn)的,這里探討一下觀察者模式的演化2014-02-02
Java實(shí)現(xiàn)數(shù)組轉(zhuǎn)List的四種方式
在Java編程中,數(shù)組和列表是兩種非常常用的數(shù)據(jù)結(jié)構(gòu),數(shù)組是一種固定大小的數(shù)據(jù)結(jié)構(gòu),能夠高效存儲(chǔ)同一類型的數(shù)據(jù),而列表則是一個(gè)更為靈活的結(jié)構(gòu),可以動(dòng)態(tài)調(diào)整大小,將數(shù)組轉(zhuǎn)換為列表是一個(gè)常見(jiàn)的任務(wù),這里我們將介紹四種簡(jiǎn)單實(shí)現(xiàn)方式,需要的朋友可以參考下2025-08-08

