進程啓動後,線程數迅速上升至最小線程數後,緩慢上升(線程池限制)到數千,而後因爲線程過多,CPU飆升到90%。sql
對外表現爲Api無響應或鏈接超時。數據庫
有些數據存在於另外一個機房,經過內網專線鏈接。一個服務程序有4個數據庫,其中3個在本地機房,1個在外地。 api
各類排查,沒有解決。緩存
函數中,第一句的GetKey函數以下,其中有一個lock。其中代碼僅僅是賦值,或是在集成認證的狀況下才執行。因此卡住的可能性不大。服務器
第二句是個賦值,且MysqlPoolManager.pools是個字段(field),理論上不會卡住。網絡
第二個lock中,若是指定key對應的緩存已存在,則lock會很快返回。若是不存在,則執行new MysqlPool(setttings);函數代碼以下:
異步
其主要功能有socket
這5個步驟中,最可能耗時較久的是步驟d。其餘步驟理論上不會有問題。函數
步驟d中的代碼,雖然就一個函數,可是代碼不少。spa
通過不停的查看代碼,發現其主要功能是根據鏈接字符串中的設置,建立一個指定類型的鏈接。其底層建立代碼以下:
能夠看到,任何建立Stream失敗的狀況都會拋出異常,最終致使鏈接池建立失敗。
其中第一句,GetStream的底層代碼以下:
開始鏈接(BeginConnect)後,即開始了等待。等待的超時默認值以下:
2147483s,即596h。若是有鏈接到數據庫服務器的網絡有問題或其餘緣由致使鏈接不成功,而也未觸發其餘致使失敗的狀況,則會一直等下去。若是推斷正確,那麼全部線程中,必定有線程的調用堆棧在以下位置:
對Dump文件中的全部線程堆棧排序,有且僅有一個線程處於該調用堆棧處。高亮行正是上述堆棧的函數名CreateSocketStream。上面一行就是WaiteOne。以後進入本機代碼。
那麼根本緣由也就清楚了:一個鏈接的建立卡住了數據庫鏈接建立,間接卡住了鏈接池的鎖,又間接卡住了其餘鏈接池的使用和建立。致使全部數據庫鏈接不可用。因此,全部進入的請求通過運行,所有堆在GetPool這裏。
以上全部信息基於.Net版本Mysql.Data 6.9.9版本反編譯分析。