[英]HttpWebRequest is extremely slow!
我正在使用開源庫連接到我的網絡服務器。 我擔心網絡服務器運行速度非常慢,然后我嘗試在 Ruby 中做一個簡單的測試,我得到了這些結果
Ruby 程序:10 個 HTTP GET 需要 2.11 秒
Ruby 程序:18.13 秒用於 100 個 HTTP GET
C# 庫:10 個 HTTP GET 需要 20.81 秒
C# 庫:100 個 HTTP GET 需要 36847.46 秒
我已經分析並發現問題出在這個函數上:
private HttpWebResponse GetRawResponse(HttpWebRequest request) {
HttpWebResponse raw = null;
try {
raw = (HttpWebResponse)request.GetResponse(); //This line!
}
catch (WebException ex) {
if (ex.Response is HttpWebResponse) {
raw = ex.Response as HttpWebResponse;
}
}
return raw;
}
標記的行本身需要超過 1 秒才能完成,而發出 1 個請求的 ruby 程序需要 0.3 秒。 我也在 127.0.0.1 上做所有這些測試,所以網絡帶寬不是問題。
是什么導致了這種巨大的減速?
更新
查看更改后的基准測試結果。 我實際上用 10 個 GET 而不是 100 個進行了測試,我更新了結果。
我發現 Web 請求緩慢的罪魁禍首是代理屬性。 如果在調用 GetResponse 方法之前將此屬性設置為 null,則查詢將跳過代理自動檢測步驟:
request.Proxy = null;
using (var response = (HttpWebResponse)request.GetResponse())
{
}
在返回響應之前,代理自動檢測最多需要 7 秒進行查詢。 默認情況下為 HttpWebRequest 對象設置此屬性有點煩人。
這可能與您同時打開多個連接的事實有關。 默認情況下,最大打開 HTTP 連接數設置為兩個。 嘗試將其添加到您的 .config 文件中,看看它是否有幫助:
<system.net>
.......
<connectionManagement>
<add address="*" maxconnection="20"/>
</connectionManagement>
</system.net>
我在 VB.Net MVC 項目中遇到了類似的問題。
在我的電腦 (Windows 7) 本地,點擊頁面請求的時間不到 1 秒,但在服務器 (Windows Server 2008 R2) 上,每個頁面請求需要 20 多秒。
我嘗試了將代理設置為空的組合
System.Net.WebRequest.DefaultWebProxy = Nothing
request.Proxy = System.Net.WebRequest.DefaultWebProxy
並通過添加更改配置文件
<system.net>
.......
<connectionManagement>
<add address="*" maxconnection="20"/>
</connectionManagement>
</system.net>
這仍然沒有減少服務器上緩慢的頁面請求時間。 最后的解決方案是取消選中服務器本身 IE 選項中的“自動檢測設置”選項。 (在工具 -> Internet 選項下選擇連接選項卡。按 LAN 設置按鈕)
在我取消選中服務器上的此瀏覽器選項后,所有頁面請求時間立即從 20+ 秒下降到 1 秒以下。
我開始觀察到類似於該區域中的 OP 的減速,當增加 MaxConnections 時,速度會有所改善。
ServicePointManager.DefaultConnectionLimit = 4;
但是在構建了這個數量的 WebRequest 之后,延遲又回來了。
就我而言,問題在於我正在調用 POST 並且不關心響應,因此沒有接聽或對它做任何事情。 不幸的是,這讓 WebRequest 一直浮動,直到它們超時。
解決方法是拿起 Response 並關閉它。
WebRequest webRequest = WebRequest.Create(sURL);
webRequest.Method = "POST";
webRequest.ContentLength = byteDataGZ.Length;
webRequest.Proxy = null;
using (var requestStream = webRequest.GetRequestStream())
{
requestStream.WriteTimeout = 500;
requestStream.Write(byteDataGZ, 0, byteDataGZ.Length);
requestStream.Close();
}
// Get the response so that we don't leave this request hanging around
WebResponse response = webRequest.GetResponse();
response.Close();
使用localhost以外的計算機,然后使用WireShark查看網絡上真正發生了什么。
就像其他人所說的那樣,它可以是很多東西。 在 TCP 級別上查看事物應該會給出清晰的畫面。
我不知道我到底是如何達到這個解決方法的,我還沒有時間做一些研究,所以這取決於你們。 有一個參數,我像這樣使用它(在我的類的構造函數中,在實例化 HTTPWebRequest 對象之前):
System.Net.ServicePointManager.Expect100Continue = false;
我不知道究竟是為什么,但現在我的電話看起來更快了。
我知道這是一些舊線程,但是我因 HttpWebRequest 緩慢而迷失了一整天,嘗試了所有提供的解決方案,但都沒有運氣。 對任何地址的每次請求都超過一分鍾。
最終,問題出在我的防病毒防火牆 (Eset) 上。 我在交互模式下使用防火牆,但Eset 以某種方式完全關閉。 這導致請求永遠持續。 開啟 Eset並執行請求后,顯示提示防火牆消息,確認后,請求執行不到一秒。
對我來說,使用HttpWebRequest
在本地調用 API 平均需要 40 毫秒,在服務器上調用 API 平均需要 270 毫秒。 但是在兩種環境中通過 Postman 調用它們平均需要 40 毫秒。 該線程中的任何解決方案都沒有對我產生任何影響。
然后我發現這篇文章提到了 Nagle 算法:
Nagle 算法通過減少通過網絡發送的數據包數量來提高網絡效率。 當少量數據寫入網絡時,它通過在客戶端設置最多 200 毫秒的延遲來實現這一點。 延遲是可能寫入的其他數據的等待期。 新數據被添加到同一個數據包中。
將ServicePoint.UseNagleAlgorithm
設置為false
是我需要的魔法,它產生了巨大的差異,服務器上的性能現在幾乎與本地相同。
var webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ServicePoint.Expect100Continue = false;
webRequest.ServicePoint.UseNagleAlgorithm = false; // <<<this is the important bit
請注意,這對我來說適用於少量數據,但是如果您的請求涉及大量數據,那么根據請求的大小/響應的預期大小,可能值得將此標志設為條件。
我嘗試了這里描述的所有解決方案,但沒有成功,電話大約需要 5 分鍾。
問題是什么:我需要相同的會話和顯然相同的 cookie(在同一台服務器上發出的請求),所以我將 cookie 從 Request.Cookies 重新創建到 WebRequest.CookieContainer 。 響應時間約為 5 分鍾。
我的解決方法:注釋掉cookie相關的代碼,bam! 通話時間不到一秒鍾。
這對我有用:
<configuration>
<system.net>
<defaultProxy enabled="false"/>
</system.net>
</configuration>
對我來說,問題是我安裝了 LogMeIn Hamachi——具有諷刺意味的是遠程調試相同的程序,然后開始表現出這種極端緩慢。
僅供參考,禁用 Hamachi 網絡適配器是不夠的,因為它的 Windows 服務似乎重新啟用了適配器。
此外,重新連接到我的 Hamachi 網絡並沒有解決問題。 僅禁用適配器(通過禁用 LogMeIn Hamachi Windows 服務)或者,大概是卸載 Hamachi,為我解決了問題。
是否可以通過特定的網絡適配器要求HttpWebRequest
出去?
在我的情況下,將AspxAutoDetectCookieSupport=1
添加到代碼中,問題就解決了
Uri target = new Uri("http://payroll");
string responseContent;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(target);
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(new Cookie("AspxAutoDetectCookieSupport", "1") { Domain = target.Host });
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader sr = new StreamReader(responseStream))
responseContent = sr.ReadToEnd();
}
}
我們在工作中遇到了類似的問題,我們有兩個 REST API 在本地相互通信。 在我們的例子中,所有HttpWebRequest
花費了超過 2 秒的時間,即使請求 url 是http://localhost:5000/whatever
也很慢。
但是,在使用 Wireshark 調查此問題時,我們發現了這一點:
結果發現框架首先嘗試建立到本地主機的 IPv6 連接,但是由於我們的服務正在偵聽0.0.0.0
(IPv4) 連接嘗試失敗,並且在 500 毫秒超時后重試,直到嘗試失敗 4 次(4 * 500 毫秒) = 2 秒)它最終放棄並使用 IPv4 作為后備(顯然幾乎立即成功)。
我們的解決方案是將請求 URI 更改為http://127.0.0.1/5000/whatever
(或者還偵聽我們認為對於本地回調不必要的 IPv6)。
通過 httpwebrequest 創建到 api 的會話時,我遇到了 15 秒左右的延遲。 延遲是在等待 getrequeststream() 。 在尋找答案后,我找到了這篇文章,解決方案只是更改有關 ssl 的本地 Windows 策略:
https://www.generacodice.com/en/articolo/1296839/httpwebrequest-15-second-delay-performance-issue
我們在網絡應用程序上遇到了同樣的問題。 我們等待響應 5 秒。 當我們將 IIS 上的 applicationPool 上的用戶更改為 networkService 時,響應開始到達不到 1 秒
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.