2008-12-04 23 views
10

Tôi đang viết một dịch vụ chỉ nhận cuộc gọi từ máy chủ cục bộ. Hiệu suất là quan trọng vì vậy tôi nghĩ rằng tôi muốn thử các NetNamedPipeBinding thay vì NetTcpBinding và xem Nếu tôi có thể thấy bất kỳ lợi ích hiệu suất đáng chú ý.Làm cách nào để tôi có thể đặt liên kết Ống có tên được kết nối lại tự động trong WCF

Nếu một khách hàng, sau khi thực hiện một hoặc nhiều yêu cầu đến máy chủ, không hoạt động trong một khoảng thời gian dài, yêu cầu tiếp theo sẽ thất bại có vẻ do một số thời gian chờ nhàn rỗi trong ràng buộc. Điều tương tự cũng xảy ra khi dịch vụ được khởi động lại.

Tôi cần khách hàng của mình có thể giữ kết nối mở miễn là được phép để tránh chi phí liên quan đến việc thiết lập kết nối mới. Tôi cũng cần có thể khởi động lại dịch vụ theo thời gian và yêu cầu khách hàng tự động thử lại nếu họ nhận thấy kết nối đã bị chấm dứt.

Tôi biết rằng điều này được thúc đẩy bởi các công cụ đáng tin cậy trong NetTcpBinding nhưng làm thế nào một trong những đi về việc cùng một mức độ kết nối lại độ tin cậy trong NetNamedPipeBinding? Thậm chí có thể không?

Câu hỏi có phần học thuật vì nó không phải là yêu cầu để sử dụng NetNamedPipes, tôi có thể dễ dàng áp dụng nó để sử dụng tcp-binding nhưng đó là một ngứa và tôi thực sự muốn làm xước nó.

+0

IIRC, tham số thứ hai cuối cùng của CreateNamedPipe (chức năng win32 không được quản lý bên dưới NamedPipeBinding - http://msdn.microsoft.com/en-us/library/windows/desktop/aa365150%28v=vs.85%29.aspx) hoạt động như một thời gian chờ kết nối máy khách, mà là khá ngắn .Điều này có thể có cái gì đó để làm với thời gian chờ bạn nhìn thấy khi máy chủ bắt đầu; có lẽ bạn có thể sử dụng phản xạ/dotpeek/trình gỡ lỗi để xem các thông số nào được truyền từ WCF sang hàm gốc và nếu các tham số đó có thể được thay đổi bằng cấu hình –

+0

Vì câu hỏi này mang tính học thuật, nói chung tôi sẽ tiếp tục theo cách này: xem các hàm gốc nào được gọi, với thời gian chờ nào, và sau đó theo dõi lại nơi các hàm này được gọi từ mã được quản lý, để xem nơi các tham số bắt nguồn. Long, nhưng vui vẻ và giúp bạn tìm ra cách nó thực sự hoạt động :) Tôi gỡ lỗi một vấn đề Sharepoint theo cách này ... –

Trả lời

17

Tôi chưa sử dụng NetNamedPipes trong WCF nhưng tôi đã dành nhiều thời gian hơn tôi quan tâm để tìm hiểu các giá trị thời gian chờ cho NetTcp. Tôi sử dụng các cấu hình sau đây cho NetTcpBindings của mình và có may mắn khi kết nối vẫn hoạt động.

Server:

<binding name="MyBindingName" sendTimeout="00:00:30" receiveTimeout="infinite"> 
    <reliableSession enabled="true" inactivityTimeout="00:05:00" ordered="true" /> 
    <security mode="None" /> 
</binding> 

Chủ đầu tư:

<binding name="MyBindingName" closeTimeout="00:00:30" openTimeout="00:00:30" receiveTimeout="infinite" sendTimeout="00:00:30"> 
    <reliableSession enabled="true" inactivityTimeout="00:01:00" ordered="true" /> 
    <security mode="None" /> 
</binding> 

Các thiết lập quan trọng mà tôi dành nhiều thời gian nhất trên là sendTimeout và receiveTimeout. Nếu receiveTimeout của bạn giống hoặc ít hơn gửi của bạn, kênh sẽ giảm sau khi hết thời gian chờ đó. Nếu nhận được cao hơn và gửi là trên một ngưỡng, kênh sẽ cháy một mức độ vận chuyển keepalive. Từ các thử nghiệm của tôi, ngưỡng sendTimeout là 30 giây. Bất cứ điều gì ít hơn đó và các keepalives không được gửi đi.

Ngoài ra, tôi có cuộc gọi theo chu kỳ dựa trên hẹn giờ mà tôi thực hiện từng phút để thử và đảm bảo kênh hoạt động tốt. Cuộc gọi chỉ đơn giản là cho một thành viên trở boolean:

[OperationContract(IsOneWay = false, IsInitiating = false, IsTerminating = false)] 
bool KeepAlive(); 

public bool KeepAlive() 
{ 
    return true; 
} 

Bạn cũng có thể lấy các sự kiện kênh (nếu bạn nhận được chúng vào đúng thời điểm) và mở lại kết nối nếu có điều gì xấu xảy ra:

InstanceContext site = new InstanceContext(this); 
_proxy = new MyServiceChannel(site); 
if (_proxy != null) 
{ 
    if (_proxy.Login()) 
    { 
     //Login was successful 
     //Add channel event handlers so we can determine if something goes wrong 
     foreach (IChannel a in site.OutgoingChannels) 
     { 
      a.Opened += Channel_Opened; 
      a.Faulted += Channel_Faulted; 
      a.Closing += Channel_Closing; 
      a.Closed += Channel_Closed; 
     } 
    } 
} 

Tôi hy vọng một số dịch này và có giá trị cho bạn với NetNamedPipes.

Edit: Các tuỳ chọn khác để chụp máy chủ khởi động lại vấn đề

Khi máy chủ khởi động lại nó sẽ khiến kênh của khách hàng hoặc là gần hoặc lỗi. Việc nắm bắt các sự kiện đó ở phía máy khách sẽ cung cấp cho bạn tùy chọn sử dụng bộ hẹn giờ kết nối lại cho đến khi dịch vụ có sẵn một lần nữa.

private void Channel_Faulted(object sender, EventArgs e) 
{ 
    IChannel channel = sender as IChannel; 
    if (channel != null) 
    { 
     channel.Abort(); 
     channel.Close(); 
    } 

    //Disable the keep alive timer now that the channel is faulted 
    _keepAliveTimer.Stop(); 

    //The proxy channel should no longer be used 
    AbortProxy(); 

    //Enable the try again timer and attempt to reconnect 
    _reconnectTimer.Start(); 
} 

private void _reconnectTimer_Tick(object sender, System.EventArgs e) 
{ 
    if (_proxy == null) 
    { 
     InstanceContext site = new InstanceContext(this); 
     _proxy = new StateManagerClient(site); 
    } 
    if (_proxy != null) 
    { 
     if (_proxy.Login()) 
     { 
      //The connection is back up 
      _reconnectTimer.Stop(); 
      _keepAliveTimer.Start(); 
     } 
     else 
     { 
      //The channel has likely faulted and the proxy should be destroyed 
      AbortProxy(); 
     } 
    } 
} 

public void AbortProxy() 
{ 
    if (_proxy != null) 
    { 
     _proxy.Abort(); 
     _proxy.Close(); 
     _proxy = null; 
    } 
} 

Bạn muốn đảm bảo các lần đăng nhập của bộ hẹn giờ kết nối lại được thực hiện trên chuỗi nền không đồng bộ để chúng không treo giao diện người dùng mỗi khi họ cố đăng nhập. YMMV

+0

Cảm ơn Chris nhưng sửa đổi thời gian chờ và thêm một phương pháp keepalive tiếc là sẽ chỉ giải quyết đầu tiên của hai vấn đề của tôi. Tôi vẫn còn có cùng một vấn đề khi dịch vụ được khởi động lại. –

+0

làm thế nào để bạn thiết lập ràng buộc/đáng tin cậySession lập trình? –

14

Tôi đã xem xét vấn đề kết nối TCP bị ngắt trong hai ngày và đến kết luận rằng nhiều người đang thiếu điểm tàn bạo khi thiết lập kết nối trong WCF. Những gì mọi người dường như đang làm là tạo một kênh một lần và sau đó cố gắng giữ nó trong suốt vòng đời của ứng dụng, chơi tất cả các thủ thuật bẩn để giữ cho phiên TCP tồn tại. Đây không phải là ý nghĩa của nó.

Bạn nên tạo kênh, thực hiện một kênh (hoặc một số sau ngay sau lần đầu tiên) cuộc gọi trên dịch vụ của bạn, sau đó đóng và hủy kênh. Điều này sẽ cung cấp cho bạn (hầu như) hoạt động phi trạng thái và bạn không phải bận tâm với việc giữ các phiên còn sống, mà bạn không nên muốn ở nơi đầu tiên.

Bạn sẽ thấy rằng chi phí tạo và đóng kênh (từ ChannelFactory được sử dụng lại) không đáng kể, chỉ mất vài chục nano giây trên một máy điển hình.

Thuộc tính receiveTimeout mà mọi người đang tăng tốc xác định thời gian kênh có thể ở chế độ chờ trước khi nó tự động bị xóa, cho bạn biết kênh không được giữ mở trong thời gian rất dài (mặc định là 1 phút). Nếu bạn đặt receiveTimeout thành TimeSpan.MaxValue, nó sẽ giữ cho kênh của bạn mở ra lâu hơn nhưng đây không phải là những gì nó cho hay những gì bạn muốn trong một kịch bản thực tế.

Điều cuối cùng đã cho tôi đi đúng hướng là http://msdn.microsoft.com/en-us/library/ms734681.aspx cung cấp một ví dụ khủng khiếp nhưng chưa cho thấy cách người dùng nên sử dụng ChannelFactory. Người trả lời chỉ ra các lỗi và thiết lập hồ sơ thẳng để tất cả trong tất cả các bạn có thể nhận được tất cả mọi thứ bạn cần ở đây.

Và sau đó, tất cả các vấn đề của tôi đã kết thúc. Không còn "Một hoạt động đã được thử trên một cái gì đó mà không phải là một ổ cắm" và không còn nữa "Một kết nối hiện tại đã bị buộc phải đóng bởi máy chủ từ xa".

+0

http://social.msdn.microsoft.com/forums/en-US/wcf/thread/d5ab7e93-ff03-4d4f-badc-91423236e49b - Dave Cliffe (MSFT) cho rằng đây là một hoạt động khá tốn kém và các kênh đó nên được tái sử dụng nếu có thể –

+0

@Martin: "chi phí tạo và đóng kênh ... không đáng kể". Điều đó không phụ thuộc vào những thứ như đàm phán an ninh? Tôi tưởng tượng việc tái đàm phán bằng một thứ gì đó giống như một máy chủ AD là không đáng kể. – Xiaofu

+0

@romkyns: Có một blog MSDN tốt về các cải thiện hiệu suất cho ClientBase đi kèm với .NET 3.5 tại đây: http://blogs.msdn.com/wenlong/archive/2007/10/27/performance-improvement-of-wcf -client-proxy-creation-and-best-practices.aspx – Xiaofu

19

Trải nghiệm của tôi là khi sử dụng NetNamedPipes, "ReceiveTimout" trên các chức năng liên kết như "Thời gian chờ không hoạt động" thay vì thời gian chờ nhận. Lưu ý rằng điều này khác với cách NetTCPBinding hoạt động. Với TCP, nó thực sự là một thời gian chờ nhận và có một thời gian chờ không hoạt động riêng biệt mà bạn có thể cấu hình thông qua tin nhắn đáng tin cậy. (Nó cũng có vẻ trái ngược với tài liệu SDK, nhưng tốt thôi).

Để khắc phục điều này, hãy đặt RecieveTimout thành thứ gì đó lớn khi bạn tạo liên kết.
Ví dụ, nếu bạn đang tạo ràng buộc của bạn procedurally ...

NetNamedPipeBinding myBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); 
myBinding.ReceiveTimeout = TimeSpan.MaxValue; 

Hoặc, nếu bạn quan tâm đến việc tạo ra ràng buộc bạn khai báo ...

<netNamedPipeBinding> 
    <binding name="myBinding" receiveTimeout="infinite"> 
    </binding> 
</netNamedPipeBinding> 
+0

Cảm ơn lời khuyên đó. Tôi đã đặt thời gian chờ (nhận) thành 20:00 (20 phút) và không có hoạt động nào của tôi mất hơn 2 phút ... thậm chí có thể dài hơn 5 giây và điều đó đã diễn ra. Mọi người cũng nên nhìn vào "tính năng" microsoft này với tuyên bố sử dụng mà cũng nhận được tôi. https://stackoverflow.com/questions/573872/what-is-the-best-workaround-for-the-wcf-client-using-block-issue – granadaCoder

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