關於Windows頻繁開啟關閉連接埠時出現的問題至老趙)

來源:互聯網
上載者:User

最近事情很多,人也懶,東西看了不少,也想到過一些東西,但就是懶得寫。現在記錄一下前兩個星期做一個壓力測試時出現的現象,希望重開一個好頭。簡單地說,這是個從Windows Server串連Linux下的MongoDB服務時出現的問題。MongoDB使用的是自訂的二進位協議,用戶端使用普通的TCP串連進行串連後再讀寫資料。在以前的測試中,我使用的都是建立少量串連,每個串連進行多次操作,而這次則是對“應用程式”進行壓力測試,因此需要不斷地開啟及關閉串連——頻率大約是每秒4、500次吧。

我使用的環境是Windows Web Server 2008 R2,MongoDB部署在Cent OS上,雙方都是64位作業系統。壓力測試剛開啟時一切順利,效能也比較令人滿意,但是不久後便會拋出這樣的異常:

由於系統緩衝區空間不足或隊列已滿,不能執行通訊端上的操作。

一開始我以為是程式裡有哪個地方沒有釋放串連,於是檢查了程式碼,覺得沒有問題;後來又直接使用mongodb-csharp進行頻繁串連關閉,結果還是出現了同樣的錯誤,於是我又懷疑是驅動本身的問題,但是看了看討論群組中似乎又沒有人彙報過這個問題;於是我又換了個思路,使用了Java平台上的驅動寫了個簡單的測試程式,居然還是得到了這個錯誤。由此我確定了兩點:

  • 這很可能不是mongodb-csharp這個驅動程式的問題。當然,要確定這一點還需要更多測試,例如在mono上使用這個驅動。
  • 這是作業系統方面的問題,因為.NET和Java都給出了同樣的錯誤資訊,甚至和當前程式的語言文化設定無關。

還有一個細節:在直接使用驅動進行插入操作的時候,發現無論使用多少線程同時進行,最終永遠是在插入了16370-16380條記錄之後停止,這意味著每次都是開啟關閉了確定次數之後出現的錯誤,這很有可能是一個作業系統限制所致的結果。因此,我使用這段錯誤資訊在網上尋找解決方案,原因有很多,大都不是我需要的。順便一提,只有中文的錯誤資訊真是很難找到合適的結果,因此我不得不通過幾個關鍵字,再連蒙帶猜地得到了錯誤的標準英文翻譯:

An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.

有了這段資訊,找起答案來就簡單多了,例如KB上找到了這樣一條記錄,說是在Windows Vista及2008中,Tcp/IP動態連接埠的範圍調整到49152至65535,做一個簡單的減法可以發現我們可以使用16384個介面,和我們之前看到的記錄數量大致相同,基本可以確定是頻繁地開啟關閉操作造成用戶端的動態連接埠用盡的問題。KB上也給出瞭解決方法,只要使用netsh命令便可以進行設定。

不過有意思的是,我在此之前還找到了另一條記錄,說是在HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters下面可以增加一個MaxUserPort參數,指定程式可以使用的連接埠範圍,它的預設值是5000,也就是連接埠範圍是1025至5000,這也是上一條記錄中說Windows之前的連接埠策略,它的“適用範圍”已經不包括2008系統,但我鬼使神差地將MaxUserPort設定為65534(十進位)之後,原本只能插入16000多條記錄的程式已經能夠插入數萬條,這意味著修改的確生效了。

當然,這麼做還是沒有解決問題,總不見得插入這麼多條記錄之後還是失敗吧。其實第二條記錄裡還寫到,有一個TcpTimedWaitDelay參數,表示一個關閉後的連接埠等待多久之後可以重新使用,順著這個資訊我找到了《TCP/IP Registry Values for Windows Server 2008》這樣一篇文章,描述Vista與2008系統中各種TCP/IP相關的參數,其中自然包括了TcpTimedWaitDelay,它的預設值為120,表示連接埠關閉後120秒才能重新使用。

於是我們來算一下,假設有60000個連接埠可用,如果在120秒內消耗完畢,則每秒最多使用500個連接埠,這遠遠低於MongoDB的效能瓶頸,甚至接近了一個Web應用程式的需求——根據壓力測試,我們單台Web伺服器每秒可以處理接近200個動態請求,這意味著平均每個請求只能使用2.5個串連。根據文檔,我將TcpTimedWaitDelay設成最短的30秒,這意味著我們可以每秒開啟關閉2000個連接埠,平均每個請求使用10個串連。夠了。

這個問題就這樣解決了,說實話很簡單,也就是個“知道就能解決”的配置問題。當然現在這個方式並不算太理想,更好的方式應該是利用串連池,這樣便不會開啟/關閉大量的TCP/IP串連,預設的連接埠數量也已經足夠了,更重要的是這也可以省下很大的開銷——因為經過測試,即使是最複雜的ASP.NET頁面,只要不涉及MongoDB,每秒也能處理6500多個請求,而目前每秒200個動態請求,從數字上看也遠低於MongoDB的能力,我們有理由相信目前的效能似乎是卡在串連的開啟/關閉上了。

只可惜目前mongodb-csharp的串連池實現有bug,用於清理串連的維護進程居然會讓造成明顯的中斷,甚至在頻繁使用十幾分鐘後還拋出了異常。有機會的話我再看看吧,但我總覺得它目前的實現過於複雜了,我估計都可以說是物件導向的“經典”使用案例了。

最後再來一提,話說我目前使用的是64位的Windows Web Server 2008 R2系統,功能強大,價格便宜,授權寬鬆,最多允許使用到32GB記憶體,作為Web伺服器我很滿意。

 

原文地址:http://blog.zhaojie.me/2010/08/lack-of-dynamic-ports-when-frequently-open-and-close-socket.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.