Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 4개 있습니다.)
(시리즈 글이 3개 있습니다.)
개발 환경 구성: 172. IIS 7.5부터 지원되는 웹 사이트 자동 시작 모드
; https://www.sysnet.pe.kr/2/0/1367

개발 환경 구성: 701. IIS - w3wp.exe 프로세스의 ASP.NET 런타임을 항상 Warmup 모드로 유지하는 preload Enabled 설정
; https://www.sysnet.pe.kr/2/0/13512

닷넷: 2194. C# - WebActivatorEx / System.Web의 PreApplicationStartMethod 특성
; https://www.sysnet.pe.kr/2/0/13513




IIS 7.5부터 지원되는 웹 사이트 자동 시작 모드

IIS는 웹 애플리케이션을 호스팅하는 w3wp.exe 프로세스를 HTTP 요청이 없는 경우 기본적으로 20분이 지나면 자동적으로 프로세스를 종료시킵니다.

이는, 서비스를 거의 사용하지 않는 시간에 w3wp.exe를 내림으로써 개발자들이 설령 프로그램에 Memory Leak과 같은 버그를 남겨놨다고 해도 정상적으로 서비스가 될 수 있도록 만드는 장점을 갖습니다. 하지만, 단점도 또한 존재합니다. w3wp.exe가 내려간 상태에서 첫 번째 요청을 보내는 사용자는 로딩 시간만큼 서비스 이용이 지연된다는 불편함이 발생하는 것입니다.

이런 문제를 해결하기 위해 II 7.5부터는 AppPool에 "Start Automatically", "Start Mode" 2가지 옵션이 제공됩니다.

apppool_start_1.png

이 중에서 "Start Automatically" 옵션은 IIS 7부터 이미 제공되고 있었습니다. 이 옵션에 대해서는 다음의 글에서 자세하게 설명해 주고 있습니다.

Configure Automatic Startup for an Application Pool (IIS 7)
; https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc772112(v=ws.10)

옵션의 이름과는 달리 "Start Automatically" 옵션은 .NET 웹 애플리케이션을 자동으로 시작해 주는 것이 아니고, IIS 서비스가 시작할 때나 AppPool 자체가 생성되면서 그것이 동작할 것이냐를 지정하는 것뿐입니다. 그렇게 따지면 IIS 6.0의 경우에도 "Start Automatically" == "True"라는 설정으로 이미 동작하고 있었던 것이나 다름없습니다. 단지 IIS 7부터 이 옵션이 등장하게 된 것은 "False"라는 값을 설정하기 위해서인데, 이에 대해서는 다음과 같이 언급하고 있습니다.

You can configure the Windows Process Activation Service (WAS) to automatically start an application pool when the application pool is created or when IIS is started. If you disable automatic startup of an application pool, you must start the application pool manually. Disabling automatic startup is useful when you want to make configuration or content changes to an application in the application pool before the application pool starts.

ImportantImportant

When an application pool is not started, requests made to applications in the application pool will return an HTTP 503-Service Unavailable error.


즉, 서비스를 구동시키기 전에 이거저거 설정해야 할 것이 있다면 "Start Automatically" == "False"로 해놓은 상태에서 할 수 있다는 의미가 있는 것입니다.

어찌 보면, IIS 7까지 이 옵션은 그다지 큰 의미가 없었지만 IIS 7.5부터 새롭게 생긴 "Start Mode"에서 상황이 바뀝니다.




"Start Mode" 설정은 AppPool 설정창에서 "Start Automatically" 옵션 바로 아래에 있습니다.

apppool_start_2.png

기본값은 OnDemand이지만, "AlwaysRunning"으로 설정한 경우 IIS 7.5는 Recycle 후에 w3wp.exe를 곧바로 다시 실행을 합니다. 즉, Recycling은 그대로 되는 장점을 유지하면서 첫 번째 사용자의 초기 로딩 시간은 줄일 수 있게 됩니다. 참고로, 이 정보는 "%WINDIR%\system32\inetsrv\config\applicationHost.config" 파일의 applicationPools 노드 내에 담겨 있습니다.

...[생략]...
<system.applicationHost>
...[생략]...

        <applicationPools>
...[생략]...
            <add name="AutoSite" autoStart="true" enable32BitAppOnWin64="true" 
                    managedRuntimeVersion="v4.0" startMode="AlwaysRunning" />
        </applicationPools>
...[생략]...
</system.applicationHost>
...[생략]...


그런데, .NET 웹 애플리케이션인 경우 "AlwaysRunning"은 그다지 큰 장점이 있는 것은 아닙니다. 아래 그림을 보시면,

apppool_start_3.png

.NET 웹 애플리케이션을 운영하다가 idle 시간이 20분 지나면 위의 그림에서처럼 새로운 w3wp.exe 프로세스가 실행됩니다. 그런데 아쉽게도 Working Set이 10MB 가량 나옵니다. 즉, 최소한의 native 코드만 올라왔을 뿐 CLR 쪽은 전혀 초기화가 안된 것입니다. 대부분의 시간이 .NET 어셈블리에 대한 JIT 컴파일 시간으로 소비되기 때문에 이렇게 되면 결과적으로 첫 번째 사용자의 기다림을 줄이는 데는 별로 도움이 되지 않습니다.

부가적으로 IIS 7.5에는 .NET 초기화를 위해 이에 대한 확장으로 "Auto Start Provider"라는 것이 추가되었습니다.

Writing an IIS 7.5 Auto Start Provider
; https://azurecloudai.blog/2011/05/11/writing-an-iis-7-5-auto-start-provider/

즉, IProcessHostPreloadClient 인터페이스를 구현한 닷넷 모듈을 사용자가 제공하면 IIS 7.5는 최초 w3wp.exe가 시작되면 configuration 파일에 지정된 닷넷 모듈을 로드해서 IProcessHostPreloadClient.Preload 메소드를 호출하게 됩니다. 어디... 실제로 한번 구현해 볼까요? ^^

간단하게 Library 유형의 프로젝트를 하나 만들고 System.Web 어셈블리를 참조한 후 다음과 같이 간단하게 인터페이스를 구현합니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Hosting;

namespace PreloadWarmup
{
    public class WarmUp : IProcessHostPreloadClient
    {
        public void Preload(string[] parameters)
        {
        }
    }
}

위의 코드를 빌드한 어셈블리명이 PreloadWarmup.dll인 경우, 이것을 배포하는 방법은 2가지로 1) GAC에 설치하거나 2) 대상이 되는 웹 애플리케이션 프로젝트에서 참조를 하는 것입니다. (대개의 경우, 간편하게 참조를 하겠지요. ^^)

이후, 이 모듈을 코드를 통해 config 파일에 반영하려면 "Writing an IIS 7.5 Auto Start Provider" 글의 내용을 참조하고, 수작업으로 변경하려면 "%WINDIR%\system32\inetsrv\config\applicationHost.config" 파일을 열어서 pre-load를 적용하려는 웹 사이트를 <sites> 노드 내에서 찾아내 serviceAutoStartEnabled, serviceAutoStartProvider를 다음과 같이 설정해 줍니다.

...[생략]...
    <sites>
        ...[생략]...
        <site name="AutoSite" id="5">
                <application path="/" applicationPool="AutoSite" 
                    serviceAutoStartEnabled="true" 
                    serviceAutoStartProvider="PreWarmupApp">
                    <virtualDirectory path="/" physicalPath="D:\WebApplication1\WebApplication1" />
                </application>
                <bindings>
                    <binding protocol="http" bindingInformation="*:8075:" />
                </bindings>
        </site>
        ...[생략]...
    </sites>
...[생략]...

주의할 것은 반드시 serviceAutoStartProvider == "PreWarmupApp"을 지정했으면 그에 해당하는 모듈이 로드되어야 합니다. 그렇지 않으면 웹 애플리케이션 서비스가 되지 않습니다. (이 부분이 좀 아쉽습니다. 일반적으로는 StartProvider가 서비스 자체에 크게 영향이 없는 코드일 텐데 원래의 애플리케이션 동작을 방해한다는 것은 좀 심한 것 같습니다.)

어쨌든, 우리가 만든 WarmUp 클래스를 로드하려면 serviceAutoStartProvider에 지정한 PreWarmupApp라는 이름과 이전에 우리가 만들어 두었던 PreloadWarmup.dll 어셈블리를 연결해야 하는데요. <system.applicationHost /> 내에 <serviceAutoStartProviders /> 노드가 이미 정의되어 있는지 살펴보고 없다면 새로 추가하고, 있다면 그 노드의 하위에 <add />로 다음과 같이 등록해 줍니다.

    <system.applicationHost>
        <sites>
            ...[생략]...
        </sites>

        ...[생략]...
        <serviceAutoStartProviders>
            <add name="PreWarmupApp" 
                type="PreloadWarmup.WarmUp, PreloadWarmup" />
        </serviceAutoStartProviders>
        ...[생략]...
    </system.applicationHost>

위에서는 PreloadWarmup.dll을 웹 애플리케이션에 같이 배포하기 때문에 상관없지만, 만약 GAC에 배포하는 경우라면 name을 FQDN 방식으로 넣어주어야 합니다. (예: PreloadWarmup.WarmUp, PreloadWarmup, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc862a9be44088eb)

이제부터는, w3wp.exe 프로세스는 recycle 후 항상 시작되고, 우리가 만든 PreloadWarmup.WarmUp 클래스의 Preload 메소드를 호출합니다.

(Preload 메소드는 여러분들이 어떻게 구현하느냐에 달려 있습니다.)




참고로, 대개의 경우 preload 기능을 구현하는 것은 특정 URL을 미리 호출해 두도록 하는 목적일 텐데요. 그래서 이를 일반화한 "Application Initialization Module"이 제공되고 있습니다.

Application Initialization Module for IIS 7.5
; http://www.iis.net/downloads/microsoft/application-initialization

그리고 윈도우 서버 2012의 IIS 8에서는 이것이 아예 IIS에 내장되었습니다.

IIS 8.0 Application Initialization 
; http://www.iis.net/learn/get-started/whats-new-in-iis-8/iis-80-application-initialization

이에 대한 사용법은 위의 문서를 보시면 쉽게 알 수 있으니 생략합니다. (나중에 시간나면 실습 과정을 한번 써보겠습니다. ^^)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 12/22/2023]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2022-05-23 10시49분
정성태

... 61  62  63  64  65  66  67  68  69  70  71  [72]  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
12136정성태2/6/202017308Windows: 168. Windows + S(또는 Q)로 뜨는 작업 표시줄의 검색 바가 동작하지 않는 경우
12135정성태2/6/202022562개발 환경 구성: 468. Nuget 패키지의 로컬 보관 폴더를 옮기는 방법 [2]
12134정성태2/5/202020994.NET Framework: 884. eBEST XingAPI의 C# 래퍼 버전 - XingAPINet Nuget 패키지 [5]파일 다운로드1
12133정성태2/5/202018407디버깅 기술: 161. Windbg 환경에서 확인해 본 .NET 메서드 JIT 컴파일 전과 후 - 두 번째 이야기
12132정성태1/28/202021245.NET Framework: 883. C#으로 구현하는 Win32 API 후킹(예: Sleep 호출 가로채기) [1]파일 다운로드1
12131정성태1/27/202020237개발 환경 구성: 467. LocaleEmulator를 이용해 유니코드를 지원하지 않는(한글이 깨지는) 프로그램을 실행하는 방법 [1]
12130정성태1/26/202017494VS.NET IDE: 142. Visual Studio에서 windbg의 "Open Executable..."처럼 EXE를 직접 열어 디버깅을 시작하는 방법
12129정성태1/26/202023648.NET Framework: 882. C# - 키움 Open API+ 사용 시 Registry 등록 없이 KHOpenAPI.ocx 사용하는 방법 [3]
12128정성태1/26/202017987오류 유형: 591. The code execution cannot proceed because mfc100.dll was not found. Reinstalling the program may fix this problem.
12127정성태1/25/202017136.NET Framework: 881. C# DLL에서 제공하는 Win32 export 함수의 내부 동작 방식(VT Fix up Table)파일 다운로드1
12126정성태1/25/202018553.NET Framework: 880. C# - PE 파일로부터 IMAGE_COR20_HEADER 및 VTableFixups 테이블 분석파일 다운로드1
12125정성태1/24/202016030VS.NET IDE: 141. IDE0019 - Use pattern matching
12124정성태1/23/202017807VS.NET IDE: 140. IDE1006 - Naming rule violation: These words must begin with upper case characters: ...
12123정성태1/23/202019516웹: 39. Google Analytics - gtag 함수를 이용해 페이지 URL 수정 및 별도의 이벤트 생성 방법 [2]
12122정성태1/20/202015653.NET Framework: 879. C/C++의 UNREFERENCED_PARAMETER 매크로를 C#에서 우회하는 방법(IDE0060 - Remove unused parameter '...')파일 다운로드1
12121정성태1/20/202016348VS.NET IDE: 139. Visual Studio - Error List: "Could not find schema information for the ..."파일 다운로드1
12120정성태1/19/202018747.NET Framework: 878. C# DLL에서 Win32 C/C++처럼 dllexport 함수를 제공하는 방법 - 네 번째 이야기(IL 코드로 직접 구현)파일 다운로드1
12119정성태1/17/202018956디버깅 기술: 160. Windbg 확장 DLL 만들기 (3) - C#으로 만드는 방법
12118정성태1/17/202019971개발 환경 구성: 466. C# DLL에서 Win32 C/C++처럼 dllexport 함수를 제공하는 방법 - 세 번째 이야기 [1]
12117정성태1/15/202018827디버깅 기술: 159. C# - 디버깅 중인 프로세스를 강제로 다른 디버거에서 연결하는 방법파일 다운로드1
12116정성태1/15/202019480디버깅 기술: 158. Visual Studio로 디버깅 시 sos.dll 확장 명령어를 (비롯한 windbg의 다양한 기능을) 수행하는 방법
12115정성태1/14/202019735디버깅 기술: 157. C# - PEB.ProcessHeap을 이용해 디버깅 중인지 확인하는 방법파일 다운로드1
12114정성태1/13/202021532디버깅 기술: 156. C# - PDB 파일로부터 심벌(Symbol) 및 타입(Type) 정보 열거 [1]파일 다운로드3
12113정성태1/12/202021567오류 유형: 590. Visual C++ 빌드 오류 - fatal error LNK1104: cannot open file 'atls.lib' [1]
12112정성태1/12/202016782오류 유형: 589. PowerShell - 원격 Invoke-Command 실행 시 "WinRM cannot complete the operation" 오류 발생
12111정성태1/12/202020568디버깅 기술: 155. C# - KernelMemoryIO 드라이버를 이용해 실행 프로그램을 숨기는 방법(DKOM: Direct Kernel Object Modification) [16]파일 다운로드1
... 61  62  63  64  65  66  67  68  69  70  71  [72]  73  74  75  ...