2009-05-08

.Net Connection Pooling 問題 - (.Net 1.1 一般網路錯誤/ .Net 2.0 在傳送要求至伺服器時發生傳輸層級的錯誤。 (provider: TCP 提供者, error: 0 - 遠端主機已強制關閉一個現存的連線。)

偉哉 微軟~

透過 .Net default Connection Pooling 機制存取 DB

會有問題,其實不是一天兩天的事了

網路上的論壇 也有提到 這樣的問題 已經三、四年了 但是 一點兒也沒有解決的辦法 亦無一通用的說明及解決方法

在 .Net framework 中,使用connection pooling機制存取DB,依不同 framework 版本 又分下列兩種一般的錯誤訊息:

.Net Framework 1.1 -> 一般網路錯誤
.Net Framework 2.0 -> 在傳送要求至伺服器時發生傳輸層級的錯誤。 (provider: TCP 提供者, error: 0 - 遠端主機已強制關閉一個現存的連線。)
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) ....

其實,軟體本身就是 unreliable 的東西

若是一味的依錯誤訊息 斷定是硬體、網路的問題 這樣或許太偏執

以上述的訊息來看,一樣的senario 不一樣的 .net framework 居然丟出這樣不同的訊息
就是 .net framework 的一個問題


再者,明明不是網路問題 卻丟出網路錯誤的message 更是該打屁股

以下聽我道來:

* connection pooling 的美意是因為connection的建立cost非常的高,若能reuse 已建立好的connection,則可省下許多的運算資源

* .NET default 就會 by application domain, connection string 有自動的connection pooling機制
只要是在同一 Application Domain下、擁有相同connection string的 connection,
都會share同一connection pool (default: MIN Pool Size=0; MAX Pool Size=100)

* .Net connection pooling 並沒有檢查 connection pool 中 既有connections有效性的機制
透過以下lab實驗,可以證明這件事
a. 透過 .net client 程式透過connection pooling機制query db,可以讓 pool 中保持一定的connection
b. 在 SQL Server 端,將對應的connection 殺掉(透過 kill)
c. 再透過 .net client 程式透過connection pooling機制query db,偉大的.net 就會依framework版本,吐出上述兩種不同的訊息(都跟網路錯誤有關)

* 由以上小實驗可知,.net framework 的訊息 容易讓developer 誤解,以為 是網路的不穩定,但 實際的原因則是,connection pool 裡的connection 本來就不保證一定是可用、沒問題的

* .Net Framework 並不保證 也不會maintain connection pool 內的connection的正確性

其實,我也是深受其害 才會來做這些驗證的實驗的...

以下是當你遇到這個問題時,建議的解決方法:

1. handle sqlclient 的 exception 並適時加入 retry 或其它exception handling的作業
正解
software is unreliable, 既然有 exception 發生的可能性,為何不 catch 它,而要任由它throw出來
殊不知,thrown exception 的 cost 比 handle exception 的 cost 大上十倍以上
且,加上 exception handling code, 在不發生 exception 的狀態下,根本對程式的performance沒影響
百利而不一害~ 幻想偉大的programmer 們~ 為何不去 handle 它呢 ?

2. 避開它, 不使用connection pooling 機制
停用 connection pooling 的機制(在 connection string 上,加上Pooling=false)
既然不用該機制,當然也就不會有該問題發生啦 :)
不過,這是消極的做法,必竟 不做connection pooling 是會降低一些performance的,
尤其是您的系統是忙碌的線上系統時

3. 調整Connectoin String中 Connection Lifetime 參數 (default 是 0, 即 不主動回收)
透過connection lifetime,把一段時間未使用的connection 進行 release 可以降低 long connectoin可能造成的問題,亦可在 traffic burst(尖峰時段) 時段有pooling, reuse-connection的效果
BTW, 這個值 還要再試驗; 另外,exception 還是要handle 的啦~

Connection Lifetime

0

When a connection is returned to the pool, its creation time is compared with the current time, and the connection is destroyed if that time span (in seconds) exceeds the value specified by Connection Lifetime. This is useful in clustered configurations to force load balancing between a running server and a server just brought online.

A value of zero (0) causes pooled connections to have the maximum connection timeout.


下面是我做的另一個實驗,這更加深了我對 .Net connection pooling 機制的懷疑:

測試原理: 透過簡單的 test driver, 分別以 使用connection pooling、不使用connection pooling的狀況下,在一定的間隔,對Database做簡單的操作 (如: select N'ok')

測試設備: 3台
測試時間: 2天
測試架構: test driver -> web farm(3台設備) -> switch -> clustered DB Server
測試結果: 不用connection pooling 錯誤率 0%
使用connection pooling 錯誤率依測試間隔 往上飆高


以上~ 供各位參考

強調: 這只是在我的實驗環境裡的結果,或許有其它設定值的因素 導致這樣的結果

2 則留言:

Nick'Home 提到...

您好:
目前我遇到的狀況倒不是連線失敗的問題--檢查連線建立失敗時,會改成pooling=false. 目前主要是一旦實際連線數逼近或等於max pool(=700)時,連線速度就變得非常的慢.我所謂實際連線,是因為我的c# AP是透過WINDOWS AP Server端的Web service程式去連接informix DB.從informix主機(Linux)可以看到connection隨著時間不斷飆高,直到達到max pool時,C# AP Query informix Server就變成龜速.此時,將Web Service所在主機的IIS重啟後,連線就全被清除了,速度也恢復正常.但等到user哀哀叫再重開IIS似乎並非良策.因此參考您提到的Connection Lifetime,把它加進去了(設定為600).至於結果如何?因為剛加,目前的連線速度看來還頗正常.等過個一天再看看吧.

匿名 提到...

Foг nеwеst іnformatiοn you hаvе to
ѵisіt intеrnet and on the wеb I found this web site as
a moѕt еxcellеnt wеb pagе fοr most up-to-date updates.


Feel free to surf tο my wеbsitе iphone repair malaysia