關於Sql Server最大連接數(Max Pool Size)的配置問題

Timeout expired 超時時間已到. 達到了最大池大小 錯誤及Max Pool Size設置
參考數據庫鏈接串:
[code=sql]<add key="data" value="server=192.168.1.123; Port=3306; uid=root; pwd=root;database=data;pooling=true;min pool size=5;max pool size=512;connect timeout = 20; "/> [/code]
查看應用程序池佔用數量:
[code=sql]select * from sysprocesses where dbid= db_id('數據庫名')[/code]
Max Pool Size:如果未設置則默認爲100,理論最大值爲32767。最大連接數是連接池能申請的最大連接數,如果數據庫連接請求超過此數,後面的數據庫連接請求將被加入到等待隊列中,這會影響之後的數據庫操作。在等待隊列中,默認等待與服務器的連接的時間爲15秒。
中文錯誤:
超時時間已到。超時時間已到,但是尚未從池中獲取連接。出現這種情況可能是因爲所有池連接均在使用,並且達到了最大池大小。
英文錯誤:
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. 
問題描述:我們獲取連接超過連接池最大值時產生如上異常。通常連接池最大值爲100。當我們獲取連接超過最大值時,ADO.NET等待連接池返回連接而超時,這樣將拋出如上異常
解決辦法:首先要做的是在我們使用連接後立即關閉連接。如果沒有關閉連接那麼連接將保存到連接池中知道GC來銷燬。這種情況下你以爲連接池沒有到達最大值但實際上連接池已經到達了最大值 其次我們可以通過連接字符串中的Max Pool Size = N;來動態擴大連接池中的連接最大數量。

說明: 
也就是在connectionString中如果未指定max pool size的值,則max pool size=100,當訪問人員同時連接數據庫的數量爲101人時,則等待SqlConnection.ConnectionTimeout設置的時間(默認是15 秒)後,還是沒有可用的Connection則會出現上面的錯誤。
當我們設置爲:
"Server=(local); Integrated Security=SSPI; Database=Northwind; Max Pool Size=512; Min Pool Size=5"  時。則訪問人員同時連接數據庫的數量爲513時,則等待SqlConnection.ConnectionTimeout設置的時間(默認是15 秒)後,還是沒有可用的Connection則 就會出現上面的錯誤。

-          Connection Pool 是什麼呢 ?
每當程序需要讀寫數據庫的時候。Connection.Open()會使用ConnectionString連接到數據庫,數據庫會爲程序建立 一個連接,並且保持打開狀態,此後程序就可以使用T-SQL語句來查詢/更新數據庫。當執行到Connection.Close()後,數據庫就會關閉當 前的連接。很好,一切看上去都是如此有條不紊。

但是如果我的程序需要不定時的打開和關閉連接,(比如說 ASP.Net 或是 Web Service ),例如當Http Request發送到服務器的時候、,我們需要打開Connection 然後使用Select* from Table 返回一個DataTable/DataSet給客戶端/瀏覽器,然後關閉當前的Connection。那每次都Open/Close Connection 如此的頻繁操作對於整個系統無疑就成了一種浪費。

ADO.Net Team就給出了一個比較好地解決方法。將先前的Connection保存起來,當下一次需要打開連接的時候就將先前的Connection 交給下一個連接。這就是Connection Pool。



-          Connection Pool 如何工作的?
首先當一個程序執行Connection.open()時候,ADO.net就需要判斷,此連接是否支持Connection Pool (Pooling 默認爲True),如果指定爲False, ADO.net就與數據庫之間創建一個連接(爲了避免混淆,所有數據庫中的連接,都使用”連接”描述),然後返回給程序。
如果指定爲 True,ADO.net就會根據ConnectString創建一個Connection Pool,然後向Connection Pool中填充Connection(所有.net程序中的連接,都使用”Connection”描述)。填充多少個Connection由Min Pool Size (默認爲0)屬性來決定。例如如果指定爲5,則ADO.net會一次與SQL數據庫之間打開5個連接,然後將4個Connection,保存在 Connection Pool中,1個Connection返回給程序。

當程序執行到Connection.close() 的時候。如果Pooling 爲True,ADO.net 就把當前的Connection放到Connection Pool並且保持與數據庫之間的連接。
同時還會判斷Connection Lifetime(默認爲0)屬性,0代表無限大,如果Connection存在的時間超過了Connection LifeTime,ADO.net就會關閉的Connection同時斷開與數據庫的連接,而不是重新保存到Connection Pool中。
(這個設置主要用於羣集的SQL 數據庫中,達到負載平衡的目的)。如果Pooling指定爲False,則直接斷開與數據庫之間的連接。

然後當下一次Connection.Open() 執行的時候,ADO.Net就會判斷新的ConnectionString與之前保存在Connection Pool中的Connection的connectionString是否一致。
(ADO.Net會將ConnectionString轉成二進制流,所 以也就是說,新的ConnectionString與保存在Connection Pool中的Connection的ConnectionString必須完全一致,即使多加了一個空格,或是修改了Connection String中某些屬性的次序都會讓ADO.Net認爲這是一個新的連接,而從新創建一個新的連接。所以如果您使用的UserID,Password的認 證方式,修改了Password也會導致一個Connection,如果使用的是SQL的集成認證,就需要保存兩個連接使用的是同一個)。
然後 ADO.net需要判斷當前的Connection Pool中是否有可以使用的Connection(沒有被其他程序所佔用),如果沒有的話,ADO.net就需要判斷ConnectionString設 置的Max Pool Size (默認爲100),如果Connection Pool中的所有Connection沒有達到Max Pool Size,ADO.net則會再次連接數據庫,創建一個連接,然後將Connection返回給程序。
如果已經達到了 MaxPoolSize,ADO.net就不會再次創建任何新的連接,而是等待Connection Pool中被其他程序所佔用的Connection釋放,這個等待時間受SqlConnection.ConnectionTimeout(默認是15 秒)限制,也就是說如果時間超過了15秒,SqlConnection就會拋出超時錯誤(所以有時候如果SqlConnection.open()方法拋 出超時錯誤,一個可能的原因就是沒有及時將之前的Connnection關閉,同時Connection Pool數量達到了MaxPoolSize。)
如果有可用的Connection,從Connection Pool 取出的Connection也不是直接就返回給程序,ADO.net還需要檢查ConnectionString的ConnectionReset屬性 (默認爲True)是否需要對Connection 最一次reset。這是由於,之前從程序中返回的Connection可能已經被修改過,比如說使用 SqlConnection.ChangeDatabase method 修改當前的連接,此時返回的Connection可能就已經不是連接當前的Connection String指定的Initial Catalog數據庫了。所以需要reset一次當前的連接。但是由於所有的額外檢查都會增大ADO.net Connection Pool 對系統的開銷。

點擊打開鏈接
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章