Microsoft MVP성태의 닷넷 이야기
개발 환경 구성: 702. IIS - AppPool의 "Disable Overlapped Recycle" 옵션 [링크 복사], [링크+제목 복사],
조회: 2304
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

(시리즈 글이 6개 있습니다.)
.NET Framework: 174. 작업자 프로세스(w3wp.exe)가 재시작되는 시점을 알 수 있는 방법
; https://www.sysnet.pe.kr/2/0/841

.NET Framework: 447. w3wp.exe AppPool 재생(recycle)하는 방법 정리
; https://www.sysnet.pe.kr/2/0/1704

개발 환경 구성: 246. IIS 작업자 프로세스의 20분 자동 재생(Recycle)을 끄는 방법
; https://www.sysnet.pe.kr/2/0/1774

.NET Framework: 643. 작업자 프로세스(w3wp.exe)가 재시작되는 시점을 알 수 있는 방법 - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/11145

개발 환경 구성: 702. IIS - AppPool의 "Disable Overlapped Recycle" 옵션
; https://www.sysnet.pe.kr/2/0/13514

닷넷: 2196. IIS - AppPool의 "Disable Overlapped Recycle" 옵션의 부작용
; https://www.sysnet.pe.kr/2/0/13516




IIS - AppPool의 "Disable Overlapped Recycle" 옵션

IIS의 AppPool 설정에는 "Disable Overlapped Recycle" 옵션이 제공됩니다.

overlapped_recycle_1.png

[disallowOverlappingRotation] If true, the application pool recycle will happen such that the existing worker process exits before another worker process is created. Set to true if the worker process loads an application that does not support multiple instances.


ApplicationPoolRecycling.DisallowOverlappingRotation Property
; https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.administration.applicationpoolrecycling.disallowoverlappingrotation?view=iis-dotnet

IIS 6.0 시절부터 제공하던 기능인데요,

Overlapped Recycling
; https://learn.microsoft.com/en-us/previous-versions/iis/6.0-sdk/ms525803(v=vs.90)#overlapped-recycling

간단하게 설명하자면, w3wp.exe가 recycle 되어야 할 시점이 오면 신규 w3wp.exe를 동시에 띄워 요청을 받을 수 있는 준비를 시켜둡니다. 준비가 되면, 이후 요청을 신규 w3wp.exe로 돌리고, 기존 w3wp.exe는 종료 작업에 들어가게 됩니다. 결국, 웹 서비스의 응답 시간 지연을 최소화시키기 위한 수단으로 마련된 옵션인데요, "Disable Overlapped Recycle" 옵션의 기본값이 false이기 때문에 저렇게 동작합니다.

반면, 만약 이 옵션을 true로 설정하게 되면, w3wp.exe를 완전히 종료한 다음에 신규 w3wp.exe를 띄워 서비스를 하는 방식으로 진행됩니다. 그렇다면 종료 후, 신규 프로세스가 서비스를 시작할 수 있는 시점까지 들어오는 요청들은 어떻게 되는 걸까요? 물론, 걱정하지 않으셔도 됩니다. 왜냐하면, TCP 연결에 대한 유지는 커널 드라이버에서 하고 있으므로 새로운 w3wp.exe가 서비스를 시작하게 되었을 때 IIS 커널 드라이버가 신규 worker process에 요청을 배분하기 때문입니다.




자, 그럼 대충 저 의미는 아셨겠죠? ^^

대개의 경우, 이 옵션은 기본값 false를 두는 것이 좋습니다. 하지만 여전히, 의문점이 하나 남습니다. Recycle 시 IIS 커널 레벨에서 신규 w3wp.exe로 요청을 전달하는 순간이 언제냐... 하는 것인데요, 대충 다음과 같이 시점을 나눠 예측해 볼 수 있습니다.

  1. ("Start Mode" == AlwaysRunning 옵션의) w3wp.exe의 네이티브 모듈이 모두 올라온 시점
  2. [.NET Framework만 적용] (PreApplicationStartMethod가 호출되는) .NET 런타임이 초기화된 시점
  3. ASP.NET Pipeline이 구성된 시점, 즉 ASP.NET 런타임이 초기화된 시점
  4. Application Initialization이 완료된 시점, 즉 preloadEnabled + initializationPage 요청이 완료된 시점

만약, 1번 단계에서 요청을 넘겨준다면 마찬가지로 그 프로세스로 향하는 첫 번째 요청은 원치 않는 응답 지연 현상에 걸릴 것입니다. 혹은, 3번과 같은 경우라면 기타 ASP.NET 런타임 모듈들이 모두 올라와서 꽤나 지연 현상을 줄일 수 있습니다. 물론, 가장 이상적인 것은 "/" 요청 및 initializationPage로 명시한 요청들이 완료된 이후에 이뤄지는 4번일 것입니다.

예측만 하면 재미가 없죠. ^^ 확인을 위해, 간단하게 테스트를 해보면 됩니다.

예제는 지난 글에 web.config 내 initializationPage까지 구성한 사이트를 재활용하고, 추가로 global.asax.cs의 Application 이벤트에 Log를 남기도록 한 후,

using System;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using WebApplication2.Controllers;

namespace WebApplication2
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            Log("Application_Start (Start)");

            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            Log("Application_Start (End)");
        }

        protected virtual void Application_BeginRequest()
        {
            Log("Application_BeginRequest: " + HttpContext.Current.Request.RawUrl);
        }

        protected virtual void Application_Disposed()
        {
            Log("Application_Disposed");
        }

        protected virtual void Application_End()
        {
            Log("Application_End");
        }
  
        public static void Log(string message)
        {
            System.Diagnostics.Trace.WriteLine($"[{DateTime.Now}, {ValuesController.ProcessId}] WebApplication2 - {message}");
        }
    }
}

실행을 하고, 동시에 해당 웹 사이트에 /api/values 요청을 1초 간격으로 보내는 클라이언트를 준비합니다. 그럼, 대충 이런 식으로 로그가 남게 될 것입니다.

[5708] [2024-01-05 오후 09:45:19, 5708] WebApplication2 - Application_BeginRequest: /api/values 
[5708] [2024-01-05 오후 09:45:20, 5708] WebApplication2 - Application_BeginRequest: /api/values 
[5708] [2024-01-05 오후 09:45:21, 5708] WebApplication2 - Application_BeginRequest: /api/values 
[5708] [2024-01-05 오후 09:45:22, 5708] WebApplication2 - Application_BeginRequest: /api/values 

그러다, IIS 관리자에서 Recycle을 시키면 이렇게 로그가 남게 됩니다.

[1912] [2024-01-05 오후 09:45:23, 1912] WebApplication2 - Application_Start (Start) 
[1912] [2024-01-05 오후 09:45:23, 1912] WebApplication2 - Application_Start (End) 
[1912] [2024-01-05 오후 09:45:23, 1912] WebApplication2 - Application_BeginRequest: / 
[1912] [2024-01-05 오후 09:45:23, 1912] WebApplication2 - Application_BeginRequest: /api/Values 
[5708] [2024-01-05 오후 09:45:23, 5708] WebApplication2 - Application_BeginRequest: /api/values 
[5708] [2024-01-05 오후 09:45:24, 5708] WebApplication2 - Application_BeginRequest: /api/values 
[1912] [2024-01-05 오후 09:45:25, 1912] WebApplication2 - Application_BeginRequest: /api/values 
[1912] [2024-01-05 오후 09:45:26, 1912] WebApplication2 - Application_BeginRequest: /api/values 
[1912] [2024-01-05 오후 09:45:27, 1912] WebApplication2 - Application_BeginRequest: /api/values 
[1912] [2024-01-05 오후 09:45:28, 1912] WebApplication2 - Application_BeginRequest: /api/values 
[1912] [2024-01-05 오후 09:45:29, 1912] WebApplication2 - Application_BeginRequest: /api/values 
[1912] [2024-01-05 오후 09:45:30, 1912] WebApplication2 - Application_BeginRequest: /api/values 

해석이 되시나요? bold 폰트인 1912 프로세스가 새로 뜬 w3wp.exe인데 "/" 요청과 "initializationPage"로 설정한 "/api/Values" 요청이 23초까지 진행되었습니다. 하지만, 여전히 23초와 24초에 1초 간격으로 발생하던 클라이언트의 요청은 5708 프로세스, 즉 기존에 서비스 중이던 w3wp.exe에서 받아서 처리하고 있습니다.

그리고, 이후 25초부터는 완벽히 초기화를 마친 1912 프로세스가 요청을 전담하고 있습니다. 뭐, 이 정도면 완벽한 ^^ 수준이죠?




예전에는, Cold Start 시의 응답 시간 지연 현상을 어떻게라도 없애기 위해 심지어 자동 재생을 끄는 것도 고려를 하는 경우가 있었습니다.

IIS 작업자 프로세스의 20분 자동 재생(Recycle)을 끄는 방법
; https://www.sysnet.pe.kr/2/0/1774

하지만, 이제는 "Disable Overlapped Recycle" 옵션과 함께 IIS 8.0의 "preload Enabled" 설정이 있으므로 저렇게 할 필요가 없어졌습니다.




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







[최초 등록일: ]
[최종 수정일: 1/5/2024]

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

비밀번호

댓글 작성자
 




1  2  3  4  5  6  7  8  9  10  11  [12]  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13336정성태5/4/20234685.NET Framework: 2111. C# - 바이너리 출력 디렉터리와 연관된 csproj 설정
13335정성태4/30/20234720.NET Framework: 2110. C# - FFmpeg.AutoGen 라이브러리를 이용한 기본 프로젝트 구성 - Windows Forms파일 다운로드1
13334정성태4/29/20234401Windows: 250. Win32 C/C++ - Modal 메시지 루프 내에서 SetWindowsHookEx를 이용한 Thread 메시지 처리 방법
13333정성태4/28/20233800Windows: 249. Win32 C/C++ - 대화창 템플릿을 런타임에 코딩해서 사용파일 다운로드1
13332정성태4/27/20233886Windows: 248. Win32 C/C++ - 대화창을 위한 메시지 루프 사용자 정의파일 다운로드1
13331정성태4/27/20233923오류 유형: 856. dockerfile - 구 버전의 .NET Core 이미지 사용 시 apt update 오류
13330정성태4/26/20233579Windows: 247. Win32 C/C++ - CS_GLOBALCLASS 설명
13329정성태4/24/20233773Windows: 246. Win32 C/C++ - 직접 띄운 대화창 템플릿을 위한 Modal 메시지 루프 생성파일 다운로드1
13328정성태4/19/20233454VS.NET IDE: 184. Visual Studio - Fine Code Coverage에서 동작하지 않는 Fake/Shim 테스트
13327정성태4/19/20233860VS.NET IDE: 183. C# - .NET Core/5+ 환경에서 Fakes를 이용한 단위 테스트 방법
13326정성태4/18/20235311.NET Framework: 2109. C# - 닷넷 응용 프로그램에서 SQLite 사용 (System.Data.SQLite) [1]파일 다운로드1
13325정성태4/18/20234601스크립트: 48. 파이썬 - PostgreSQL의 with 문을 사용한 경우 연결 개체 누수
13324정성태4/17/20234434.NET Framework: 2108. C# - Octave의 "save -binary ..."로 생성한 바이너리 파일 분석파일 다운로드1
13323정성태4/16/20234364개발 환경 구성: 677. Octave에서 Excel read/write를 위한 io 패키지 설치
13322정성태4/15/20235161VS.NET IDE: 182. Visual Studio - 32비트로만 빌드된 ActiveX와 작업해야 한다면?
13321정성태4/14/20233978개발 환경 구성: 676. WSL/Linux Octave - Python 스크립트 연동
13320정성태4/13/20233912개발 환경 구성: 675. Windows Octave 8.1.0 - Python 스크립트 연동
13319정성태4/12/20234386개발 환경 구성: 674. WSL 2 환경에서 GNU Octave 설치
13318정성태4/11/20234254개발 환경 구성: 673. JetBrains IDE에서 "Squash Commits..." 메뉴가 비활성화된 경우
13317정성태4/11/20234299오류 유형: 855. WSL 2 Ubuntu 20.04 - error: cannot communicate with server: Post http://localhost/v2/snaps/...
13316정성태4/10/20233592오류 유형: 854. docker-compose 시 "json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)" 오류 발생
13315정성태4/10/20233814Windows: 245. Win32 - 시간 만료를 갖는 컨텍스트 메뉴와 윈도우 메시지의 영역별 정의파일 다운로드1
13314정성태4/9/20233970개발 환경 구성: 672. DosBox를 이용한 Turbo C, Windows 3.1 설치
13313정성태4/9/20234016개발 환경 구성: 671. Hyper-V VM에 Turbo C 2.0 설치 [2]
13312정성태4/8/20234046Windows: 244. Win32 - 시간 만료를 갖는 MessageBox 대화창 구현 (개선된 버전)파일 다운로드1
13311정성태4/7/20234534C/C++: 163. Visual Studio 2022 - DirectShow 예제 컴파일(WAV Dest)
1  2  3  4  5  6  7  8  9  10  11  [12]  13  14  15  ...