Mamy C# serwis internetowy i klienta, oba utworzone w Visual Studio 2008 (nowy projekt -> usługa sieci Web ASP.Net). Usługa jest hostowana na serwerze Windows 2012 R2, IIS 8.5.Niewystarczające zasoby winsock
Kiedy klient wysyła dane do naszej usługi, przekazujemy je do usługi zewnętrznej, zapisujemy wynik w bazie danych i zwracamy do klienta.
Problem polega na tym, że w niektórych rzadkich przypadkach, gdy nasza usługa jest obciążona dużym obciążeniem (wiele żądań na sekundę), rozpoczyna się wyrzucanie "Niewystarczających zasobów systemu winsock dostępnych do zakończenia inicjowania połączenia z gniazdem".
Okazało się, że nasz serwis internetowy otwiera wiele połączeń TCP z usługami innych firm i pozostawia je w stanie TIME_WAIT. Kiedy liczba takich połączeń osiąga dużą liczbę (około 17000), cały serwer traci możliwość tworzenia nowych połączeń. Wszystko od zdalnego pulpitu do przeglądarki internetowej przestaje działać. Trwa to kilka minut, a następnie, gdy Windows rozpoczyna zamykanie tych połączeń, wznawia normalnie.
W celu komunikacji z usługą innej firmy nasza usługa wykorzystuje tylko jedną instancję SoapClient przez cały czas jej użytkowania. Jest tworzony podczas inicjalizacji i nigdy nie jest zamknięty ani niszczony; nowe instancje nigdy nie są tworzone.
BLIND.BLINDSoapClient client = new BLIND.BLINDSoapClient(base.binding, base.address);
Wysyłając dane do usługi 3rd party po prostu wywołać jego metodę WWW i pozostawić ją tak bez zamykania, usuwania lub wykonując dowolną clean-up:
BLIND.Answer answer = client.Search(...);
..save to database
return answer;
Czy coś nam może zrobić, aby uniknąć gromadzenia się połączeń time_wait?
Czy istnieje lepszy sposób zarządzania SoapClient (s)? Czy powinniśmy otworzyć nowego klienta mydła dla każdego żądania i zamknąć je ręcznie?
Jeśli jest to istotne, tutaj jest jak nasz wiążący jest skonfigurowana:
binding = new BasicHttpBinding();
binding.Name = "SLTDSoap";
binding.CloseTimeout = TimeSpan.FromSeconds(Timeout);
binding.OpenTimeout = TimeSpan.FromSeconds(Timeout);
binding.ReceiveTimeout = TimeSpan.FromSeconds(Timeout);
binding.SendTimeout = TimeSpan.FromSeconds(Timeout);
binding.AllowCookies = false;
binding.BypassProxyOnLocal = false;
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.MaxBufferSize = 65536;
binding.MaxBufferPoolSize = 524288;
binding.MessageEncoding = WSMessageEncoding.Text;
binding.TextEncoding = System.Text.Encoding.UTF8;
binding.TransferMode = TransferMode.Buffered;
binding.UseDefaultWebProxy = true;
binding.ReaderQuotas.MaxDepth = 32;
binding.ReaderQuotas.MaxStringContentLength = 8192;
binding.ReaderQuotas.MaxArrayLength = 16384;
binding.ReaderQuotas.MaxBytesPerRead = 4096;
binding.ReaderQuotas.MaxNameTableCharCount = 16384;
binding.Security.Mode = (_url.StartsWith("https:")) ? BasicHttpSecurityMode.Transport : BasicHttpSecurityMode.None;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
binding.Security.Transport.Realm = "";
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
binding.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Default;
System.Net.ServicePointManager.DefaultConnectionLimit = 500;
Dziękujemy!
Jest to klasa stworzona przez studio graficzne po dodaniu odwołania do usługi internetowej innej firmy. Kliknięcie prawym przyciskiem myszy Odsyłacze do usług -> Dodaj odwołanie do usługi – dbrckovi