WMI로 IIS 7의 작업자 프로세스 및 응용 프로그램 도메인 관리하기

등록일시: 2007-12-28 14:22,  수정일시: 2013-11-28 15:17
조회수: 8,646
이 문서는 IIS 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.

서론

간단한 WMI 스크립트를 사용해서 비교적 쉽게 IIS 7.0 작업자 프로세스와 응용 프로그램 도메인을 관리할 수 있습니다. IIS 7.0의 작업자 프로세스는 윈도우 프로세스 활성화 서비스(WAS)에 의해 생성되며 W3WP.EXE에 의해서 실행됩니다. 작업자 프로세스는 응용 프로그램 도메인을 포함할 수 있으며, 일반적으로 응용 프로그램 도메인은 특정 .ASPX 페이지 요청에 대한 응답으로 생성됩니다.

본문에서는 간단한 VBScript 코드를 사용해서 다음과 같은 작업들을 수행하는 방법을 살펴보려고 합니다. *:

  • 작업자 프로세스에서 현재 실행중인 요청을 살펴보는 방법
  • 모든 작업자 프로세스의 상태를 조회하는 방법
  • 특정 응용 프로그램 도메인, 또는 모든 응용 프로그램 도메인을 언로드 하는 방법
  • 모든 응용 프로그램 도메인 및 그 속성들을 출력하는 방법

* 작업자 프로세스와 응용 프로그램 도메인은 거의 모든 경우에 IIS 자체나 .NET 런타임에 의해서 생성됩니다. 개발자가 프로그래밍 작업을 통해서 생성하는 경우는 거의 없다고 말할 수 있으며, 그렇기 때문에 본문에서는 작업자 프로세스와 응용 프로그램 도메인을 생성하는 방법은 다루지 않습니다. 본문이 이전 몇 가지 번역 문서와 구별되는 부분입니다.

첫 번째 단계

  • IIS 설치 및 스크립팅 활성화 *
    • 만약, 윈도우 비스타를 사용중이라면 제어판에서 "프로그램 및 기능"을 열고 "Windows 기능 사용/사용 안 함"을 실행합니다. 그리고, "웹 관리 도구" 하위의 "IIS 관리 스크립트 및 도구" 항목을 선택해서 스크립팅을 활성화시킵니다.
    • 만약, 롱혼 서버를 사용중이라면 서버 관리자를 실행합니다. 그리고, Add Roles Wizard를 사용해서 IIS 웹 서버를 설치합니다. 설치 과정 중, Select Role Services 페이지에서 Management Tools 하위의 "IIS Management Scripts and Tools" 항목을 선택합니다.
  • 관리자 권한으로 명령 프롬프트를 실행합니다. 명령 프롬프트가 관리자 권한으로 실행되면 이 명령 프롬프트에서 실행되는 모든 응용 프로그램들이 관리자 권한으로 실행됩니다. 또한, 스크립트 파일을 .VBS 확장자를 가진 텍스트 파일 형식으로 저장하십시오. 이런 스크립트 파일들은 명령 프롬프트에서 "cscript.exe <scriptname>.vbs" 형식의 명령을 입력해서 실행할 수 있습니다.
  • 본문의 내용을 시작하기 전에 먼저 System32\inetsrv\config\applicationhost.config 파일의 백업본을 만들어 두십시오. 이 백업본 파일을 다시 덮어 쓰는 것만으로도 IIS를 기존 상태로 복구할 수 있습니다. **

* 기본적으로 본문의 원문은 2007년 4월 경에 비스타와 2008 베타 3을 기준으로 작성된 문서입니다. 그러나, 번역문은 가장 최신 버전인 RC1에서 거의 대부분의 테스트를 마친 결과를 반영한 것입니다. 결과만 얘기하면 사소한 몇 가지를 제외하고는 큰 변화는 존재하지 않습니다.

** 민망하지만 사실입니다. WMI에 관한 처음 두 번역 문서에서 설명했던 APPCMD 명령어를 사용한 백업 및 복구는 큰 의미가 없습니다. 파일을 복사해뒀다가 다시 덮어쓰기만 하면 다시 복구되기 때문입니다. 그러나, 제 입장에서는 직접 작성한 문서도 아니고 번역한 문서의 내용을 마음대로 변경할 수는 없었고, 배치 파일 등을 작성할 때는 제법 쓸모있는 명령어 구문이라고 판단되어 그대로 번역했습니다.

작업자 프로세스

이번 단락에서는 웹 서버에 존재하는 각각의 작업자 프로세스들이 현재 처리하고 있는 요청들을 조회하는 방법을 살펴봅니다. 그리고, 작업자 프로세스의 PID와 상태, 그리고 작업자 프로세스가 속해 있는 응용 프로그램 풀을 조회하는 방법을 알아봅니다.

처리중인 요청 조회

IIS 7.0은 작업자 프로세스가 현재 처리하고 있는 요청들을 살펴볼 수 있는 새롭고 흥미로운 기능을 제공해줍니다. WorkerProcess 클래스의 GetExecutingRequests 메서드를 사용해서 이 정보를 살펴볼 수 있습니다.

이 메서드는 자신이 실행되는 시점에 작업자 프로세스가 처리하고 있는 요청들의 정보를 스냅샷 방식으로 제공해줍니다. 대부분의 요청은 대단히 신속하게 처리되므로, 웹 브라우저에서 수작업으로 이 메서드를 테스트하는 작업이 쉽지만은 않습니다. 그렇기 때문에, 테스트를 위한 웹 페이지를 하나 작성하는 것이 좋습니다.

메모장을 사용해서 텍스트 파일에 다음 코드를 입력하고 default.aspx라는 이름으로 저장합니다.

<%
    System.Threading.Thread.Sleep(30000)
    Response.Write("I'm finally finished...")
%>

그 다음에, 이 파일을 테스트에 사용하고자 하는 웹 응용 프로그램의 컨텐츠 루트 디렉터리에 복사합니다. 이 때, Default.aspx 파일이 해당 디렉터리의 유일한 기본 문서거나 응용 프로그램의 기본 문서 목록 중, 최상단에 위치해 있어야 합니다.

이 Default.aspx 파일의 용도는 웹 페이지를 30초 동안 강제로 실행시키는 것입니다. 그 결과 스크립트로 GetExecutingRequests 메서드를 테스트 할 수 있는 시간적인 여유를 얻게 됩니다.

GetExecutingRequests 메서드는 비어있는 OUT 배열 변수를 인자로 받고 여기에 HttpRequest 객체를 채워넣습니다. 각각의 요청들에 대한 속성들을 살펴보려면 이 배열 인자의 항목들을 반복적으로 처리하면 됩니다. 다음 스크립트는 HttpRequest 개체 출력을 받고, 각각의 요청에 대한 현재 모듈, 동사, 호스트명, 그리고 URL 정보를 출력합니다.

이 스크립트를 실행하기 전에, 웹 브라우저를 사용해서 방금 생성한 Default.aspx 파일 웹 페이지를 엽니다. 그러면, 요청 처리가 실행되고 페이지 렌더링이 완료될 때까지 30초간 대기하게 됩니다.

Set oWebAdmin = GetObject("winmgmts:root\WebAdministration")
Set oWorkerProcesses = oWebAdmin.InstancesOf("WorkerProcess")

For Each oWorkerProcess In oWorkerProcesses
    ' 프로세스 큐에 존재하는 요청들을 배열 변수에 적재합니다.
    oWorkerProcess.GetExecutingRequests arrReqs

    ' 큐에서 가져온 요청들의 갯수를 점검합니다.
    If IsNull(arrReqs) Then
        WScript.Echo "No currently executing requests."
    
    Else
        ' 요청의 갯수를 출력합니다.
        WScript.Echo "Number of currently executing requests: " & _
            UBound(arrReqs) + 1
        WScript.Echo

        ' 각각의 요청의 속성들을 출력합니다.
        For Each oRequest In arrReqs
            WScript.Echo "Module: " & "[" & oRequest.CurrentModule & "]"
            WScript.Echo "Verb:" & "[" & oRequest.Verb & "]"
            WScript.Echo "HostName: " & "[" & oRequest.HostName & "]"
            WScript.Echo "Url: " & "[" & oRequest.Url & "]"
            WScript.Echo
        Next
    End If
Next

출력 결과 사례

이 스크립트를 실행시켜보면 다음과 비슷한 결과가 출력될 것입니다.

Number of currently executing requests: 2

Module: [ManagedPipelineHandler]
Verb: [GET]
HostName: [localhost]
Url: [/MyApp/]

Module: [ManagedPipelineHandler]
Verb: [GET]
HostName: [localhost]
Url: [/MyApp/default.aspx]

작업자 프로세스 상태 조회 *

IIS 7.0 WMI 제공자의 WorkerProcess 개체는 작업자 프로세스가 시작 중인지, 실행 중인지, 중지 중인지 등의 정보를 제공해주는 GetState 메서드를 제공합니다. 또한, WorkerProcess에는 흥미를 가질만한 두 가지 속성들이 제공되는데 ApplicationPool 속성과 PID 속성이 바로 그것입니다. ApplicationPool 속성은 작업자 프로세스가 속해 있는 응용 프로그램 풀 정보를 제공합니다. 그리고, PID 속성은 작업자 프로세스를 유일하게 구분할 수 있는 프로세스 ID 정보를 제공합니다.

다음 코드는 각각의 작업자 프로세스의 PID와 상태, 응용 프로그램 풀 정보를 출력합니다. 만약, 실행 중인 작업자 프로세스가 존재하지 않는다면 스크립트는 아무런 동작도 하지 않을 것입니다.

' WMI WebAdministration 네임스페이스에 연결합니다.
Set oWebAdmin = GetObject("winmgmts:root\WebAdministration") 

' 작업자 프로세스들의 인스턴스를 얻습니다.
Set oWorkerProcesses = oWebAdmin.InstancesOf("WorkerProcess") 

' 각각의 작업자 프로세스의 ID 와 응용 프로그램 풀, 상태를 얻고 출력합니다.
For Each oWorkerProcess In oWorkerProcesses 
    ' GetStateDescription 함수를 통해서 작업자 프로세스 상태를 출력합니다.
    WScript.Echo "WorkerProcess " & oWorkerProcess.ProcessID & ": " & _ 
        GetStateDescription(oWorkerProcess.GetState) 
    WScript.Echo "Application Pool: " & oWorkerProcess.AppPoolName
    WScript.Echo 
Next 

' 리턴값을 텍스트로 변환해주는 함수.
Function GetStateDescription(StateCode) 
    Select Case StateCode 
        Case 0 
            GetStateDescription = "Starting" 
        Case 1 
            GetStateDescription = "Running" 
        Case 2 
            GetStateDescription = "Stopping" 
        Case 3 
            GetStateDescription = "Unknown" 
        Case Else 
            GetStateDescription = "Undefined value." 
    End Select 
End Function 

출력 결과 사례

이 스크립트를 실행해보면 다음과 비슷한 결과가 출력될 것입니다.

WorkerProcess 1336: Running
Application Pool: DefaultAppPool

WorkerProcess 3680: Running
Application Pool: Classic .NET AppPool

WorkerProcess 1960: Running
Application Pool: NewAppPool

지금까지 우리들은 작업자 프로세스의 비밀을 밝혀내기 위해 WMI 스크립트를 사용하는 방법을 살펴보았습니다. 그럼, 이번에는 응용 프로그램 도메인에 관해서 살펴보도록 하겠습니다.

* 한 가지 주의해야 할 점이 있습니다. 테스트를 해 본 결과, 본문에 설명된 작업자 프로세스의 두 가지 중요한 속성, 즉 ApplicationPool 속성과 PID 속성은 그 이름이 변경되었습니다. 참고로 제 테스트 환경은 비스타 SP1 RTM과 2008 RC1입니다. SP1 RTM을 설치하지 않은 비스타에서는 테스트를 실시해보지 못했으므로 이 부분은 직접 확인해보시기 바랍니다.

다음 이미지는 비스타 SP1 RTM에서 캡춰한 작업자 프로세스 클래스의 속성탭입니다. 이 이미지에서 확인할 수 있는 것처럼 ApplicationPool 속성은 AppPoolName으로, PID 속성은 ProsessId로 이름이 변경되었습니다. 따라서, 본문의 샘플 스크립트를 그대로 실행하면 오류가 발생하므로, 이 점 참고하시기 바랍니다.

응용 프로그램 도메인 *

특정 ASP.NET 페이지에 대한 요청이 최초로 전달되면 IIS의 관리되는 엔진 모듈이 메모리에 응용 프로그램 도메인을 생성합니다. 응용 프로그램 도메인은 ASPX 페이지 및 관리되는 코드를 사용하는 기타 페이지들에 대한 요청을 처리합니다. WMI를 사용하면 손쉽게 응용 프로그램 도메인을 언로드하거나 열거할 수 있으며, 이번 단락에서는 이 두 가지 방법을 모두 살펴볼 것입니다.

특정 응용 프로그램 도메인 언로드

IIS 7.0에서 응용 프로그램 도메인을 언로드하는 작업과 IIS 6.0에서의 작업은 다소 차이가 존재합니다. 왜냐하면, IIS 6.0의 AppUnload 명령이 아웃-오브-프로세스 ASP 응용 프로그램을 언로드하는 기능을 제공하는 반면, IIS 7.0의 AppDomain.Unload 메서드는 오직 ASP.NET 응용 프로그램 도메인만을 언로드하기 위한 것이기 때문입니다. IIS 7.0에서는 더 이상 IIS 5.0 호환 모드를 제공하지 않으므로 AppUnload는 지원되지 않습니다.

응용 프로그램 도메인을 언로드하기 위해서는 도메인을 식별할 수 있어야 합니다. AppDomain 개체는 세 개의 키 속성, ApplicationPath, ID, 그리고 SiteName을 갖고 있습니다. 그렇지만, 이 중 한 가지 속성만 사용해도 응용 프로그램 도메인을 식별할 수 있습니다.

응용 프로그램 도메인 ID 속성은 숫자 형태가 아닌 다음과 같은 형태의 경로 문자열입니다.:

/LM/W3SVC/1/ROOT

이 경로에서 "1"은 사이트 ID를 의미합니다. (기본적으로, 1은 기본 웹 사이트에 대응됩니다.) 만약, 먼저 서버에 존재하는 응용 프로그램 도메인들과 그 속성들의 목록을 조회해보고 싶다면 본문 하단의 "응용 프로그램 도메인 열거" 부분을 살펴보시기 바랍니다.

다음의 스크립트는 "Northwind"라는 이름의 응용 프로그램 도메인을 언로드합니다. 이 스크립트에서는 사용 가능한 모든 응용 프로그램 도메인의 목록을 ApplicationPath 속성이 일치하는 항목을 찾을 때까지 반복 조회하고 있습니다.

Set oWebAdmin = GetObject("winmgmts:root\WebAdministration")
Set oAppDomains = oWebAdmin.ExecQuery("SELECT * FROM AppDomain")
    
' Northwind 응용 프로그램 도메인만 언로드합니다.
For Each oAppDomain In oAppDomains
    If oAppDomain.ApplicationPath = "/Northwind/" Then 
        oAppDomain.Unload
        Exit For 
    End If 
Next 

모든 응용 프로그램 도메인 언로드

모든 응용 프로그램 도메인을 언로드하는 방법은 간단합니다. 먼저 모든 응용 프로그램 도메인의 목록을 얻고, 반복하여 모두 언로드시키면 됩니다.

다음 스크립트는 IIS 7.0 웹 서버에 존재하는 모든 응용 프로그램 도메인을 업로드합니다. 간단한 WQL 질의문(WQL은 SQL의 WMI 버전입니다)을 사용해서 응용 프로그램 도메인의 목록을 얻는 방법을 주의하여 살펴보시기 바랍니다. **

Set oWebAdmin = GetObject("winmgmts:root\WebAdministration")
    
' 웹 서버상에 존재하는 모든 응용 프로그램 도메인을 얻는다.
Set oAppDomains = oWebAdmin.ExecQuery("SELECT * FROM AppDomain")
    
' 모든 응용 프로그램 도메인을 언로드한다.
For Each oAppDomain In oAppDomains
    oAppDomain.Unload
Next

이 스크립트에서 사용한 WQL 질의문을 작업자 프로세스에서 사용했던 것과 동일하게 WMI InstancesOf 메서드를 사용하도록 바꿀 수도 있습니다.

Set oAppDomains = oWebAdmin.InstancesOf("AppDomain")

응용 프로그램 도메인 열거

방금 전에 살펴봤던 스크립트와 유사한 코드를 사용해서 현재 실행중인 응용 프로그램 도메인들과 그 속성들을 출력할 수 있습니다. 다음은 AppDomain의 속성 목록입니다.:

Id
IsIdle
PhysicalPath
ProcessId
SiteName

여기에서 한 가지 주의해야 할 부분은 응용 프로그램 도메인의 프로세스 ID 속성 이름은 "ProcessID"며, WorkerProcess 클래스에서와 같은 "PID"가 아니라는 점입니다. ***

다음 스크립트는 각각의 응용 프로그램 도메인의 PhysicalPath 속성을 제외한 모든 속성들을 출력합니다. 그러나, 원한다면 간단하게 추가할 수 있습니다. 편의를 위해서 이 스크립트에서는 키 속성과 런-타임 속성들을 구분하여 출력하고 있습니다.

' WMI WebAdministration 네임스페이스에 연결합니다.
Set oWebAdmin = GetObject("winmgmts:root\WebAdministration")
Set oAppDomains = oWebAdmin.InstancesOf("AppDomain")

WScript.Echo "AppDomain Count: " & oAppDomains.Count
WScript.Echo 

ADCounter = 0

For Each oAppDomain In oAppDomains
    ADCounter = ADCounter + 1
    WScript.Echo "---- AppDomain " & ADCounter & " of " & oAppDomains.Count & " ----" & vbCrLf

    WScript.Echo "[ Key properties ]"
    WScript.Echo "ID: " & oAppDomain.ID
    WScript.Echo "Site Name: " & oAppDomain.SiteName
    WScript.Echo "Application Path: " & oAppDomain.ApplicationPath
    WScript.Echo

    WScript.Echo "[ Run-time properties ]"
    WScript.Echo "Process ID: " & oAppDomain.ProcessID
    WScript.Echo "Is idle: " & oAppDomain.IsIdle
    WScript.Echo vbCrLf
Next 

출력 결과 사례

이 스크립트를 실행시켜보면 다음과 비슷한 결과가 출력될 것입니다.

AppDomain Count: 3

---- AppDomain 1 of 3 ----

[ Key properties ]
ID: /LM/W3SVC/1/ROOT
Site Name: Default Web Site
Application Path: /

[ Run-time properties ]
Process ID: 3608
Is idle: False


---- AppDomain 2 of 3 ----

[ Key properties ]
ID: /LM/W3SVC/2/ROOT/ContosoApp
Site Name: ContosoSite
Application Path: /ContosoApp/

[ Run-time properties ]
Process ID: 3608
Is idle: True


---- AppDomain 3 of 3 ----

[ Key properties ]
ID: /LM/W3SVC/1/ROOT/Fabrikam
Site Name: Default Web Site
Application Path: /Fabrikam/

[ Run-time properties ]
Process ID: 2552
Is idle: False

* 응용 프로그램 도메인(AppDomain)에 대한 정보는 다음의 MSDN 문서를 참고하시기 바랍니다.

** WQL에 대한 정보는 다음의 MSDN 문서를 참고하시기 바랍니다. 참고로 ADSI 프로그래밍 작업에서도 이와 비슷한 형태의 SQL 구문을 사용할 수 있습니다.

*** 이미 설명했던 것처럼 작업자 프로세스의 ID 속성 이름은 응용 프로그램 도메인과 동일한 ProcessID로 변경되었습니다. 아마도 작업자 프로세스 클래스와 응용 프로그램 도메인 클래스의 속성 이름을 통일하기 위한 목적이 아닌가 추측해봅니다.

결론

본문에서는 IIS 7.0 작업자 프로세스와 응용 프로그램 도메인의 정보를 얻기 위해서 WMI 스크립트를 사용하는 기본적인 방법들을 살펴봤습니다. 그리고, 이런 정보들을 얻기 위해서 WMI InstanceOf 메서드와 WQL 질의문을 사용할 수 있었습니다. 마지막으로, 메서드와 해당 메서드가 사용되는 작업을 살펴보도록 하겠습니다.:

  • 작업자 프로세스에서 현재 실행중인 요청을 살펴보려면: WorkerProcess.GetExecutingRequests
  • 모든 작업자 프로세스의 상태를 조회하려면: WorkerProcess.GetState
  • 특정 응용 프로그램 도메인, 또는 모든 응용 프로그램 도메인을 언로드 하려면: AppDomain.Unload

보다 많은 정보를 보시려면 IIS 7.0 WMI Provider Reference 문서를 살펴보시기 바랍니다. *

* WMI 스크립트를 사용해서 IIS 7.0을 관리하려면 본문에서 소개하는 WMI 공급자 레퍼런스를 꼼꼼히 검토해 볼 필요가 있습니다. 그러나, 별다른 문제가 없고 관리되는 프로그램(.NET)을 사용하는 환경이라면 WMI 대신 MWA를 사용하는 것을 더 권장합니다. 이에 관해서는 제가 번역해서 MSDN에 기고한 Microsoft.Web.Administration.dll 관련 문서를 참고하시기 바랍니다.