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)
12162정성태2/26/202021835디버깅 기술: 166. C#에서 만든 COM 객체를 C/C++로 P/Invoke Interop 시 메모리 누수(Memory Leak) 발생 [6]파일 다운로드2
12161정성태2/26/202017875오류 유형: 597. manifest - The value "x64" of attribute "processorArchitecture" in element "assemblyIdentity" is invalid.
12160정성태2/26/202018246개발 환경 구성: 469. Reg-free COM 개체 사용을 위한 manifest 파일 생성 도구 - COMRegFreeManifest
12159정성태2/26/202015354오류 유형: 596. Visual Studio - The project needs to include ATL support
12158정성태2/25/202017935디버깅 기술: 165. C# - Marshal.GetIUnknownForObject/GetIDispatchForObject 사용 시 메모리 누수(Memory Leak) 발생파일 다운로드1
12157정성태2/25/202017976디버깅 기술: 164. C# - Marshal.GetNativeVariantForObject 사용 시 메모리 누수(Memory Leak) 발생 및 해결 방법파일 다운로드1
12156정성태2/25/202016553오류 유형: 595. LINK : warning LNK4098: defaultlib 'nafxcw.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
12155정성태2/25/202016011오류 유형: 594. Warning NU1701 - This package may not be fully compatible with your project
12154정성태2/25/202015388오류 유형: 593. warning LNK4070: /OUT:... directive in .EXP differs from output filename
12153정성태2/23/202019507.NET Framework: 898. Trampoline을 이용한 후킹의 한계파일 다운로드1
12152정성태2/23/202018570.NET Framework: 897. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 세 번째 이야기(Trampoline 후킹)파일 다운로드1
12151정성태2/22/202019355.NET Framework: 896. C# - Win32 API를 Trampoline 기법을 이용해 C# 메서드로 가로채는 방법 - 두 번째 이야기 (원본 함수 호출)파일 다운로드1
12150정성태2/21/202019604.NET Framework: 895. C# - Win32 API를 Trampoline 기법을 이용해 C# 메서드로 가로채는 방법 [1]파일 다운로드1
12149정성태2/20/202018417.NET Framework: 894. eBEST C# XingAPI 래퍼 - 연속 조회 처리 방법 [1]
12148정성태2/19/202020940디버깅 기술: 163. x64 환경에서 구현하는 다양한 Trampoline 기법 [1]
12147정성태2/19/202018623디버깅 기술: 162. x86/x64의 기계어 코드 최대 길이
12146정성태2/18/202019370.NET Framework: 893. eBEST C# XingAPI 래퍼 - 로그인 처리파일 다운로드1
12145정성태2/18/202019232.NET Framework: 892. eBEST C# XingAPI 래퍼 - Sqlite 지원 추가파일 다운로드1
12144정성태2/13/202019422.NET Framework: 891. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 두 번째 이야기파일 다운로드1
12143정성태2/13/202015990.NET Framework: 890. 상황별 GetFunctionPointer 반환값 정리 - x64파일 다운로드1
12142정성태2/12/202018343.NET Framework: 889. C# 코드로 접근하는 MethodDesc, MethodTable파일 다운로드1
12141정성태2/10/202017380.NET Framework: 888. C# - ASP.NET Core 웹 응용 프로그램의 출력 가로채기 [2]파일 다운로드1
12140정성태2/10/202017919.NET Framework: 887. C# - ASP.NET 웹 응용 프로그램의 출력 가로채기파일 다운로드1
12139정성태2/9/202019182.NET Framework: 886. C# - Console 응용 프로그램에서 UI 스레드 구현 방법
12138정성태2/9/202023204.NET Framework: 885. C# - 닷넷 응용 프로그램에서 SQLite 사용 [6]파일 다운로드1
12137정성태2/9/202016431오류 유형: 592. [AhnLab] 경고 - 디버거 실행을 탐지했습니다.
... 61  62  63  64  65  66  67  68  69  70  [71]  72  73  74  75  ...