【问题标题】:WCF service stops handling calls for 15 secondsWCF 服务停止处理调用 15 秒
【发布时间】:2015-10-09 09:34:18
【问题描述】:

我在我的一个 WCF 服务中遇到了一个奇怪的行为。这项服务在大约 1.5 年内运行良好,但几周后它显示出某种“中断”(不幸的是,我无法发布图片,因为我是新来的)。

呼叫/秒降至 0,但仍有来电。 “中断”总是 15 秒长。在这 15 秒之后,排队的呼叫被处理。它可能与网络无关,因为 90% 的调用来自同一服务器上的另一个 WCF 服务,并且没有其他服务(总共 10 个)受此行为影响。服务本身确实会继续工作,例如计算内部数据、进行数据库更新等。内部工作的执行时间不会增加。这发生在 18 到 25 分钟左右,但中断始终是 15 秒。

操作系统

Windows 服务器 2012

WCF 作为 Windows 服务运行

WCF 配置:

InstanceContextMode = InstanceContextMode.PerCall,

ConcurrencyMode = ConcurrencyMode.Multiple,

UseSynchronizationContext = false,

IncludeExceptionDetailInFaults = true

绑定 = WebHttpBinding

并发限制设置:

MaxConcurrentCalls = 384,

MaxConcurrentInstances = 2784,

MaxConcurrentSessions = 2400

我已经做了一些调查:

  1. WCF 油门设置

我在服务发生的确切时间对服务进行了完整转储。 ConcurrentCalls 和 ConcurrentSessions 都没有用尽。转储没有显示任何可能导致问题的异常。

  1. 最大 TCP 连接

对活动 TCP 连接的监控远未达到其限制。

  1. 交换机中的端口中继

由于没有呼叫,即使来自本地服务(使用本地主机),我很确定它与网络无关。

  1. 加载问题

这种行为发生在低负载(见下文)和高负载(来电的 5 倍)时。其频率不会根据负载而改变。我还尝试以大约 600-1000 次调用/秒的速度在我的暂存系统上重现该行为。我设法将服务带入一种状态,即在服务可以处理的情况下,我每秒发送更多的来电。未完成的呼叫增加了,在某些时候服务当然崩溃了。但这种行为从未出现过。

  1. 线程池耗尽

当服务以 50 个线程和 200 个线程运行时会出现此问题。尽管没有更多可用线程,但会出现一条错误消息。

我用完了可能会导致这种行为的事情。我认为,这可能是 GC 阻塞线程,因为该服务在 RAM 中使用了大约 10GB。它是一种内存缓存服务。或者它可能是操作系统(Windows Server 2012)或与 Windows 服务本身相关的东西。

有没有人自己遇到过这样的事情,或者有人有其他想法可能导致这种情况?

编辑:现在我可以发布图片了:

编辑: GC 堆转储(感谢 usr)

我看到将近 50%(总共 70%,包括相关的参考文献)是由一本大字典引起的,其中大约 50%。 2700 万个条目(基于内存转储堆)。我将专注于重构它。里面有很多没用的东西。也许这会有所帮助。

另外,我将从 msdn 添加GC.WaitForFullGCApproach Method,以查看在服务停止处理传入请求时 GC 是否正在运行。

当我知道更多时,我会及时通知你。

编辑: GC Stats(包括 14 秒的中断)

•CLR Startup Flags: CONCURRENT_GC
•Total CPU Time: 42.662 msec
•Total GC CPU Time: 2.748 msec
•Total Allocs : 1.524,637 MB
•MSec/MB Alloc : 1,802 msec/MB
•Total GC Pause: 2.977,2 msec
•% Time paused for Garbage Collection: 19,4%
•% CPU Time spent Garbage Collecting: 6,4%
•Max GC Heap Size: 11.610,333 MB
•Peak Process Working Set: 14.917,915 MB
•Peak Virtual Memory Usage: 15.326,974 MB

这“只是”3 秒的暂停。无论如何,这不应该那么高,我将重构内存存储。但它根本没有解释 15 秒 :(

编辑:在周末我做了以下事情:

  1. 已安装最新的 Windows 更新(上次更新是 2 个月前)

  2. 重启windows服务器

  3. 重构了 2700 万个对象的内存存储。我设法将使用的内存从 11GB 减少到 6-8GB(相当多)。那里的代码很旧;)

到目前为止,该问题没有再次出现(现在运行大约 17 小时)。这使我假设 GC 导致服务暂停或某些与操作系统相关的问题导致了该行为。

我猜这个问题根本没有“解决”,并且会在某个时候再次发生,因为数据会随着时间的推移而增加。

感谢大家花时间在这上面。我将继续调查转储并尝试详细了解发生了什么。我会及时通知你。

【问题讨论】:

  • 您是否尝试过打开 WCF 跟踪?我在创建频道时看到了 15 秒的停顿,我也想知道原因。
  • 迄今为止的诊断尝试非常好!我经常观察到 1-2GB/秒的 GC 速率。这种适合这里的问题。查看转储以查看所有线程在做什么。还可以使用某种 GC 分析器,PerfView 非常简单,可以为您分析 GC。
  • @Polyfun:是的,我尝试使用日志级别 = 警告进行 WCF 跟踪。没有任何可疑之处。
  • @usr:感谢您的建议。现在就来看看。
  • 事件日志会带来一些额外的信息吗?这段时间,应用程序池被回收了吗?

标签: c# multithreading wcf windows-services webhttpbinding


【解决方案1】:

如果中断足够可预测,您可以在中断期间连接windbg+SOS吗?

  • 在中断期间暂停服务两次
  • 每次运行!threads~*e!dumpstack 以显示线程状态和堆栈

如果您有 100 个线程在 15 秒内没有做任何工作,那么这应该反映在堆栈中 - 幸运的是,您的 100 个线程中的大部分是:

  1. 坚持您的一种方法(检查每个线程的“当前帧”)
  2. 卡在 WCF 方法中
  3. 执行*WaitFor* 调用
  4. 执行睡眠/延迟/IO 完成调用

【讨论】:

  • 感谢您的建议。由于它不再发生,我无法尝试。无论如何,我会在它再次发生时立即尝试。我有一个问题:如果我看到您提到的某个观点中的线程,它们是如何导致这种行为的?即使线程正在等待或阻塞等。它们如何阻止服务继续工作/接受新请求?
  • 如果您看到大量线程卡在 1 或 2 中,则说明服务代码中存在活锁/死锁,您将大致了解代码卡在的位置。如果大多数都停留在 4 中,那么请求可能无法脱离网络。这不是一门精确的科学,但我以前曾以这种方式发现过活锁类型的问题,症状与您描述的差不多,但服务的 CPU 使用率很高。
  • 好的,明白了。当它再次发生时会尝试得到它。
猜你喜欢
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
  • 2012-09-08
  • 2015-08-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多