[Vista/2008]リモートマシンへの認証を複数回繰り返し実行するとLSASS.exeのCPU使用率がスパイクする(KB:2028484/修正モジュールあり)

みなさんごきげんよう、ういこです。今日は障害情報「リモートマシンへの認証を複数回繰り返し実行するとLSASS.exeのCPU使用率がスパイクする」 (Windows Vista / 2008 Server 無印限定) についてお知らせいたします。この現象は、Windows 2003 および Windows XP、Windows 7 および Windows Server 2008 R2 では発生しません。

【現象】
Windows Server 2008 / Windows Vista において、リモート PC に対しての WMI を使ったプログラムを同一のマシン上で同時に複数インスタンスを起動すると、プログラムを稼動させているマシン上の lsass.exe の CPU 使用率がスパイクし、プログラムの反応が遅くなっていき、最終的にプログラムがフリーズするように見える状態にまで至ることがある。この状態の間は無応答になるが、しばらくすると CPU 使用率も低下し処理が戻る。

【ステータス】
この現象は認証関連の動作の問題に起因する現象となり、修正モジュールが以下のサポート技術情報にて公開されております。
対象は Windows Vista、Windows Server 2008 です。(モジュールは CPU の種別はあるものの、OS の違いはありません)

Article ID: 2028484 - Last Review: October 13, 2010 - Revision: 1.0
You experience poor performance when you use Kerberos authentication to connect to lots of remote computers at the same time from a computer that is running Windows Server 2008 or Windows Vista
https://support.microsoft.com/default.aspx?scid=2028484

【原因】
この問題は WMI 固有の動作ではありません。認証関連の処理に起因するものになります。
よって、認証処理フェーズを実施する LSASS.exe の CPU 使用率が上昇するという形で問題が発生します。今回の事例では WMI にて発生した現象に見えますが、WMI に限らず、認証動作が伴う処理を複数実行する場合に発生する可能性があります。

リモート PC への WMI 操作を実行する場合、複数の WQL 文によるクエリが実施されますが、このように毎回認証動作が発生する動作パターンの場合、この問題による認証時の処理のオーバーヘッドが乗算的に増加し、CPU 使用率や処理時間に影響を及ぼす状況になります。

修正モジュールが適用できない場合の回避策
■プログラミングの場合

WMI によるリモート環境の参照には、必ず有効な資格情報が必要となります。この資格情報を毎回取得し認証するか、既存の資格情報により認証するかで処理負荷の改善が可能です。

ConnectionOptions でアカウントを指定するのではなく、ConnectionOptions を指定せず、事前にプロセスアカウントを想定ユーザで偽装していただくことが可能であれば、本現象に触れることはありません。
そのため、RunAS や .NET Framework の Process.Start() メソッドを用いて System.Management 名前空間を通じた WMI の処理を実行するプロセスの実行アカウントを指定し、同名前空間のメソッドの引数を変更することによって資格情報の取得および認証動作を減らすことで回避することになります。
認証動作の回数自体を減らすことはできませんが、認証に必要とされる資格情報をプロセス アカウントの資格情報で使いまわすことで資格情報の取得という認証フェーズの中でもコストの高い処理をスキップすることができ、結果として認証動作の処理負荷を軽減することが可能になります。
しかしながら同一ドメインに所属したコンピュータ間のリモート管理ではなく、ドメイン所属マシンからワークグループ所属マシンに対してのリモート管理を実施するシナリオの場合は、残念ながらこの方法を採ることが出来ません。

■WMIC コマンドの場合
ドメインに属したマシンからパスワードとユーザ名を指定せずに実行することになります。
※ ワークグループの場合は net use であらかじめ IPC$ をマウントしてコマンドを実行することで対処可能です。(後述 "再現例(2) コマンド" でも回避可能)

【再現例(1) スクリプト】
Const WbemAuthenticationLevelPktPrivacy = 6

'接続先コンピュータ名
strComputer = "uikoutest2008"
strNamespace = "root\cimv2"
'接続ユーザアカウント名:パターン1-NetBIOS (ドメイン名\ユーザ名)
strUser = "fareast\uikou"
'接続ユーザアカウント名:パターン2-FQDN (ユーザ名@ドメイン名)
'strUser = "uikou@microsoft.com"
'パスワード
strPassword = "P@ssw0rd"

For i = 0 to 1000
Set objWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objWMIService = objwbemLocator.ConnectServer _
(strComputer, strNamespace, strUser, strPassword)
objWMIService.Security_.authenticationLevel =
WbemAuthenticationLevelPktPrivacy

     Set colItems = objWMIService.ExecQuery("Select * from Win32_LocalTime")

     For Each objItem in colItems
Wscript.Echo objItem.Hour & ":" & objItem.Minute & ":" &
objItem.Second
     Next

     Set objWMIService = nothing
Set objWbemLocator = nothing
Next

【再現例(2) コマンド → バッチ化して複数回実行】
以下内容を 拡張子(.BAT) のファイルにコピーいただき、複数 (3 つ ~)のコマンド プロンプトを開いた上で同時実行します。

@ECHO OFF for /L %%i in (1,1,50) Do WMIC /node:uikou01v /user:fareast\uikou /password:P@ssw0rd path Win32_LocalTime

/node オプション : WMI 参照対象のコンピュータ名
/user オプション : 認証アカウント名 ドメイン名\ユーザ名
/password オプション : /user で指定したアカウントのパスワード

それではみなさんごきげんよう。

ういこう@大丈夫か?問題ないか?