2014-06-12 18 views
5

Chúng tôi có dịch vụ web và khách hàng C#, cả hai được tạo trong Visual Studio 2008 (dự án mới -> ứng dụng dịch vụ web ASP.Net). Dịch vụ được lưu trữ trên máy chủ Windows 2012 R2, IIS 8.5.Không đủ tài nguyên winsock

Khi khách hàng gửi dữ liệu đến dịch vụ của chúng tôi, chúng tôi chuyển tiếp nó đến dịch vụ của bên thứ ba, lưu kết quả vào cơ sở dữ liệu và gửi lại cho khách hàng.

Vấn đề là, trong một số trường hợp hiếm hoi, khi dịch vụ của chúng tôi chịu tải nặng (nhiều yêu cầu mỗi giây), nó bắt đầu ném 'Không đủ tài nguyên chiến thắng để hoàn thành việc khởi tạo kết nối socket'.

Chúng tôi thấy rằng dịch vụ web của chúng tôi đang mở nhiều kết nối TCP cho các dịch vụ của bên thứ ba và để chúng ở trạng thái TIME_WAIT. Khi số lượng kết nối như vậy đạt đến số lượng cao (khoảng 17000), toàn bộ máy chủ sẽ mất khả năng thực hiện bất kỳ kết nối mới nào. Mọi thứ từ máy tính từ xa đến trình duyệt internet đều ngừng hoạt động. Điều này kéo dài trong một vài phút, và sau đó, khi Windows bắt đầu đóng các kết nối đó, nó sẽ tiếp tục bình thường.

Để liên lạc với dịch vụ bên thứ 3, dịch vụ của chúng tôi chỉ sử dụng một phiên bản SoapClient trong toàn bộ thời gian sử dụng của nó. Nó được tạo ra khi khởi tạo và không bao giờ bị đóng hoặc bị phá hủy; các phiên bản mới không bao giờ được tạo.

BLIND.BLINDSoapClient client = new BLIND.BLINDSoapClient(base.binding, base.address); 

Khi gửi dữ liệu đến các dịch vụ bên thứ 3 chúng tôi chỉ đơn giản là gọi phương thức web của mình, và để lại nó như thế mà không đóng, xử lý hoặc làm bất kỳ dọn dẹp:

BLIND.Answer answer = client.Search(...); 
..save to database 
return answer; 

Có bất cứ điều gì chúng tôi có thể làm gì để tránh việc xây dựng các kết nối time_wait này?

Có cách nào tốt hơn để quản lý SoapClient (s)? Chúng ta có nên mở một ứng dụng xà phòng mới cho mọi yêu cầu và đóng chúng theo cách thủ công không?

Nếu đó là có liên quan, đây là cách ràng buộc của chúng tôi được thiết lập:

 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; 

Cảm ơn bạn!

+0

Đây là lớp được tạo bởi studio trực quan khi chúng tôi thêm tham chiếu vào dịch vụ web của bên thứ ba. Nhấp chuột phải Tham khảo dịch vụ -> Thêm tham chiếu dịch vụ – dbrckovi

Trả lời

4

Tôi nghĩ rằng chúng tôi có thể đã giải quyết được vấn đề 'tài nguyên winsock không đủ'.

Chúng tôi đã thiết lập các giá trị registry sau đây: HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ Tcpip \ Parameters \ MaxUserPort = 60000 HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ Tcpip \ Parameters \ TcpTimedWaitDelay = 30

tối đa của chúng tôi dự kiến ​​tải về môi trường sản xuất tại thời điểm peek là 150 yêu cầu mỗi giây. Điều này có nghĩa là chúng tôi sẽ tạo 4500 kết nối trong 30 giây, trước khi các cửa sổ bắt đầu phát hành chúng. Đây là dưới 60000, và nên đảm bảo vấn đề này không xảy ra một lần nữa.

Chúng tôi đã để hệ thống chạy ở 150 yêu cầu mỗi giây với các cài đặt này trong 3 ngày và sự cố không xảy ra.

0

Theo lời khen của bạn BLIND.BLINDSoapClient được thừa kế từ System.ServiceModel.ClientBase. Lớp này là IDisposable có nghĩa là bạn nên luôn luôn vứt bỏ nó khi bạn đang thực hiện với nó (trên nền nó gọi để đóng - mà đóng đối tượng truyền thông trong nền).

tức là .:

using(var client = new BLIND.BLINDSoapClient(base.binding, base.address)) { 
    // enjoy client 
} 

Có cuối cùng có thể có một số giới hạn có thể mất máy chủ của bạn xuống. Bạn có thể:

  1. Set giới hạn về số lượng yêu cầu cho phép trang web của bạn/webservice trên IIS - xem http://www.iis.net/configreference/system.applicationhost/sites/sitedefaults/limits, dưới tải nặng bạn gọi đến webservice sẽ sau đó thỉnh thoảng thất bại - nhưng đứng về phía khách hàng
  2. Di chuyển webservice của bạn từ một giải pháp hộp cho giải pháp trang trại (một hộp hoạt động như cân bằng tải mà đại biểu yêu cầu nhiều hộp dựa trên tải hiện tại của họ)
  3. Di chuyển dịch vụ web của bạn sang đám mây - như Amazon hoặc Azure (giống như 2., chỉ bạn không cần phải quan tâm đến cân bằng tải)
+0

Chúng tôi không thể xử lý BLIND.BLINDSoapClient vì chúng tôi đang sử dụng cùng một đối tượng cho tất cả các liên lạc với dịch vụ bên thứ 3. Nếu tôi vứt bỏ nó, yêu cầu tiếp theo sẽ thất bại vì khách hàng sẽ bị đóng. Trong trường hợp này, chúng ta sẽ phải tạo một cá thể mới của lớp này cho mọi yêu cầu. Đây có phải là một thực hành tốt hơn? – dbrckovi

+0

Là một lưu ý phụ, chúng tôi đang có kế hoạch di chuyển dịch vụ tới một đám mây tại một số điểm, nhưng ưu tiên của chúng tôi bây giờ là loại bỏ tất cả các vấn đề có thể do thiết kế xấu gây ra. – dbrckovi

+0

@ user3733031 - thực hành tốt hơn là tạo cá thể mới khi bạn cần và xử lý nó khi bạn đã hoàn thành nó. Nếu không, kết nối vẫn mở cho toàn bộ thời gian yêu cầu web thay vì chỉ mở khi bạn cần. –

Các vấn đề liên quan