【问题标题】:How to troubleshoot MaxConcurrentSessions exceeded in IIS hosted WCF Service如何对 IIS 托管的 WCF 服务中超出的 MaxConcurrentSessions 进行故障排除
【发布时间】:2019-06-05 17:38:04
【问题描述】:

我已经走出了自己的舒适区,所以请耐心等待我提供相关信息。我们刚刚将 IIS 托管的 WCF 服务移至新服务器,调用此服务的客户端开始遇到超时。回收应用程序池后大约 10 分钟就可以了,然后一切都开始超时。我们启用了 WCF 跟踪,我可以看到它说 MaxConcurrentSessions 已超出。文档说该值默认为 2 x [处理器数],因此对我们来说应该是 200。

服务器位于负载平衡器后面,但目前是唯一的服务器。我们注意到性能监视器中的连接以每秒 6 次左右的速度挂起,但在发生超时时会上升到 30 左右,并从那里继续上升。

客户端正在使用wsHttpBinding TransportWithMessageCredential 安全性进行连接。该服务使用配置为用于服务器绑定行为的自定义UserNamePasswordValidator 中的 asp.net 成员资格提供程序来验证消息中提供的凭据。客户端未在其绑定上启用reliableSession。该服务使用默认的SessionModeInstanceContextMode,我认为它们分别是AllowedPerSession?我们不会在服务代理上调用Close,因为在过去的调查中,我发现这只会在选项上设置一个标志,防止它被重复使用,而且我们的总是超出范围......但现在正在进行测试看看这是否会关闭连接。

如果我正确地解释了 WCF 跟踪日志(而且我不理解我在那里阅读的大部分内容),我们似乎每分钟处理大约 30-40 条消息,并且每个请求在更少的时间内完成少于 300 毫秒(通常要少得多,在极少数情况下接近 1 秒。)我通过计算 1 分钟内的 Processing message n 消息来确定消息的数量。因此,如果我们每分钟获得 40 个,并且这些连接/会话需要 100 秒才能超时和关闭,那么在第一个开始超时之前,我们仍然只能同时打开大约 68 个。没有接近200的限制。单个客户端请求的连接是否获得多个会话?

奇怪的是我们之前没有任何超时并将服务和 web.config 直接复制到新服务器。我相信服务器和 IIS 版本已升级(服务器 2016、IIS 10。)请您帮我识别并提供相关信息以追踪导致这些超时的问题吗?

编辑
根据我的阅读,一切似乎都表明客户端必须调用Close,否则服务器将保持连接打开,直到超时。但是,在我们的测试中,我们看到 perf 中创建了一个连接。星期一。但无论如何在调用Close 后它仍然保持打开状态。所以我无法确定是否需要关闭是谣言,或者我们是否误解了我们的监控。真正的测试是在任何地方调用Close,看看它是否消除了我们的超时。

在将MaxConcurrentSessions 增加到 400 后,在性能监视器中,我们看到并发会话和实例的数量以每秒大约 1 的速度稳步上升,达到大约 225,最终趋于平稳并徘徊在那里。所以看起来会话没有被关闭。

【问题讨论】:

  • 您是否将应用程序池的高级设置与旧服务器进行了比较?
  • 是的,没有发现任何差异。

标签: c# wcf iis


【解决方案1】:

好吧,我们想通了。没有任何东西弹出并告诉我们问题出在哪里,这需要大量的头脑风暴,但我们做了以下事情:

  1. 启用 WCF 跟踪。通过痕迹,能够理解到基本可以看出交通并没有异常。所有事件似乎都是针对预期数量和类型的服务调用。在svctraceviewer 中查看,这似乎不是 DOS 攻击或类似的攻击。我们只是使用了该链接中的默认配置,但如果您知道那是什么,它看起来可以非常定制以提供您所追求的特定信息。

  2. 在这种情况下真正有帮助的是找到WCF Performance Counters。最初,我们使用 ASP.NET 性能计数器来查看打开的会话,这不是正确的指标。 This codeproject guide 帮助我们启用了 WCF 性能计数器,让我们能够实时了解会话数量和限制。

  3. 它还有助于复习 WCF 会话和实例之间的关系以及安全上下文的创建:

我们能够看到正在使用的最大 WCF 会话的百分比,并观察到它越来越高地接近默认限制 200(每个处理器 100 个),但最终稳定在 150 到 200 之间。在给定时间存在的会话数远远多于我们 WCF 跟踪中看到的每分钟平均请求数,这表明会话正在关闭,但似乎在超时之前保持打开状态,而不是在服务器完成请求后立即关闭。

在 Stack Overflow 上的某个地方,我一直无法找到,我曾经询问过 [ClientBase<TChannel>.Close][4] 方法(又名 WCF 服务代理的 close 方法)的用途,结果有点不正确,得出的结论是它所做的只是在代理对象上设置一个标志,将其标记为关闭,使其无法再次使用。文档对该方法的描述似乎与此一致:

使ClientBase<TChannel> 对象从其当前的 状态进入关闭状态。

好吧,在我调用Close 的时候,我的引用总是超出范围,允许垃圾收集来清理它,所以这似乎毫无意义。但我认为一个关键因素是关于无状态的 basicHttpBindings。在这种情况下,我们使用的是有状态的 wsHttpBindings,这意味着服务器在完成请求后离开保持会话并保持连接打开,以便可以在同一连接上进行来自客户端的后续调用。因此,尽管我在源代码中找不到任何文档或追踪它发生的位置,但似乎 WCF 客户端必须在他们发出最后一个请求后在其服务代理上调用 Close,以便告诉服务器它可以关闭连接并释放该会话槽。我没有机会在调用Close 时查找发送到服务器的消息来执行此操作,但我们能够使用性能计数器观察到会话数从 1 下降到 0 之前它会在我们的客户调用服务后保持为 1。

但我们说的是,我们可能无法控制的 WCF 客户端可能会损害服务器性能,并且如果他们不勤奋地编写代码并记得调用 Close 和服务器无法控制自己的性能??这听起来像是灾难的秘诀。好吧,您可以在服务器上做两件事来缓解这种情况。首先,您可以增加最大会话数。在我们的例子中,我们徘徊在 175 左右,但偶尔会出现超过 200 的流量峰值。我们暂时将其提高到 800,以确保我们不会超过最大值。权衡是将更多的服务器资源用于保存那些在超时之前可能永远不会再次使用的会话。幸运的是,服务器还控制超时。该服务可以使用ReceiveTimeout and the InactivityTimeout 控制这些会话保持打开状态的时长。两者都默认为 10 分钟,但将使用两者中较小的一个。如果您在想,“接收超时听起来是错误的。它控制了服务接收大消息所需的时间”,那么您并不孤单。但是,that's incorrect。在服务器端:

ReceiveTimeout – 服务框架层使用它来初始化会话空闲超时,该超时控制会话在超时之前可以空闲多长时间。

并且在客户端不使用它。因此,我们将ReceiveTimeout 设置为 30 秒,会话显着下降。这实际上可能太低了,因为代码中确实重用服务代理的某些位置(例如,在循环中进行多次调用,或者在调用之间进行一些数据处理)现在在尝试调用服务时出现错误会话结束后。所以你必须找到合适的平衡点。但似乎最好的做法是关闭您的连接。

需要注意的一个问题是在您的服务代理上使用Dispose。我一直尝试输入.dispo 以查看智能感知是否会在我的代理上弹出Dispose 方法,并发现它并没有假设它没有实现IDisposable 并且不需要关闭或处置。事实证明它确实实现了IDisposable,但它明确地实现了它,因此您必须将其转换为IDisposable 才能在其上调用Dispose。可是等等!暂时不要将您的代理放在using 声明中。 Dispose 的实现愚蠢地只是在代理上调用Close,如果代理处于故障状态(即,如果服务调用抛出异常),它将抛出异常。所以你不能安全地做这样的事情:

using(MyWcfClient proxy = new MyWcfClient())
{
    try
    {
        proxy.Calculate();
    }
    catch(Exception)
    {
    }
}

因为如果Calculate 抛出异常,using 块的右括号也会在尝试处置您的代理时抛出异常。相反,您只需在最后一次服务方法调用之后调用Close。显然你也可以在catch 中调用Abort,但我不确定这是否真的与服务器通信以结束会话。

MyWcfClient proxy = new MyWcfClient

try
{
    proxy.Calculate();
    proxy.Close();
}
catch(Exception)
{
    proxy.Abort();
}

附录

我们推测我们在移动服务器时开始遇到这种情况并且之前没有遇到过这种情况的原因是我们之前使用梭子鱼产品而现在使用 Oracle,并且可能旧的负载平衡器或防火墙正在为我们关闭打开的连接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 2010-09-12
    • 2023-04-03
    • 2016-10-13
    相关资源
    最近更新 更多