分析案例:应用服务无响应,任务管理器中发现大量w3wp僵尸进程----等待异构系统WebService返回值

问题描述:

      某二次开发的项目反馈,不定期出现应用服务器无响应的情况,登录服务器发现任务管理器中有大量的w3wp僵尸进程。

分析过程:

      针对同一进程每隔15秒抓取dump,连续抓取3个,对比发现线程信息没有变化,并且每个线程的CPU时间和堆栈都没有变化,奇怪???

以其中一个僵尸进程的dump日志为例,总计61个工作线程,其中正在运行的为15个,但我们仅能查看其中3个线程的信息。

0:000> .load d:dumpssos.dll
0:000> !tp
CPU utilization: 3%
Worker Thread: Total: 61 Running: 15 Idle: 46 MaxLimit: 5600 MinLimit: 56
Work Request in Queue: 0
--------------------------------------
Number of Timers: 263
--------------------------------------
Completion Port Thread:Total: 1 Free: 1 MaxFree: 112 CurrentLimit: 0 MaxLimit: 5600 MinLimit: 56
0:000> !runaway
User Mode Time
  Thread       Time
   1:259e4      0 days 0:02:57.107
   2:1fa68      0 days 0:01:45.706
   0:1bc54      0 days 0:00:49.561

进一步对比这三个可见线程的堆栈显示,都在等待异构系统Webservice的网络返回。调用异构系统的具体实现为同步的HttpSoap方式,经过ESB调用第三方的认证接口。。。,按照常理来说,该WebService服务应该很简单,什么原因呢?不超时吗?

根据堆栈我们能够看到SoapHttpClientProtocol ---》HttpWebClientProtocol ---》WebClientProtocol ---》HttpWebRequest 依次的调用关系,最终的实现是HttpWebRequest。

按照msdn上官方的文档显示,HttpWebRequest 类有三个关于Timeout的设置:Timeout、ContinueTimeout、ReadWriteTimeout

https://msdn.microsoft.com/zh-cn/library/system.net.httpwebrequest(v=vs.110).aspx 

根据进程现象和活动线程的堆栈信息,推测是“远程异构系统”先响应返回HttpHeader信息后,使得Timeout超时属性失效; 之后每5分钟内都有flush回一些信息,ReadWriteTimeout也会失效;当应用程序池在设定的空闲超时限内没有接到新的request请求,触发应用程序池的回收事件;但关闭进程时发现当前进程仍有未处理完的工作进程,当前进程在等待所有工作线程执行完毕然后再退出。当应用收到新的web请求时,应用程序池创建新的w3wp进程接收处理,依次推理,长时间后便出现了很多的僵尸进程。。。。

为什么“第三方系统能够持续的反馈数据,却没有执行完成呢”? 这基本上也是不可能的,个人感觉应该是中间网络设备(防火墙、路由器、交换机)或ESB出现问题导致的,但是如果正向的联调测试话,难度太大,需要协调很多不同的外协单位。。。。

image

解决办法:

      将同步的WebService调用改为异步调用,对超过指定的时限仍未获得返回结果的请求,提示响应超时并对异步请求做Abort处理。

参考:https://msdn.microsoft.com/en-us/library/system.web.services.protocols.soaphttpclientprotocol(v=vs.110).aspx

核心的示例代码如下:

   TestSoapHttpClient webClient = new TestSoapHttpClient();
   Console.WriteLine("testing webservice: " + webClient.HelloWorld1());  // 同步调用示例 

   object asyState = new object();
   var asyResult = webClient.BeginHelloWorld2((x) => { }, asyState);

   // 设置超时时限,超时后主动终止web请求
   for (int i = 0; !asyResult.IsCompleted && i <= 5000; i += 50)
   {
       Thread.Sleep(50);
   }
   if (asyResult.IsCompleted)
   {
       string result = webClient.EndHelloWorld2(asyResult);

       // 根据远程Webservice返回的结果,继续业务处理
       Console.WriteLine("request succeed: " + result);
   }
   else
   {
       webClient.Abort();
       webClient.Dispose();

       // 记录必要的日志,根据情况决定是否抛出异常
       Console.WriteLine("web request is aborted after timeout");
       // log ......
       // throw new Exception("远程Webservice请求超时");
   }

完整的Demo:http://files.cnblogs.com/files/zhaoguan_wang/ConsoleApplication1_%E5%BC%82%E6%AD%A5%E8%B0%83%E7%94%A8WebService%E8%B6%85%E6%97%B6%E7%BB%88%E6%AD%A2%E8%AF%B7%E6%B1%82.zip

原文地址:https://www.cnblogs.com/zhaoguan_wang/p/5849541.html