久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Tomcat 9.0.26高并發(fā)場景下DeadLock問題怎么處理

143次閱讀
沒有評論

共計 2697 個字符,預(yù)計需要花費 7 分鐘才能閱讀完成。

這篇文章給大家分享的是有關(guān) Tomcat 9.0.26 高并發(fā)場景下 DeadLock 問題怎么處理的內(nèi)容。丸趣 TV 小編覺得挺實用的,因此分享給大家做個參考,一起跟隨丸趣 TV 小編過來看看吧。

一、Tomcat 容器 9.0.26 版本 Deadlock 問題 1.1 問題現(xiàn)象 1.1.1  發(fā)生 Deadlock 的背景

某接口 /get.do 壓測,3 分鐘后,成功事務(wù)數(shù) TPS 由 1W 驟降至 0。

1.1.2  Tomcat 服務(wù)器出現(xiàn)大量的 CLOSE_WAIT

被壓測服務(wù)器,出現(xiàn) TCP CLOSE_WAIT 狀態(tài)個數(shù)在 200~2W 左右。

1.2 初步定位:線程堆棧信息入手

通過 jstack 打印 Tomcat 堆棧信息,發(fā)現(xiàn)“Found 1 deadlock”

Found one Java-level deadlock:
=============================
 http-nio-8080-exec-409 :
waiting to lock monitor 0x00007f064805aa78 (object 0x00000006c0ebf148, a java.util.HashSet),
which is held by  http-nio-8080-ClientPoller 
 http-nio-8080-ClientPoller :
waiting to lock monitor 0x00007f05e8061058 (object 0x00000007bfe40a70, a java.lang.Object),
which is held by  http-nio-8080-exec-205 
 http-nio-8080-exec-205 :
waiting to lock monitor 0x00007f0614018448 (object 0x00000006c0e8e088, a java.util.HashSet),
which is held by  http-nio-8080-BlockPoller 
 http-nio-8080-BlockPoller :
waiting to lock monitor 0x0000000001ed06e8 (object 0x00000007bfe110f8, a java.lang.Object),
which is held by  http-nio-8080-exec-380 
 http-nio-8080-exec-380 :
waiting to lock monitor 0x00007f064805aa78 (object 0x00000006c0ebf148, a java.util.HashSet),
which is held by  http-nio-8080-ClientPoller [object Object]

1.2.1  快速修復(fù)方案

內(nèi)部討論后,認(rèn)為當(dāng)前 Tomcat 版本可能有 Bug。不影響項目進(jìn)度,簡單修改方案把 SpringBoot 使用的 Tomcat 9.0.26 降級到 Tomcat 8。降級后再次壓測,沒有發(fā)現(xiàn)問題。基本上可以確定 Tomcat 9.0.26 應(yīng)該是存在 Deadlock 問題。

1.3  問題進(jìn)一步跟蹤 1.3.1  向 Apache 社區(qū)的反饋

為了確認(rèn)問題,我們試著給 Tomcat 提交 Bug 反饋。

從堆棧信息來看,是 3 類線程 5 個線程由于加鎖的順序不致,從而相互等待發(fā)生了死鎖。圖形化上面加鎖的過程如下圖。

1.4 問題原因分析

明確了死鎖的過程,但是哪個環(huán)節(jié)出了問題呢。這就需要深入到源碼層去定位問題。首先需要下載 OpenJDK 源碼,然后是 Tomcat 9.0.26 的源碼。根據(jù)堆棧信息,定位到相應(yīng)的代碼位置。我們理出如下圖 Tomcat 9.0.26 死鎖流程說明。

要比較好的理解上圖,需要對于 NIO 有一定的了解。在 Tomcat 中 NIO 主要是理解 NIO Endpoint。

Poller 是對于 Selector 的一個封裝,而線程名為 exec-xx 的執(zhí)行線程是 Channel 的封裝。在 NIO 中 Channel 注冊到 Selector 然后通過 SelectionKey 來記錄對應(yīng)關(guān)系。到此,主角都上場了。

Poller 的 run 方法作為后臺線程一直在輪詢(select)準(zhǔn)備好的 SelectionKey,在輪詢的時候也順便需要把 cancelledKey 中的 SelectionKey 給反注冊。執(zhí)行線程 EXEC-XX 在處理時會先判斷連接的狀態(tài),比如失敗、異常等情況會調(diào)用 Channel 的 close 方法去關(guān)閉連接。

而 Channel 的 close 實際只是把 SelectionKey 加入到 cancelledKey。兩者都需要先鎖定,但鎖定的順序不一致,從而導(dǎo)致死鎖。

1.4.1  與 Tomcat 開發(fā)者的交流

在提交 Bug 后,很快得到了 Remy Maucherat 的回復(fù),首先他提到這個 NIO 內(nèi)部的死鎖。然后我們提到 NIO 內(nèi)部的死鎖是由于 Poller.run 和 Poller.canceledKey 在并發(fā)時導(dǎo)到的。

Remy Maucherat 很快就進(jìn)行了修復(fù),主要是把 Poller.canceledKey 中 close 移到了 finally 中去執(zhí)行,也就是先讓 Poller.run 獲得鎖。

在得到修復(fù)后,我們使用替換后的代碼進(jìn)行了再次壓測,死鎖問題沒有出現(xiàn)了。Remy Maucherat 同時提到在最新的 OpenJDK 中相關(guān)問題的修復(fù),但只會出現(xiàn)在 jdk 11 和 14 版本。

溝通中的詳情見下圖。

1.4.2  Github 上修復(fù)的驗證

https://github.com/apache/tomcat/commit/9b1a8b67bffe462fc745b19e15ed59c37e2e1dcf

1.5 結(jié)果驗證

使用  
https://github.com/apache/tomcat/commit/9b1a8b67bffe462fc745b19e15ed59c37e2e1dcf  提供修復(fù)后代碼,重新打包 tomcat-embed-core.jar 替換 9.X.XX 的再次壓測,TPS 平穩(wěn)在 1.5W 左右。

到此問題基本是定位清楚,并得到了修復(fù)。Remy Maucherat 也回復(fù)到“The fix will be in Tomcat 9.0.31+”。

目前 Tomcat 最新版本是 Tomcat 9.0.30,還需要耐心等待 31 版本更新。建議使用 Tomcat 8 版本。

感謝各位的閱讀!關(guān)于“Tomcat 9.0.26 高并發(fā)場景下 DeadLock 問題怎么處理”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-08-16發(fā)表,共計2697字。
轉(zhuǎn)載說明:除特殊說明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 阳信县| 新巴尔虎右旗| 兴化市| 化隆| 荔浦县| 应城市| 田东县| 五大连池市| 昌图县| 什邡市| 忻城县| 吐鲁番市| 陆丰市| 温宿县| 哈尔滨市| 绿春县| 揭东县| 贡觉县| 罗城| 明溪县| 黄冈市| 蕉岭县| 永德县| 张家川| 柳河县| 溧水县| 手游| 武川县| 商都县| 富锦市| 邯郸县| 天津市| 班玛县| 洛隆县| 安阳市| 枞阳县| 噶尔县| 长兴县| 旬邑县| 闸北区| 长宁县|