使用WMI \ ADSI(C#)启动应用程序池会在重新引导后立即挂起

vdicta 发布于 2019-11-10 adsi 最后更新 2019-11-10 12:09 36 浏览

我遇到了一个奇怪的情况,即在服务器重新启动后立即使用WMI或ADSI从Windows服务(用C#编写,设置为“自动”启动)启动应用程序池。 我将描述这个问题: 我们正在开发一个大型应用程序(Windows 2003 Server SP2,IIS 6.0),它包含以下主要进程(在启动应用程序时使用Windows服务启动过程调用和初始化这些进程): 1)XServer1.exe,XServer2.exe - 这些进程是本机COM-Exe服务器,包含一些逻辑,但主要通过DCOM(主要是.NET2COM interOp调用和纯COM调用)向其他进程提供COM对象。例如,一些经典的ASP“应用程序范围静态对象”(w3wp.exe)是在这些进程中“活动”的COM对象。 2)dllhost.exe - 这是一个COM +应用程序。我们的一些DLL被加载到这个进程中,它充当“状态服务器”(与ASP.NET进程外会话服务器相同,但对于传统的ASP页面)。 3)3个不同的IIS应用程序池(我们称之为appPool1 \ 2 \ 3) - 我们的ASP页面,ASP.NET页面,WCF服务等容器。这些应用程序池中的代码(本机C++ COM dlls和C#)( w3wp.exe)通常会对(1)&中描述的过程进行DCOM调用。 (2)。只有appPool1可以配置为Web Garden。 为了启动\停止我们的应用程序,我们编写了一个控制这些过程的Windows服务(C#)。我们的服务流程称为XWinService.exe。该服务取决于以下Windows服务(列表从前4个服务开始,正在进行的尝试使列表像这样......): W3SVC aspnet_state COMSysApp DCOMLAUNCH 为Winmgmt lanmanserver lanmanworkstation seclogon 浏览器 TermService 应用程序的Stop过程摘要(由服务实现): 1)停止所有3个IIS应用程序池(appPool1 \ 2 \ 3) - 这样做是为了防止w3wp.exe进程在应用程序关闭时跳转为活动状态。这是使用C#(system.Management.dll)中的WMI实现的 2)停止XServer1 \ 2.exe 3)停止COM +应用程序(dllhost.exe)。 应用程序的Start过程摘要(由服务实现): 1)执行Stop过程 - 这确保没有HTTP命中将在w3wp.exe进程之前唤醒它。 2)调用&初始化XServer1 \ 2.exe COM-Exe服务器 - 在任何w3wp.exe调用之前需要初始化。只有在初始化了一些对象后,w3wp.exe才能访问这些服务器。这是由.NET2COM InterOp(最终是DCOM)实现的。 3)调用&初始化dllhost.exe(COM +应用程序)进程 - 这是由ComAdmin Catalog API(C#)实现的。 4)启动我们的3个应用程序池 - 这允许传入的HTTP命中唤醒w3wp.exe进程并开始提供请求。 这是C#代码,负责启动\停止应用程序池(WMI)。此代码在我们的服务进程(XWinService.exe)中运行:

    ConnectionOptions co = new ConnectionOptions(); 
ManagementScope scope = new ManagementScope(@"\\localhost\root\MicrosoftIISV2", co); 
foreach (string appPool in AppPools) 
{ 
   string objPath = string.Format("IISApplicationPool.Name='W3SVC/AppPools/{0}'", appPool); 
   using (ManagementObject mc = new ManagementObject(objPath)) 
  {
    mc.Scope = scope; 
    if (Operation.ToLower() == "start") 
    {
     mc.InvokeMethod("Start", null, null); // ### The problematic line of code ### 
    } 
    else if (Operation.ToLower() == "stop") 
   { 
      mc.InvokeMethod("Stop", null, null); 
   } 
   else if (Operation.ToLower() == "recycle") 
  {
     mc.InvokeMethod("Recycle", null, null); 
  }

}

}

现在问题是: 在重新启动服务器之前,手动(从services.msc工具)启动服务成功没有任何问题。此外,停止它是好的。我们已将服务设置为启动“自动”,即在服务器(Win2K3 SP2)启动并重新启动服务器时启动。当服务器启动时(出现登录屏幕),我们的服务“卡住”(状态=“正在启动”)并且永远不会(它挂起2天!)启动。 分析过程揭示了以下内容: 1)XWinService.exe进程停留在有问题的代码行(### above ###)上。这件事绞死了2天,直到我们杀了这个过程。请注意:关闭应用程序池(启动过程以停止过程开始)没有挂起! 2)在这个“挂起”期间从XWinService.exe中获取的DUMP文件(使用DebugDiag工具),我们可以看到正在等待的线程。这是它的(本机)堆栈跟踪:

    Thread 6 - System ID 2784
Entry point mscorwks!Thread::intermediateThreadProc
Create time 11/19/2009 1:40:05 PM
Time spent in user mode 0 Days 00:00:00.078
Time spent in kernel mode 0 Days 00:00:00.781

This thread is making a COM call to multi-threaded apartment (MTA) in process 884 Function Source ntdll!KiFastSystemCallRet
ntdll!NtRequestWaitReplyPort+c
rpcrt4!LRPC_CCALL::SendReceive+230
rpcrt4!I_RpcSendReceive+24
ole32!ThreadSendReceive+138
ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall+112
ole32!CRpcChannelBuffer::SendReceive2+d3
ole32!CAptRpcChnl::SendReceive+ab
ole32!CCtxComChnl::SendReceive+1a9
rpcrt4!NdrProxySendReceive+43
rpcrt4!NdrClientCall2+206
rpcrt4!ObjectStublessClient+8b
rpcrt4!ObjectStubless+f
….

此线程正在调用(通过DCOM)进程884中的一个组件,即svchost.exe,运行以下服务:AeLookupSvc,AudioSrv,Browser,CryptSvc,dmserver,EventSystem,helpsvc,lanmanserver,lanmanworkstation,Schedule,seclogon,SENS,ShellHWDetection ,TrkWks,winmgmt,wuauserv,WZCSVC。 正如您所看到的,“winmgmt”服务(负责WMI)正在此过程中运行,我们的服务依赖于它,因此我们的服务将在启动winmgmt之后启动(对于IIS W3SVC服务也是如此)。 svchost.exe进程(884)被转储,我们可以看到一个线程(等待DCOM调用结束)访问进程2880,即 - wmiprvse.exe(我猜这是WMI服务器。不知道它是否相关,但这个过程有2个实例)。这是线程的本机调用堆栈(在svchost.exe中):

     Thread 48 - System ID 3816
Entry point wbemcore!CCoreQueue::_ThreadEntry
Create time 11/19/2009 1:40:56 PM
Time spent in user mode 0 Days 00:00:00.00
Time spent in kernel mode 0 Days 00:00:00.00

This thread is making a COM call to multi-threaded apartment (MTA) in process 2880

Function Source ntdll!KiFastSystemCallRet ntdll!NtRequestWaitReplyPort+c rpcrt4!LRPC_CCALL::SendReceive+230 rpcrt4!I_RpcSendReceive+24 ole32!ThreadSendReceive+138 ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall+112 ole32!CRpcChannelBuffer::SendReceive2+d3 ole32!CAptRpcChnl::SendReceive+ab ole32!CCtxComChnl::SendReceive+1a9 …

3)将我们的服务设置为“手动”并启动它(手动 - 登录到服务器或在重新启动后立即从另一台服务器远程启动)是可以的 - 没有任何事情挂起。 4)我们删除了我们的服务(来自注册表!)并将批处理文件放在windows“startup”文件夹中。此批处理文件调用服务的代码,但将其作为普通的C#可执行文件运行。服务器重新启动后,它也会挂在相同的有问题的代码行上(再次......直到我们杀死它2天)。 5)使用ADSI(System.DirectoryServices)而不是WMI具有相同的结果(启动应用程序池挂起!)。 过去两周我们一直在研究这个问题...... 我的问题:

1)有没有人遇到同样的问题? 2)有谁知道它挂起的原因?我们应该考虑其他服务依赖吗? 3)有没有人有这个问题的解决方案? 4)为什么仅在服务设置为“自动”启动后重启后才会发生这种情况?如果我们手动完成 - 一切都好! ***小更新: 我们注意到在VM(VMware工作站)上,服务在重启后平均挂起约40分钟,直到它开始(注意:它永远不会启动,但40分钟太多了)。事件日志消息记录在系统事件日志中,表明我们的服务挂起超过16分钟(来源:服务控制管理器,事件ID:7044)。 在“常规”机器(真正的金属)上,服务开始前的平均时间是~55小时!同样,如上所述记录事件日志条目。 从10个不同的VMs& VM计算avergae值。 8个不同的“真实”服务器。

已邀请:

ad_est

赞同来自:

我看到没有人回应,但无论如何我都会发布一些消息...... 我们发现,在启动应用程序池之前,将服务状态设置为“已启动”并打开运行上述代码的新线程(new Thread(...))(使用WMI启动应用程序池)可解决此问题。 这是服务的OnStart方法的伪代码:

OnStart {
     StopProcedure();
InvokeInitXServer1And2(); //COM-Exe servers
InvokeInitCOMPlusApplication(); //dllhost.exe
SetServiceStatus(SERVICE_STARTED);
Thread worker = new Thread(new threadStart(IISAppPoolStartWMI); //Calls the code
}
这是服务在合理时间内启动的唯一方式(最多3分钟,实际机器和虚拟机的平均值大约为1.5分钟!)并启动w3wp.exe进程。 如果有人对它进行了探索(MTA \ STA问题?!?!?),我将很乐意阅读它。