.net を使用して約 10.000 の同時要求を実行したいHttpWebRequest
のですが、すべてが同じホストに送信されるわけではなく、プロキシのプールを経由するものもあります。
現在、最大 1000 の同時リクエスト (タスク マネージャーでは約 3% に相当) まで正常に動作するスレッドを使用していますが、2000 または 5000 の同時リクエストにスケールアップすると、多くの例外 (以下を参照) と 100% の CPU 負荷が発生します。
サーバーには多すぎると思ったのですが、たとえば 1000 の同時実行で 2 つのインスタンスを実行することもできるので、接続管理で何かを推測しています。
まず最初に: リクエストのサンプル コード (問題ないと思いますが、大規模になるまで問題なく動作します)
public string HttpGet(string url)
{
try {
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Timeout = 20000;
request.CookieContainer = Cookie;
request.AutomaticDecompression = DecompressionMethods.GZip;
request.KeepAlive = true;
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string tmp = reader.ReadToEnd();
reader.Close();
dataStream.Close();
response.Close();
return tmp;
} catch (Exception ex) {
return "";
}
}
そしてもちろん、私は(私だと思います) ServicePointManager も正しく設定しました:
ServicePointManager.DefaultConnectionLimit = 20 * 1000;
ServicePointManager.MaxServicePointIdleTime = 1000 * 60 * 20;//maybe this is an issue?
ServicePointManager.UseNagleAlgorithm = false;
ServicePointManager.Expect100Continue = false;
奇妙なことに、アプリケーションが接続の制限の半分を使用していない場合でも、タイムアウトが発生します(実際のタイムアウトはありません。DefaultConnectionLimit が低く、要求を並列にしようとしたときに発生するようなタイムアウトです)。
そこで、ConnectionGroupName を使用して、各スレッドに一意の接続を与えることにしました。
request.ConnectionGroupName = randomStringPerThreadBasis;
これにより、少なくとも開いている TCP 接続が増加したため、.NET を拡張しただけでなく、このhttp://kb.globalscape.com/KnowledgebaseArticle10438.aspxDefaultConnectionLimit
のようなウィンドウで使用可能な動的 TCP ポートも増加しました。アプリは非常に多くの接続を開くようになりましたが、これは必要ありませんが、CPU のフッテージが高く、タイムアウトすることはめったにありません (ただし、以前よりもはるかに優れているため、接続管理に何か問題があるのでしょうか?)。
完全を期すために:私は時々これらの例外も取得します(ただし、それほど頻繁ではありません):netsh int ipv4 set dynamicport tcp start=1025 num=50000
System.Net.WebException: The underlying connection was closed: A connection that was expected to be kept alive was closed by the server. ---> System.IO.IOException:Unable to read data from the transport connection : An existing connection was forcibly closed by the remote host. ---> A connection attempt failed because the connected party did not properly
respond after a period of time, or established connection failed because
connected host has failed to respond
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count)
at System.Net.Security._SslStream.StartFrameHeader(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security._SslStream.StartReading(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security._SslStream.ProcessRead(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.TlsStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.Connection.SyncRead(HttpWebRequest request, Boolean userRetrievedStream, Boolean probeRead)
at System.Net.HttpWebRequest.GetResponse()
だから私の質問は、どうすればこれを解決できますか? 私は間違っていましたか?回避策はありますか? 自分で接続を管理できますか? この場合にうまく機能する別のクラス/言語はありますか? 等