C# wcf请求通过后,IIS process by Service Model-4模块提供100%CPU

C# wcf请求通过后,IIS process by Service Model-4模块提供100%CPU,c#,wcf,iis,C#,Wcf,Iis,我有个问题,我现在要战斗一个星期。我有一个WCF服务在Windows Server 2012 R2上的IIS 8.5中运行,还有一个Windows服务客户端,它每30秒发出一到两个请求。在某个时刻(通常在服务运行两小时后),其中一个请求会导致服务应用程序池(与其他应用程序池分离)进程获得CPU使用率。在IIS worker process部分中可以看到,该请求永远不会结束,并以AuthenticateRequest状态挂起在ServiceModel-4模块中(即,它很可能在某个地方的无限循环中)

我有个问题,我现在要战斗一个星期。我有一个WCF服务在Windows Server 2012 R2上的IIS 8.5中运行,还有一个Windows服务客户端,它每30秒发出一到两个请求。在某个时刻(通常在服务运行两小时后),其中一个请求会导致服务应用程序池(与其他应用程序池分离)进程获得CPU使用率。在IIS worker process部分中可以看到,该请求永远不会结束,并以AuthenticateRequest状态挂起在ServiceModel-4模块中(即,它很可能在某个地方的无限循环中)。在某个时刻,另一个这样的请求被添加到第一个请求中,直到它们变为四个,永远保持不变并导致100%的CPU使用率(机器上有4个逻辑处理器)。我所做的调查,解决了这个问题:

  • 使用wcf跟踪和自定义日志来确定问题所在。Wcf跟踪实际上以毫秒(!)为单位显示成功传递给服务器的所有请求(同时客户端的Wcf跟踪当然显示相同请求的超时)。自定义日志还显示服务代码正在调用请求操作的returtn。该方法的结果是两个简单的dto对象,因此没有可能的序列化问题,也没有在从服务发送应答之前执行的enpoint行为或wathever自定义代码(方法代码除外,正如我提到的,它成功返回)

  • 已使用iis失败请求跟踪,该跟踪显示请求到达ServiceModel-4,但未继续提供以下信息: ModuleName:ServiceModel-4.0 通知:验证请求 HttpStatus:500 HttpReason:内部服务器错误 HttpSubStatus:0 错误代码:操作已成功完成(0x0)

  • 使用Debug Diag跟踪持续超过10分钟的请求,并查看运行时间较长的线程。堆栈跟踪如下所示:

或如下:

我看到这些都是从iis进程调用的。由于这些都是.Net函数,我怀疑第一次.Net安装损坏了,而且服务器上同时安装了.Net4.5和.Net4(我不知道这到底是怎么发生的)。因此:

  • 我卸载了.Net4,并从windows功能打开/关闭中关闭了.Net4.5功能,然后重新启动,之后我打开它们,重新启动,但没有成功

  • 之后,我以同样的方式重新安装了IIS(从Windows功能)。再次失败


没有更多的想法

看来我找到了答案(但没有使用点跟踪或其他工具)。可以从多个线程访问通用词典。这似乎是一个已知的问题:

实际上,我在研究过程中注意到了这个问题,但排除了它,因为我无法复制它(可能是因为我没有在iis应用程序中测试字典,当然我收到了各种异常,但不是100%的Cpu),主要是因为所有日志都显示访问字典的代码已经通过,此外,上面的堆栈跟踪与字典无关

然而,我认为问题发生在解释记录信息的字典(数据契约)的序列化过程中。
仍然无法解释这到底是怎么发生的。如果有人能解释的话,我认为这对每个人来说都是一个很好的知识。

您是否有任何多线程代码在托管代码中内部运行,这可以提高CPU,并且可能进入无限循环,因为没有可用的出口,因此会无限地消耗资源。我建议使用点跟踪探查器并检查执行过程中保留的方法,它将比其他windows调试工具更具描述性。您好,一般情况下,将通用字典用作数据契约不会有问题,只要以线程安全的方式访问它,以便在代码中读写。这当然适用于通用字典的所有用例场景,但问题在“数据契约”场景中非常“隐藏”,因为它发生在字典序列化期间,在自定义应用程序代码完成字典的所有操作之后。另一方面,根据我的说法,使用字典作为数据契约不是一种好的做法,因为:1)字典是.NET的东西,可能无法很好地支持您服务的不同于.NET的客户端。2) 字典是不可扩展的-如果您使用简单类型作为键值,并且在某个时候您需要向其中添加更多信息,那么您必须更改数据协定,而不仅仅是对其进行非破坏性扩展。因此,我建议您仅使用自定义对象而不是字典作为数据协定。如果需要,出于性能原因,您仍然可以在代码中使用字典(如果您具有多线程访问权限,还可以使用ConcurrentDictionary),并在最后将其转换为自定义对象作为数据协定