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분
정성태

1  2  3  4  5  6  7  8  9  10  11  12  [13]  14  15  ...
NoWriterDateCnt.TitleFile(s)
13296정성태3/25/20233691Windows: 234. IsDialogMessage와 협업하는 WM_GETDLGCODE Win32 메시지 [1]파일 다운로드1
13295정성태3/24/20233954Windows: 233. Win32 - modeless 대화창을 modal처럼 동작하게 만드는 방법파일 다운로드1
13294정성태3/22/20234125.NET Framework: 2105. LargeAddressAware 옵션이 적용된 닷넷 32비트 프로세스의 가용 메모리 - 두 번째
13293정성태3/22/20234192오류 유형: 853. dumpbin - warning LNK4048: Invalid format file; ignored
13292정성태3/21/20234312Windows: 232. C/C++ - 일반 창에도 사용 가능한 IsDialogMessage파일 다운로드1
13291정성태3/20/20234716.NET Framework: 2104. C# Windows Forms - WndProc 재정의와 IMessageFilter 사용 시의 차이점
13290정성태3/19/20234222.NET Framework: 2103. C# - 윈도우에서 기본 제공하는 FindText 대화창 사용법파일 다운로드1
13289정성태3/18/20233418Windows: 231. Win32 - 대화창 템플릿의 2진 리소스를 읽어들여 자식 윈도우를 생성하는 방법파일 다운로드1
13288정성태3/17/20233516Windows: 230. Win32 - 대화창의 DLU 단위를 pixel로 변경하는 방법파일 다운로드1
13287정성태3/16/20233686Windows: 229. Win32 - 대화창 템플릿의 2진 리소스를 읽어들여 윈도우를 직접 띄우는 방법파일 다운로드1
13286정성태3/15/20234147Windows: 228. Win32 - 리소스에 포함된 대화창 Template의 2진 코드 해석 방법
13285정성태3/14/20233738Windows: 227. Win32 C/C++ - Dialog Procedure를 재정의하는 방법파일 다운로드1
13284정성태3/13/20233938Windows: 226. Win32 C/C++ - Dialog에서 값을 반환하는 방법파일 다운로드1
13283정성태3/12/20233480오류 유형: 852. 파이썬 - TypeError: coercing to Unicode: need string or buffer, NoneType found
13282정성태3/12/20233817Linux: 58. WSL - nohup 옵션이 필요한 경우
13281정성태3/12/20233720Windows: 225. 윈도우 바탕화면의 아이콘들이 넓게 퍼지는 경우 [2]
13280정성태3/9/20234463개발 환경 구성: 670. WSL 2에서 호스팅 중인 TCP 서버를 외부에서 접근하는 방법
13279정성태3/9/20234005오류 유형: 851. 파이썬 ModuleNotFoundError: No module named '_cffi_backend'
13278정성태3/8/20233962개발 환경 구성: 669. WSL 2의 (init이 아닌) systemd 지원 [1]
13277정성태3/6/20234583개발 환경 구성: 668. 코드 사인용 인증서 신청 및 적용 방법(예: Digicert)
13276정성태3/5/20234313.NET Framework: 2102. C# 11 - ref struct/ref field를 위해 새롭게 도입된 scoped 예약어
13275정성태3/3/20234665.NET Framework: 2101. C# 11의 ref 필드 설명
13274정성태3/2/20234254.NET Framework: 2100. C# - ref 필드로 ref struct 타입을 허용하지 않는 이유
13273정성태2/28/20233955.NET Framework: 2099. C# - 관리 포인터로서의 ref 예약어 의미
13272정성태2/27/20234211오류 유형: 850. SSMS - mdf 파일을 Attach 시킬 때 Operating system error 5: "5(Access is denied.)" 에러
13271정성태2/25/20234145오류 유형: 849. Sql Server Configuration Manager가 시작 메뉴에 없는 경우
1  2  3  4  5  6  7  8  9  10  11  12  [13]  14  15  ...