? ? ? ? NETTY作為優(yōu)秀的NIO通訊框架,深受大家喜愛,在我們的發(fā)版工具項(xiàng)目啟動(dòng)時(shí),便采用其作為通訊框架,但是使用過(guò)程中卻踩了一個(gè)坑。
踩坑分析報(bào)告
項(xiàng)目簡(jiǎn)介:
在發(fā)版工具項(xiàng)目中,由于發(fā)版過(guò)程會(huì)涉及不同的發(fā)版環(huán)境,對(duì)于一次請(qǐng)求,對(duì)應(yīng)的服務(wù)提供方IP需根據(jù)此次請(qǐng)求消息的附加信息確定,同時(shí)考慮到多次請(qǐng)求建鏈的消耗過(guò)程,選擇通訊方式為長(zhǎng)連接;而考慮到連接的管理和并發(fā)控制問(wèn)題,所以加入連接池。對(duì)于NETTY通訊框架,本身已提供連接池,可通過(guò)數(shù)行代碼完成連接池定制過(guò)程,故選擇NETTY的SimpleChannelPool連接池,同時(shí)使用AbstractChannelPoolMap<InetSocketAddress,SimpleChannelPool>管理對(duì)應(yīng)不同IP地址的連接池。
異常場(chǎng)景:
連接池的使用過(guò)程為:根據(jù)請(qǐng)求數(shù)據(jù)傳入的IP信息,從AbstractChannelPoolMap中選定對(duì)應(yīng)的連接池,進(jìn)行后續(xù)通訊過(guò)程。有一次,系統(tǒng)啟動(dòng)后,異常場(chǎng)景出現(xiàn)了,傳入的IP為“36.0.12.112”,但是從MAP中通過(guò)連接池獲取連接時(shí),顯示連接IP為“36.0.12.114”?。。?/p>
異常場(chǎng)景分析:
首先,從連接池初始化過(guò)程看起,初始化代碼如下:

該初始化過(guò)程發(fā)生在此地址對(duì)應(yīng)的第一筆交易時(shí),


如此詭異的問(wèn)題,“并發(fā)問(wèn)題”首先作為了我們的首要嫌疑犯。
? ? ? ? 首先進(jìn)行場(chǎng)景的補(bǔ)全和確認(rèn)過(guò)程,測(cè)試環(huán)境的日志還在,為我們保留了完整的“犯罪”現(xiàn)場(chǎng)。從代碼看,業(yè)務(wù)代碼中存在同步調(diào)用和異步調(diào)用兩個(gè)方法,但代碼都基本類似,使用過(guò)程一般調(diào)用同步方法,即使用圖一的連接池創(chuàng)建過(guò)程。從日志來(lái)看,在進(jìn)程啟動(dòng)后,第一批交易發(fā)起過(guò)程即出現(xiàn)了該問(wèn)題,一筆請(qǐng)求對(duì)應(yīng)發(fā)送到五個(gè)不同的IP地址,則問(wèn)題應(yīng)該發(fā)生在連接池創(chuàng)建過(guò)程或者獲取過(guò)程中,但是如圖一所示,已經(jīng)使用同步代碼塊進(jìn)行控制,雖然此同步代碼塊作用不詳(此處有伏筆),創(chuàng)建過(guò)程由不同線程創(chuàng)建不同的連接池,應(yīng)該不會(huì)出現(xiàn)問(wèn)題,難道MAP存在并發(fā)問(wèn)題?然后就開始越走越遠(yuǎn),甚至懷疑人生。。。。
? ? ? ? 此時(shí),有位同事大神說(shuō),已在本地復(fù)現(xiàn),瞬間感覺要看到了光明,但瞬間又熄滅了。能復(fù)現(xiàn)問(wèn)題的測(cè)試代碼是在圖一的基礎(chǔ)上去掉了同步代碼塊,那看來(lái)同步代碼塊還是有作用的,但這并不是問(wèn)題場(chǎng)景呀。放佛又陷入了無(wú)法解決之坑,這會(huì)兒,見證了詭異現(xiàn)象的老師忽然靈光一閃,出現(xiàn)異常場(chǎng)景的時(shí)候,跟平時(shí)流程有所出入,調(diào)用的方法不是同步方法,而是異步方法,而異步方法中正好沒加入同步代碼塊控制。

? ? ? ? 終于事件大白啦,可見混亂中的場(chǎng)景復(fù)現(xiàn)是多么的重要。到此,基本可以看到坑的面貌啦,接下來(lái)就是詳細(xì)的分析過(guò)程了。
? ? ? ? 如圖四所示,連接池在初始化過(guò)程中需要傳入第一個(gè)參數(shù)為bootstrap,由于對(duì)應(yīng)IP不同,所以需要調(diào)用bootstrap.remoteAddress(paramK)進(jìn)行賦值,重點(diǎn)來(lái)了,bootsrap實(shí)例是作為該類的成員變量存在的,但是bootstrap本身并不是線程安全的。


? ? ? ? 在并發(fā)情況下,該賦值過(guò)程會(huì)出現(xiàn)問(wèn)題,導(dǎo)致MAP中KEY值的IP地址與VALUE中連接池真正的地址信息不符,所以會(huì)出現(xiàn)根據(jù)地址A拿到的連接卻指向地址B的詭異現(xiàn)象。
異常場(chǎng)景分析總結(jié):
一次踩坑的排查終于結(jié)束啦,曲曲折折,不過(guò)為以后問(wèn)題排查點(diǎn)出了很多注意的事項(xiàng)。
一:一定一定一定要最大限度了解異常場(chǎng)景,不要想當(dāng)然;
二:對(duì)測(cè)試環(huán)境出現(xiàn)問(wèn)題保持敏感,并發(fā)問(wèn)題一般比較詭異,很多問(wèn)題在你放過(guò)后可能后續(xù)表現(xiàn)都正常,但是它仍然還在隱患中,可能上線后就暴露出來(lái)了,所以不要放過(guò)測(cè)試環(huán)境的詭異問(wèn)題。