一. 前言
(1)事件的描述:在新項(xiàng)目上線后,部分基礎(chǔ)數(shù)據(jù)需要兩個(gè)系統(tǒng)進(jìn)行同步。這些基礎(chǔ)數(shù)據(jù)涉及大量的歷史數(shù)據(jù),需要從新上線的項(xiàng)目中,同步到其他有關(guān)聯(lián)的系統(tǒng)中。同步的是方式采用RocketMq進(jìn)行消息推送和消費(fèi)。
(2)事故的反思:為避免今后在犯同樣的錯(cuò)誤,反思bug為何未在測試環(huán)節(jié)中被暴露出來,最主要的原因還是并未進(jìn)行充分的測試,測試的場景并不能覆蓋生產(chǎn)中所能涉及到的所有場景,導(dǎo)致事故的發(fā)生。
二. 事故回顧排查經(jīng)過
(1)在基礎(chǔ)數(shù)據(jù)同步過程中,一共有四部分基礎(chǔ)數(shù)據(jù)需要同步。按照數(shù)據(jù)依賴關(guān)系,有先后順序的進(jìn)行同步,當(dāng)在第四部分?jǐn)?shù)據(jù)也是數(shù)據(jù)量最大的一部分?jǐn)?shù)據(jù)同步時(shí),bug被暴露出來。數(shù)據(jù)量大概是13000多條,同步的方式是批量同步,由于雙方系統(tǒng)中都有限制,所以批量同步時(shí),每條報(bào)文中的數(shù)據(jù)量是30條。計(jì)算下來也就是需要推送434次,才可以將人員信息 全部推送完成。
至此就是本次事故的起始情況,下面來看一下異常信息。
(2)too many open files 異常
分析:從異常的直觀含以上來看是開起了太多的文件數(shù)據(jù)量,導(dǎo)致 consumer 再創(chuàng)建socket鏈接時(shí)失敗。通過百度查閱后學(xué)習(xí)到,在linux系統(tǒng)一切都是文件,socket也是以文件的形式存在,那么由此就可以將異常鏈接起來了,每創(chuàng)建一個(gè)socket鏈接或每開啟一個(gè)線程或者進(jìn)程,都是在創(chuàng)建并開啟一個(gè)文件,這個(gè)文件在linux系統(tǒng)中的學(xué)名叫做“文件句柄”。
并且每臺(tái)Linux系統(tǒng)中都有默認(rèn)的 “文件句柄”數(shù)量的限制,默認(rèn)是1024個(gè)(通過 ulimit -a 可以查看)通常只有在高并發(fā)的場景下會(huì)出現(xiàn)該情況,但以當(dāng)前的配置來看,足以支撐現(xiàn)有的并發(fā)數(shù)。
(3)繼續(xù)往下看, 正常情況下,socket使用后close掉是會(huì)被正常關(guān)閉回收掉的,且在新上線的系統(tǒng)并不會(huì)有什么并發(fā)量,所以socket持續(xù)存在是并不正常的,通過 ps -ef | grep TIME_WAIT 可以查看到,項(xiàng)目所在的服務(wù)器中有大量的 socket 處在等待狀態(tài),這也就是為生socket 不能在被實(shí)例化和 too many open files 的原因。只要批量個(gè)幾次,一定會(huì)超過1024這個(gè)open file的數(shù)量。
接下來,查看 err log 中異常拋出的具體類 ,從代碼中找到了這樣一段代碼
這段代碼的功能是用來創(chuàng)建 MQ 中 Producer 與 Broker(這里的broker是阿里的ONS)的鏈接方法,會(huì)實(shí)例化一個(gè)Producer出來供后續(xù)方法調(diào)用,實(shí)例化的本質(zhì)也就是創(chuàng)建一個(gè)和Broker 的RPC鏈接,至此too many open files 的原因就基本說的通了。
(4)再來看另外一段代碼
創(chuàng)建完鏈接后,緊接這就是方法調(diào)用,將數(shù)據(jù)推送出去。但是在推送后并未將資源關(guān)閉,這也就是為什么有那么多處在 TIME_WAIT 狀態(tài)下的 socket 的連接。
至此整個(gè)事故的回顧到此就告一段落了。
三. 方法的改進(jìn)
針對(duì)本次事故產(chǎn)生問題的位置,有兩種解決辦法。
(1)方法一:將創(chuàng)建 Product 實(shí)例化的方法改為單例模式。
此處我們使用 (Double-Check)模式優(yōu)化該方法中的單例模式以提高效率。
(2)方法二:資源調(diào)用完后,關(guān)閉釋放掉資源。
以上兩種方法任選其一即可。但是對(duì)于不同的使用場景,兩種改進(jìn)方法各有優(yōu)勢,具體情況還需具體分析。
四. 總結(jié)
在項(xiàng)目開發(fā)完成后,開發(fā)應(yīng)先將開發(fā)好的功能,盡可能的充分測試,以暴露可能存在的bug。因?yàn)橛行゜ug并不是簡單的黑盒測試可以暴露出來的。代碼書寫要嚴(yán)謹(jǐn),如果時(shí)間允許,每一個(gè)環(huán)節(jié)其實(shí)都值得認(rèn)真反復(fù)的推敲。
@Author : zhankai