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)
12086정성태12/20/201921038디버깅 기술: 144. windbg - Marshal.FreeHGlobal에서 발생한 덤프 분석 사례
12085정성태12/20/201919029오류 유형: 586. iisreset - The data is invalid. (2147942413, 8007000d) 오류 발생 - 두 번째 이야기 [1]
12084정성태12/19/201919439디버깅 기술: 143. windbg/sos - Hashtable의 buckets 배열 내용을 모두 덤프하는 방법 (do_hashtable.py) [1]
12083정성태12/17/201922389Linux: 27. linux - lldb를 이용한 .NET Core 응용 프로그램의 메모리 덤프 분석 방법 [2]
12082정성태12/17/201920596오류 유형: 585. lsof: WARNING: can't stat() fuse.gvfsd-fuse file system
12081정성태12/16/201922466개발 환경 구성: 465. 로컬 PC에서 개발 중인 ASP.NET Core 웹 응용 프로그램을 다른 PC에서도 접근하는 방법 [5]
12080정성태12/16/201919615.NET Framework: 870. C# - 프로세스의 모든 핸들을 열람
12079정성태12/13/201921549오류 유형: 584. 원격 데스크톱(rdp) 환경에서 다중 또는 고용량 파일 복사 시 "Unspecified error" 오류 발생
12078정성태12/13/201921356Linux: 26. .NET Core 응용 프로그램을 위한 메모리 덤프 방법 [3]
12077정성태12/13/201920426Linux: 25. 자주 실행할 명령어 또는 초기 환경을 "~/.bashrc" 파일에 등록
12076정성태12/12/201918958디버깅 기술: 142. Linux - lldb 환경에서 sos 확장 명령어를 이용한 닷넷 프로세스 디버깅 - 배포 방법에 따른 차이
12075정성태12/11/201919757디버깅 기술: 141. Linux - lldb 환경에서 sos 확장 명령어를 이용한 닷넷 프로세스 디버깅
12074정성태12/10/201919460디버깅 기술: 140. windbg/Visual Studio - 값이 변경된 경우를 위한 정지점(BP) 설정(Data Breakpoint)
12073정성태12/10/201920943Linux: 24. Linux/C# - 실행 파일이 아닌 스크립트 형식의 명령어를 Process.Start로 실행하는 방법
12072정성태12/9/201917705오류 유형: 583. iisreset 수행 시 "No such interface supported" 오류
12071정성태12/9/201921256오류 유형: 582. 리눅스 디스크 공간 부족 및 safemode 부팅 방법
12070정성태12/9/201923183오류 유형: 581. resize2fs: Bad magic number in super-block while trying to open /dev/.../root
12069정성태12/2/201919596디버깅 기술: 139. windbg - x64 덤프 분석 시 메서드의 인자 또는 로컬 변수의 값을 확인하는 방법
12068정성태11/28/201928252디버깅 기술: 138. windbg와 Win32 API로 알아보는 Windows Heap 정보 분석 [3]파일 다운로드2
12067정성태11/27/201919656디버깅 기술: 137. 실제 사례를 통해 Debug Diagnostics 도구가 생성한 닷넷 웹 응용 프로그램의 성능 장애 보고서 설명 [1]파일 다운로드1
12066정성태11/27/201919303디버깅 기술: 136. windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석 - OracleCommand.ExecuteReader에서 OpsSql.Prepare2 PInvoke 호출 분석
12065정성태11/25/201917610디버깅 기술: 135. windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석파일 다운로드1
12064정성태11/25/201920543오류 유형: 580. HTTP Error 500.0/500.33 - ANCM In-Process Handler Load Failure
12063정성태11/21/201919484디버깅 기술: 134. windbg - RtlReportCriticalFailure로부터 parameters 정보 찾는 방법
12062정성태11/21/201918933디버깅 기술: 133. windbg - CoTaskMemFree/FreeCoTaskMem에서 발생한 덤프 분석 사례 - 두 번째 이야기
12061정성태11/20/201919391Windows: 167. CoTaskMemAlloc/CoTaskMemFree과 윈도우 Heap의 관계
... 61  62  63  64  65  66  67  68  69  70  71  72  73  [74]  75  ...