サーバーの再起動直後に 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 サービスなどのコンテナー。これらのアプリケーション プール (w3wp) 内のコード (ネイティブ C++ COM dll および C#) .exe の) は通常、(1) & (2) で説明されているプロセスに対して DCOM 呼び出しを行います。Web ガーデンとして構成できるのは appPool1 のみです。
アプリケーションを開始/停止するために、これらの手順を制御する Windows サービス (C#) を作成しました。サービス プロセスは XWinService.exe と呼ばれます。このサービスは、次の Windows サービスに依存します (リストは最初の 4 つのサービスから始まり、継続的な試みにより、次のようなリストが作成されました...)。
W3SVC
aspnet_state
COMSysApp
DcomLaunch
winmgmt
lanmanserver
ランマンワークステーション
セクロゴン
ブラウザ
TermService
アプリケーションの停止手順の概要 (サービスによって実装されます):
1) 3 つの IIS アプリケーション プール (appPool1\2\3) をすべて停止します。これは、アプリケーションのシャットダウン時に w3wp.exe プロセスがジャンプするのを防ぐために行われます。これは、C# (system.Management.dll) の WMI で実装されます。
2) XServer1\2.exe を停止します。
3) COM+ アプリケーション (dllhost.exe) を停止します。
アプリケーションの開始手順の概要 (サービスによって実装):
1) 停止手順を実行します。これにより、時間になる前に 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 プロセスを起動し、要求の処理を開始できるようになります。
これは、アプリケーション プール (WMI) の開始と停止を担当する C# コードです。このコードは、サービス プロセス (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);
}
}
}
</p>
今問題:
サーバーを再起動する前に、サービスを手動で (services.msc ツールから) 開始すると、問題なく成功します。また、止めてもOKです。サービスを「自動」で開始するように設定しました。つまり、サーバー (Win2K3 SP2) が起動してサーバーを再起動したときに開始されます。サーバーが起動したとき (ログイン画面が表示されたとき)、サービスは「スタック」 (ステータス = 「開始中」) であり、決して開始されません (2 日間ハングします!)。
プロセスを分析すると、次のことが明らかになりました。
1) XWinService.exe プロセスが、問題のあるコード行 (### の上の ###) でスタックしていました。これは、プロセスを強制終了するまで 2 日間ハングしました。注意: アプリケーション プールのシャットダウン (Start 手順は Stop 手順で始まります) はハングしませんでした。
2) この「ハング」中に XWinService.exe から (DebugDiag ツールを使用して) 取得した DUMP ファイルから、待機中のスレッドを確認できます。これは、その (ネイティブ) スタック トレースです。
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
….
このスレッドは、プロセス 884 のコンポーネント (svchost.exe) を (DCOM 経由で) 呼び出しており、次のサービスを実行しています: 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) がダンプされ、プロセス 2880 にアクセスするスレッド (DCOM 呼び出しが終了するのを待っている) を確認できます。これは - 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 の「スタートアップ」フォルダにバッチ ファイルを配置しました。このバッチ ファイルはサービスのコードを呼び出しますが、通常の C# 実行可能ファイルとして実行します。サーバーの再起動後も、同じ問題のあるコード行でハングします (これも... 強制終了するまで 2 日間)。
5) WMI の代わりに ADSI (System.DirectoryServices) を使用しても、同じ結果が得られました (アプリケーション プールの起動が停止しました!)。
私たちは過去 2 週間、これを掘り下げてきました...
私の質問:
==========
1) 誰かが同じ問題に遭遇しましたか?
2) ハングする理由を知っている人はいますか? 留意すべき追加のサービス依存関係はありますか?
3) この問題の解決策はありますか?
4) サービスが「自動」スタートアップに設定されている場合にのみ、再起動後にこれが発生するのはなぜですか? 手動で行うと、すべて問題ありません。
***** 小さな更新:**
VM (VMware ステーション) では、サービスが再起動後、起動するまで平均 40 分ほどハングすることがわかりました (注: 起動に失敗することはありませんが、40 分は長すぎます)。システム イベント ログに、サービスが 16 分以上ハングしたことを示すイベント ログ メッセージが記録されます (ソース: Service Control Manager、イベント ID: 7044)。
「通常の」マシン (本物の金属) では、サービス開始までの平均時間は ~55 時間です!!! ここでも、前述のようにイベント ログ エントリが記録されます。
平均値は、10 の異なる VM と 8 つの異なる「実」サーバーから計算されました。