你知道嗎?chrome自動更新到104版本,居然引起Java服務(wù)內(nèi)存泄漏
前言
近期在工作中,遇到了一次很有意思的內(nèi)存泄漏,把排查過程和思路記下來,供大家參考和學(xué)習(xí),如有不正確的,歡迎指正。
起因
最近幾天很多半托管客戶,突然報連接服務(wù)失敗,登上服務(wù)器后查看內(nèi)存很高,為了讓客戶盡快恢復(fù)業(yè)務(wù),運維同事第一時間選擇了重啟。

重啟后,內(nèi)存肉眼可見的速度漲了上來,研發(fā)同事判斷后,可能之后又需要重啟,臨時給客戶部署了備用服務(wù)。(不管三七二十一先擴(kuò)容)
冰山一角
??日志

Too many open files 代表已經(jīng)到了當(dāng)前進(jìn)程可以打開的最大文件數(shù),第一時間選擇了先加大當(dāng)前進(jìn)程打開的最大文件數(shù),讓后續(xù)的請求可以正常處理
echo?-?n?"Max?open?files=85535:85535"?>?/proc/pid/limits
通過命令查看當(dāng)前已經(jīng)打開的文件數(shù)
lsof?-p?pid?|?wc?-l
43326
正常的進(jìn)程不可能打開這么多fd,所以應(yīng)該存在連接泄漏
lsof?-?p?pid?|?grep?can't?identify?protocol

jstack打印當(dāng)前的堆棧
jstack?-l?pid?>?pid.txt
找到當(dāng)前堆棧中使用http地方,排查代碼,檢查代碼有可能沒close連接的地方。
修復(fù)好代碼,上線后,重啟進(jìn)程,在觀察發(fā)現(xiàn)內(nèi)存很平穩(wěn),打開的文件數(shù)也逐漸平穩(wěn)。
你以為這么簡單就完事了?如果就這么簡單,我就不會寫這篇文章了。
第二天,第三天陸續(xù)有其他半托管客戶找過來,同樣的問題,內(nèi)存泄漏,最大文件數(shù)一直居高不下,直到達(dá)到限制。
和上面的客戶一樣,修復(fù)同樣的代碼后,均都恢復(fù)了正常。
提問
1、為什么都是半托管的客戶報這個問題,公有云未有客戶反饋
2、這些半托管的客戶為了穩(wěn)定,代碼已經(jīng)很久沒升級,代碼都是2021年的,為什么都跟商量好似的,一起報問題,難道我有bug吸引體質(zhì)?
3、為什么這些客戶,物理機(jī)房隔離,問題表象卻都一樣?
4、客戶需要一個合理的解釋,我總不能說網(wǎng)絡(luò)抽風(fēng)了吧?
所有不合理的地方,其實都有合理的解釋
半托管:后端服務(wù)和敏感數(shù)據(jù)在客戶機(jī)房,前端網(wǎng)頁在公有云。
理性分析
由于都是半托管客戶,又都是因為fd太多,導(dǎo)致的內(nèi)存泄漏。
那我們有一點是可以肯定的,那就是連接過多,導(dǎo)致fd激增,既然是網(wǎng)絡(luò)問題,那我們就使用 萬能法則 (遇事不決,先抓個包)
tcpdump?-i?any?tcp?-w?tcp.pcap
抓完包后使用wireshark進(jìn)行分析,發(fā)現(xiàn)有很多OPTIONS請求。

waht? 這個請求是使用jsonp的方式,為什么會存在options請求
在查看原本GET請求的內(nèi)容

然后在公有云相同的服務(wù)器抓了個包,發(fā)現(xiàn)只有g(shù)et請求,沒有options請求,那可以說明這個options請求,只有在出現(xiàn)問題的半托管機(jī)器上有
但是我們有那么多半托管客戶,報問題的卻只有幾個
大膽假設(shè)
我們都知道options是瀏覽器發(fā)的跨域預(yù)檢請求,那說明這件事和瀏覽器脫不了干系,通過抓包文件來看,發(fā)options請求的瀏覽器的版本都是chrome 104版本。
嗯,chrome居然又更新了,我們大膽假設(shè)一下,內(nèi)存泄漏和chrome版本有關(guān)系。
為了驗證我的假設(shè),我找到了chrome的升級說明。
嗯,果然只有假設(shè)才會有答案
附上chrome的升級說明。如果打不過也可以看下github的這個說明
??大概意思就是說:
如果你從公網(wǎng)訪問私有網(wǎng)絡(luò),那么會在chrome104版本,發(fā)option進(jìn)行預(yù)檢,該請求帶有一個新的標(biāo)頭(Access-Control-Request-Private-Network: true)。 在這個初始階段,這個請求被發(fā)送,但是目前階段你收到可以不響應(yīng),后續(xù)的請求還是會正常發(fā)送,并不會影響到你的業(yè)務(wù),只會在 DevTools 中顯示警告
下圖帶有private的為私有網(wǎng)絡(luò)

好家伙我一看,我處理的半托管客戶,ip地址都為192x,172x,10x,全都屬于私有網(wǎng)絡(luò),又都從公有云的網(wǎng)站發(fā)起請求,正好符合104版本描述的條件。
而且服務(wù)的代碼比較老,收到options請求,沒有正常釋放,導(dǎo)致了內(nèi)存泄漏。
天啦擼,你能想到一個內(nèi)存泄漏,居然是因為chrome自動更新導(dǎo)致的嗎?
總結(jié)
1、為什么都是半托管的客戶報這個問題,公有云未有客戶反饋
答:只有半托管客戶滿足公有ip訪問私有ip的條件,且部分用戶的chrome瀏覽器自動更新了
2、這些半托管的客戶為了穩(wěn)定,代碼已經(jīng)很久沒升級,代碼都是2021年的,為什么都跟商量好似的,一起報問題,難道我有bug吸引體質(zhì)?
答:chrome自動更新導(dǎo)致
3、為什么這些客戶,物理機(jī)房隔離,問題表象卻都一樣?
答:chrome自動更新導(dǎo)致,代碼版本都比較老
4、客戶需要一個合理的解釋,我總不能說網(wǎng)絡(luò)抽風(fēng)了吧?
答:不知道chrome發(fā)表的版本說明,能不能說服客戶
5、是不是只有chrome104版本受影響?
答:應(yīng)該和chrome104同版本的其他瀏覽器也會受影響,測試edge也會有影響
6、如何判斷我的網(wǎng)站受到影響。
答:首先需要滿足公網(wǎng)訪問私有網(wǎng)絡(luò)的條件,其次可以在chrome請求或者抓包中,查看請求頭有沒有該標(biāo)頭

7、訪問內(nèi)網(wǎng)的https受影響不
答:上圖就是訪問https的服務(wù),會受到影響
8、設(shè)置chrome://flags/#block-insecure-private-network-requests 可以避免不
答:我測試104版本沒效果
9、服務(wù)端如何兼容
答:服務(wù)器應(yīng)檢查是否存在Access-Control-Request-Private-Network: true標(biāo)頭。如果請求中存在此標(biāo)頭,則服務(wù)器應(yīng)檢查Origin標(biāo)頭和請求路徑以及任何其他相關(guān)信息(例如Access-Control-Request-Headers)以確保請求是安全的。通常,您應(yīng)該允許訪問您控制下的單個源。
一旦您的服務(wù)器決定允許該請求,它應(yīng)該響應(yīng)204 No Content(或200 OK)必要的 CORS 標(biāo)頭和新的 PNA 標(biāo)頭。這些標(biāo)頭包括Access-Control-Allow-Origin和Access-Control-Allow-Private-Network: true,以及其他需要的標(biāo)頭。
響應(yīng)示例
HTTP/1.1?204?No?Content
Access-Control-Allow-Origin:?https://foo.example
Access-Control-Allow-Private-Network:?true
或者
HTTP/1.1?200?No?Content
Access-Control-Allow-Origin:?https://foo.example
Access-Control-Allow-Private-Network:?true
10、服務(wù)端要不要兼容更新
答:我認(rèn)為是有必要的,現(xiàn)在chrome發(fā)起options請求,你響應(yīng)或者不響應(yīng)都不會阻止后續(xù)的請求,但是如果他那天在自動更新,你如果未正常處理options請求,就不發(fā)送后續(xù)業(yè)務(wù)請求,
嗯。。。我已經(jīng)聯(lián)想到了一大部分程序員連夜加班修bug的場面了。