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

(시리즈 글이 7개 있습니다.)
.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

닷넷: 2274. IIS - (프로세스 종료 없는) AppDomain Recycle
; https://www.sysnet.pe.kr/2/0/13672




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

비밀번호

댓글 작성자
 




... 61  62  63  64  65  66  67  68  69  [70]  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
12186정성태3/12/202017402오류 유형: 604. The SysVol Permissions for one or more GPOs on this domain controller and not in sync with the permissions for the GPOs on the Baseline domain controller.
12185정성태3/11/202018004오류 유형: 603. The browser service was unable to retrieve a list of servers from the browser master...
12184정성태3/11/202019932오류 유형: 602. Automatic certificate enrollment for local system failed (0x800706ba) The RPC server is unavailable. [3]
12183정성태3/11/202017732오류 유형: 601. Warning: DsGetDcName returned information for \\[...], when we were trying to reach [...].
12182정성태3/11/202019224.NET Framework: 901. C# Windows Forms - Vista/7 이후의 Progress Bar 업데이트가 느린 문제파일 다운로드1
12181정성태3/11/202019516기타: 76. 재현 가능한 최소한의 예제 프로젝트란? - 두 번째 예제파일 다운로드1
12180정성태3/10/202015970오류 유형: 600. "Docker Desktop for Windows" - EXPOSE 포트가 LISTENING 되지 않는 문제
12179정성태3/10/202027695개발 환경 구성: 481. docker - PostgreSQL 컨테이너 실행
12178정성태3/10/202019753개발 환경 구성: 480. Linux 운영체제의 docker를 위한 tcp 바인딩 추가 [1]
12177정성태3/9/202018970개발 환경 구성: 479. docker - MySQL 컨테이너 실행
12176정성태3/9/202018498개발 환경 구성: 478. 파일의 (sha256 등의) 해시 값(checksum) 확인하는 방법
12175정성태3/8/202018521개발 환경 구성: 477. "Docker Desktop for Windows"의 "Linux Container" 모드를 위한 tcp 바인딩 추가
12174정성태3/7/202017918개발 환경 구성: 476. DockerDesktopVM의 파일 시스템 접근 [3]
12173정성태3/7/202019241개발 환경 구성: 475. docker - SQL Server 2019 컨테이너 실행 [1]
12172정성태3/7/202023784개발 환경 구성: 474. docker - container에서 root 권한 명령어 실행(sudo)
12171정성태3/6/202018881VS.NET IDE: 143. Visual Studio - ASP.NET Core Web Application의 "Enable Docker Support" 옵션으로 달라지는 점 [1]
12170정성태3/6/202016908오류 유형: 599. "Docker Desktop is switching..." 메시지와 DockerDesktopVM CPU 소비 현상
12169정성태3/5/202019411개발 환경 구성: 473. Windows nanoserver에 대한 docker pull의 태그 사용 [1]
12168정성태3/5/202020620개발 환경 구성: 472. 윈도우 환경에서의 dockerd.exe("Docker Engine" 서비스)가 Linux의 것과 다른 점
12167정성태3/5/202019056개발 환경 구성: 471. C# - 닷넷 응용 프로그램에서 DB2 Express-C 데이터베이스 사용 (3) - ibmcom/db2express-c 컨테이너 사용
12166정성태3/4/202019450개발 환경 구성: 470. Windows Server 컨테이너 - DockerMsftProvider 모듈을 이용한 docker 설치
12165정성태3/2/202018430.NET Framework: 900. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 - 네 번째 이야기(Monitor.Enter 후킹)파일 다운로드1
12164정성태2/29/202019514오류 유형: 598. Surface Pro 6 - Windows Hello Face Software Device가 인식이 안 되는 문제
12163정성태2/27/202017844.NET Framework: 899. 익명 함수를 가리키는 delegate 필드에 대한 직렬화 문제
12162정성태2/26/202021690디버깅 기술: 166. C#에서 만든 COM 객체를 C/C++로 P/Invoke Interop 시 메모리 누수(Memory Leak) 발생 [6]파일 다운로드2
12161정성태2/26/202017690오류 유형: 597. manifest - The value "x64" of attribute "processorArchitecture" in element "assemblyIdentity" is invalid.
... 61  62  63  64  65  66  67  68  69  [70]  71  72  73  74  75  ...