65.9K
CodeProject 正在变化。 阅读更多。
Home

WCF 可靠会话绑定: 服务端和客户端的 receiveTimeout 和 inactivityTimeout

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.65/5 (11投票s)

2014年3月25日

CPOL

6分钟阅读

viewsIcon

61574

对服务器和客户端的非活动和接收超时相关的可靠会话进行分析。

引言

WCF 提供了许多可用于调整应用程序行为、可伸缩性和可用性的配置选项。此外,大多数这些设置都可以通过客户端和服务器的配置文件进行配置。虽然这使得框架具有高度的可配置性,但弄清楚各种超时是如何工作的可能具有挑战性。

在这里,我将重点介绍两个更常用的超时设置,并解释当它们通过支持可靠会话的绑定(例如 netTcpBinding)使用时,它们如何影响 WCF 客户端和服务行为。这两个超时都可以通过客户端和服务器的配置文件或以编程方式进行配置。我将仅展示配置文件实现,因为我认为在大多数情况下,使用配置文件是更好的选择,因为它将应用程序管理与开发解耦。如果您不熟悉可靠会话,请参阅 MSDN 文档以熟悉该主题,因为本文假定您具备基本的 WS-可靠会话理解。

背景

可靠会话为客户端和服务器之间的 WCF 通信提供消息级别的保证——或者更准确地说,在消息传递失败时报告失败的保证。这是通过在客户端和服务器之间共享的每条消息使用传输级别的确认 (ACK) 序列来实现的。每个已建立的可靠会话的生命周期都由客户端和服务器绑定中的 inactivityTimeoutreceiveTimeout 属性的组合决定。当一个会话过期时,在客户端和服务器之间的后续消息启动时会建立一个新的会话。了解如何通过超时控制会话的生命周期非常重要,因为建立新会话会产生基础结构开销,这会影响应用程序的可伸缩性和可用性。

在我们继续之前,让我们定义两个在讨论超时时将使用的关键术语

  • 基础结构级别消息 (ILM):这些是客户端和服务器通信堆栈之间交换的通道级别消息。它们本质上是纯粹的基础结构消息;此类消息的示例包括 ACK 和 K-A(保持活动)。它们没有任何与应用程序级别相关的开销,例如 SOAP 标头等。
  • 应用程序级别消息 (ALM):这些是 WCF SOAP 消息,根据数据和操作合同在客户端和服务器之间交换。当 ALM 在可靠会话中与服务器和客户端共享时,还会生成 ILM 来确认消息的接收。

不深入细节,只需说明典型的 WCF 客户端实现应始终缓存通道工厂以生成客户端服务代理。当代理使用 svcutil 生成或使用 ClientBase<T> 实现创建时,WCF 会在内部缓存通道工厂。这样做是一种最佳实践,并具有许多优点,包括支持连接池(本文不讨论)。

可靠会话:非活动和接收超时

一旦在客户端和服务器之间建立可靠会话,只要 receiveTimeoutinactivityTimeout 都没有过期,会话就会保持活动状态。如果其中任何一个过期,可靠会话将被断开,WCF 基础结构将生成通信故障,告知客户端相同信息。客户端可以适当地处理此故障。

表 1 是 inactivityTimeoutreceiveTimeout 适用于 WCF 客户端和服务器行为的矩阵。

让我们通过一个例子来进一步阐述这些设置。以下是示例服务器和客户端配置。

关于配置的一些快速说明

  1. 我在上面的示例中使用了 customBinding,但对于任何其他支持可靠会话的绑定,可靠会话的节流工作方式相同。
  2. 我没有展示可靠会话或自定义绑定提供的所有配置元素,而是专注于本文解释的两个超时。
  3. 在 MSDN 帮助页面上可以找到对可靠会话元素和支持可靠会话的绑定的全面解释。

服务绑定配置

   <customBinding>
    <binding name="reliableCustomBinding"
                 openTimeout="00:00:30"
                 closeTimeout="00:00:30"
                 sendTimeout="00:05:00"
                 receiveTimeout="00:20:00">
          <reliableSession acknowledgementInterval="00:00:0.2"
                           inactivityTimeout="00:10:00"/>
          <binaryMessageEncoding>
            <readerQuotas
              maxArrayLength="500000"
              maxBytesPerRead="65536"
              maxDepth="16384"
              maxNameTableCharCount="500000"
              maxStringContentLength="500000" />
          </binaryMessageEncoding>
          <tcpTransport portSharingEnabled="false"
                        maxBufferPoolSize="32768000"
                        maxBufferSize="524288"
                        maxReceivedMessageSize="524288">
          </tcpTransport>
        </binding>
   </customBinding>

让我们进一步探讨服务器配置示例

  • 接收超时设置为 20 分钟。这表明,如果自 RS 通道建立以来,在 20 分钟内客户端和服务之间没有交换应用程序消息,则该通道将被服务器拆除,并会引发通信故障。如果在可靠会话配置元素中未指定 receiveTimeout,则默认值为 10 分钟(请务必查阅 MSDN 以获取您正在定位的特定 .NET 框架的默认值,因为 Microsoft 可能会在未来的 .NET 版本中更改它们)。
  • 非活动超时设置为 10 分钟。这表明,如果在已建立的 RS 通道上 10 分钟内未收到任何基础结构级别消息(ACK 或 K-A),则该通道将被拆除,并会引发通信故障。如果未指定 inactivityTimeout,则默认值为 10 分钟(与我们在本示例中配置的相同)。
请注意,如果服务器上的任何一个超时过期,则可靠会话通道将发生故障,并通过通信故障通知客户端。

客户端绑定配置

   <customBinding>
    <binding name="reliableCustomBinding"
                 openTimeout="00:00:10"
                 closeTimeout="00:00:10"
                 sendTimeout="00:05:00">
          <reliableSession acknowledgementInterval="00:00:0.2"
                           inactivityTimeout="00:01:00"/>
          <binaryMessageEncoding>
            <readerQuotas
              maxArrayLength="500000"
              maxBytesPerRead="65536"
              maxDepth="16384"
              maxNameTableCharCount="500000"
              maxStringContentLength="500000" />
          <tcpTransport maxBufferPoolSize="1966080"
                        maxBufferSize="524288"
                        maxReceivedMessageSize="524288">
          </tcpTransport>
        </binding>
   </customBinding>

现在,让我们看一下客户端配置

  • 接收超时不适用于客户端。
  • 非活动超时设置为 1 分钟。在客户端,非活动超时用于定期生成 ILM,以防止通道因服务器的 inactivityTimeout 设置而发生故障。WCF 使用非活动超时设置的一半来生成 ILM。在这种情况下,每 30 秒将在已建立的 RS 通道上从客户端生成一个 ILM,这将重置服务器端的 inactivityTimeout 计时器(在本例中设置为 10 分钟)。

WCF 跟踪

您可以通过 WCF 跟踪捕获传输级别消息,以查看由于客户端 inactivityTimeout 设置而在客户端和服务器之间生成的 ILM 消息。这些消息将类似于下面的示例日志,这些日志是使用本文中的客户端和服务配置生成的。

请注意,ILM 每 30 秒生成一次,并且将继续生成,直到服务器 receiveTimeout 因没有 ALM(20 分钟)而过期,因为服务器 inactivityTimeout 已被客户端 inactivityTimeout 配置满足。

分析

此时,您可能想知道两个会使同一通道发生故障的超时值的作用;以及设置一个超时大于或小于另一个超时的意义是什么?根据我的经验,原因如下:

  • 根据我的经验,当客户端有兴趣在一定时间内知道服务是否不可用时,客户端的 inactivityTimeout 非常有用。这可以通过使用客户端的非活动超时并处理通信故障来实现。
  • 服务器端的 receiveTimeout 在配置服务以实现可伸缩性/可用性方面很重要,以便在客户端-服务器之间没有交换应用程序级别消息的最优时间过去后,应用程序资源可以被回收。
  • 服务器端的 inactivityTimeout 可用于拆除和回收与处于特定非活动状态的客户端的连接,这些非活动状态被认为是最优的,具体取决于网络约束。这可以提供一种比应用程序级别的 receiveTimeout 阈值更快地释放资源的方式。
  • 这两个超时有略微不同的受众——receiveTimeout 是应用程序开发人员应该理解和关心的;inactivityTimeout 是部署方面的考虑因素,应用程序管理员应该熟悉它。

结论

总而言之,在使用 RS 通道时:

  • 将服务器 receiveTimeout 设置为您愿意接受客户端在不交换 ALM 的情况下保持连接的时长。在应用程序和服务资源(可能已绑定到您的客户端,特别是当您的服务是按调用实例化的)之间进行权衡。
  • 同时,服务器 inactivityTimeout 应设置为您愿意接受客户端在不交换 ILM 的情况下保持连接的时长。这应该与网络资源的可用性和您服务的基础设施进行权衡。
  • 将客户端 inactivityTimeout 设置为生成 ILM,以使空闲的 RS 通道保持活动状态,直到由于没有 ALM 而导致接收超时过期。
  • 请订阅通信故障,以了解 RS 通道何时发生故障。
我希望这能为您提供对这两个超时设置的良好概述以及如何有效使用它们的一些想法。

历史

  • 2014 年 3 月 23 日:初稿
© . All rights reserved.