在一次資料庫連接配接問題中,我們堅持認為資料庫連接配接數過萬是阿裡雲rds的問題,但後來阿裡雲提供了當時的資料庫連接配接情況,讓我們動搖了自己的想法。

上面這5個帳戶産生了10030個資料庫連接配接,當看前4個帳戶(産生了9511個連接配接)的名稱時,我們打了一個寒顫 —— 這些都是運作 linux 上的 asp.net core 站點。。。這不是巧合,其中必有蹊跷。随後,我們觀察了主備庫切換後的 rds 中資料庫連接配接情況。有一個運作在 linux 上的 asp.net core 站點,用了3台伺服器,卻産生了1528個資料庫連接配接。
<b>select * from sys.sysprocesses </b>
<b>where loginame='xxx'</b>
重新開機其中1台伺服器上的站點,連接配接數立馬從1528降到了391。什麼情況?資料庫連接配接池發飙了?繼續觀察,目前資料庫中大量的連接配接都是由運作在 linux 上的 asp.net core 站點産生的,而且會随着時間的推移保持增長。
資料庫連接配接洩漏了,這還是第1次遇到!可我們在 aps.net core 應用中所有的資料庫操作都用的是entity framework core,不存在沒有及時關閉資料庫連接配接的情況,唯一可以懷疑的對象是在 system.data.sqlclient 中實作的 ado.net 資料庫連接配接池。
資料庫連接配接池究竟出什麼狀況了?我們在資料庫連接配接字元串中沒有另外設定連接配接池,用的是預設設定(min_pool_size = 0; 與 max_pool_size = 100;)。而且更奇怪的是 max_pool_size 的限制沒起作用,不然隻會報下面的錯誤,不會連接配接數一直增長。
<b>timeout expired. the timeout period elapsed prior to obtaining a connection from the pool. this may have occurred because all pooled connections were in use and max pool size was reached.</b>
我們想來想去,唯一能想得通的解釋是 .net core 的資料庫連接配接池發生了這樣的狀況 —— 連接配接池中已經建立的連接配接無法被重用,不僅如此,而且它們直接被 sqlclient 給無視了,都沒有被計算在 pool size 中,是以根本觸發不了 max_pool_size 的限制,造成連接配接無限制,任由 sqlclient 建。更要命的是,這些被無視的連接配接卻一直在保持着與資料庫的連接配接。于是,連接配接洩露成了命中注定。
在有了這個唯一想得通的猜測後,我們今天開始在測試環境中進行驗證。部署一個 asp.net core 站點,建立一個專用資料庫連接配接帳戶,然後用下面的 sql 語句檢視資料庫連接配接是否被重用,同時在測試伺服器用 tcpdump 進行抓包,并且分别用阿裡雲 rds 與我們自己搭建的 sql server 伺服器進行測試。
<b>select * from sys.sysprocesses where loginame='測試專用帳戶'</b>
如果連接配接池正常工作,第1次通路,建立所需的資料庫連接配接;第2次通路同樣的頁面,應該重用已有的資料庫連接配接,不會建立新的資料庫連接配接。開始測試時,不管連接配接阿裡雲 rds 還是我們自己的 sql server,連接配接池都工作正常,連接配接能被重用。後來分析了一下,雖然生産環境中連接配接數一直在增長,但增長速度不是很快,可能問題的發生需要一定的時間間隔,或許連接配接閑置超過一定時間之後才不會被重用。
于是,我們間隔了10分鐘左右進行通路測試,問題重制了!比如其中的一次測試,同一個頁面第1次通路,産生了5個連接配接;過10分鐘左右再通路,會建立3個連接配接變成8個連接配接;再過10分鐘左右通路,連接配接增長到11個。這種連接配接不能被重用的情況通過 tcp 抓包也可以看出來。如果在很短的時間内通路,連接配接數保持不變(連接配接被重用)。
這個問題不僅在阿裡雲 rds (sql server 2008 r2)可以重制,而且在我們自己搭建的 sql server 2014 也能重制,問題的真相随之水落石出:資料庫連接配接數過萬問題不是阿裡雲 rds 的問題,而是 .net core 中 system.data.sqlclient 的連接配接池在 linux 上的實作問題,<b>我們錯怪了阿裡雲,輕信了微軟</b>。這是我們使用阿裡雲以來對阿裡雲最大的一次誤會,這是我們 .net core 遷移過程中遇到的最大的一個坑。為什麼最近才出現這個問題?是因為我們最近将更多站點遷移到了 asp.net core ,而且将之前一些跑在 windows 上的 asp.net core 站點切換到了 linux 。
如何解決這個問題?我們會察看一下 system.data.sqlclient 的實作代碼,看能否找到實作層面的線索。阿裡雲會進一步驗證這個問題,如果确認是微軟實作上的問題,會與微軟溝通解決。我們在 windows 上進行對比測試發現,在 windows 上連接配接池中閑置的資料庫連接配接過段時間會被自動關閉,與上面 linux 同樣的測試場景,間隔10分鐘後檢視,資料庫連接配接全消失了。
<b>來源:部落格園</b>