-
ASP.NET Execution Model.NET 정리 2010. 2. 18. 17:03
다음 그림은 ASP.NET의 실행 구조를 나타내고 있는 그림이다.
복잡하게 보인다. 하지만, 이전 .NET의 실행 모델을 머리속에 두고 생각해 보면, 이 흐름이 그리 어렵게 느껴지지 않을 것이다. 그럼 이전 지식들을 뇌의 메모리에 올린 다음에 태오와 같이 이 흐름에 대해서 알아보도록 하자.먼저, 클라이언트는 서버로 특정 aspx (ASP.NET 페이지)를 호출한다. taeyo.aspx 라는 페이지를 달라는 클라이언트의 호출을 받은 웹 서버는 이 파일을 찾고, 이 파일의 확장자를 확인한다.
만일, 이 파일의 확장자가 htm 이라면 서버는 찾은 파일을 클라이언트에게 넘겨주기만 하는 역할일 뿐이겠지만, 파일의 확장자가 aspx 라는 것을 확인하면, 서버는 이 확장자와 연결되어져 있는 DLL (ASP.NET) 에게 이 파일의 처리를 의뢰한다. (ASP 때 그러하였던 것처럼 말이다)
ASP.NET은 이 파일을 받아서 일단 파싱하는 작업을 한다. 라인 단위의 파싱작업을 끝낸 다음에 이 파일은 서버에 의해서 일단 컴파일이 되어진다. 그림으로는 현재 우측 상단까지 진행되어 온 것이다. 컴파일이 되어지면 MSIL과 MetaData로 만들어지고, 이는 관리 코드인 Assembly IL 이라는 것으로 만들어 진다. 확장자는 DLL 이나 EXE 가 될 것이다. 나중에 실제 이렇게 만들어져 있는 어셈블리 IL을 확인해 볼 것이다.
일단, 관리 코드로 만들어진 것들은 어셈블리 캐쉬라는 공간에 쌓여지게 된다. 이 부분은 기존의 .NET 실행 모델과는 조금 다른데, 이것은 ASP.NET 이라는 웹 프로그래밍의 특성으로 인해 제공되는 것이다. 즉, 일단 컴파일되어진 aspx 페이지들은 그 중간완성품을 캐쉬에 저장해 놓고, 이후 여러 사용자들이 같은 aspx 페이지를 요청할 경우, 새롭게 컴파일을 해서 IL을 만들어 내는 것이 아니라, 이 캐쉬에 이미 존재하는 IL을 재사용하게 하는 것이다. 이로 인해 상당한 속도의 증가효과를 얻어낼 수 있다는 감이 마구 올 것이다.
일단, 어셈블리 캐쉬에 올라와 있는 IL 들은 요청에 대한 응답을 기다리고 있는 사용자들에게 결과물을 건네어주어야 하기에 실행을 실시한다. 캐쉬에 있던 IL 은 메모리로 올라가게 되고, 이것은 CLR의 Jitter 에 의해 다시 한번 컴파일되어지며, 그 결과 만들어지는 결과물들(대부분의 경우 동적으로 생성된 HTML)을 클라이언트의 브라우저에게 넘겨주게 되는 것이다.
중요한 것은 사용자들은 서버에서 어떠한 일이 일어나는지 모른다는 것이다. 여러분도 이 강의를 듣기전에는 전혀 알지 못했다. (물론, 예습을 통해서 알고 있었던 분도 있을 것이기는 하다) 사용자는 단지 aspx 페이지를 요청했고, 그 요청에 의해 결과로 HTML을 돌려받았다. 그게 전부이다. 사용자는 단순하다. 사용자가 요청한 결과만 주면, 그것으로 충분히 만족한다.
하지만, 이러한 흐름을 다루어야 할 여러분, 개발자들은 다르다. 서버측에서 발생하는 모든 흐름에 대해 이해하고 있어야만 하고, 그 흐름에 맞추어 프로그램을 작성해야만 한다. 이것이 ASP.NET의 실행구조를 이해해야만 하는 이유이며, .NET 이라는 기술을 이해해야만 하는 이유이다.
자. 정리해 보자. 위의 그림은 어떤 특정 페이지를 사용자가 처음 요청했을 경우의 모습을 보여주고 있다. 혼동해서는 안되는 것중 하나는 이러한 컴파일과정이 매번 사용자마다 발생하는 것은 아니라는 것이다. 우리 서버에는 taeyo.aspx 라는 파일이 존재하고 있고, 이 파일을 요청하는 사용자는 수십명에서 수천만명에 이르를 수 있다. 위의 코드 컴파일, Jit 컴파일은 매 사용자마다 발생하는 작업이 아니다. taeyo.aspx 라는 페이지를 처음 요청한 사용자의 의해 이는 코드 컴파일이 이루어지게 되고, 그 결과 관리코드가 어셈블리 캐쉬에 올라가게 된다. 그리고 나면, 다른 수백만명의 사용자가 taeyo.aspx 페이지를 요청할 경우, 어셈블리 캐쉬에 이미 존재하고 있는 관리 코드를 가져다가 사용하게 되는 것이다.
고로, 서버의 모든 aspx 페이지는 누군가가 처음 요청할 경우만 코드 파싱, 컴파일을 수행하고 그 후 어셈블리 캐쉬에 존재하게 하기에 처음 페이지를 요청한 사용자는 조금 느리게 결과물을 받을 수 있겠지만, 그 이후의 사용자들은 대단히 빠르게 어셈블리 캐쉬에 이미 존재하는 관리코드를 통해서 결과를 확인할 수 있다는 것이다.
다음 그림은 첫 요청에 의해 aspx 페이지가 어셈블리 캐쉬에 올라가 있어, 그 이후의 요청에는 빠르게 응답할 수 있는 바로 그러한 실행 흐름을 보여준다.
그림에서 볼 수 있다시피, 일단 첫 요청에 의해 어셈블리 캐쉬에 관리 코드가 존재하게 되면, 두번째 요청부터는 캐쉬로부터 빠르게 응답을 해 줄 수 있게 된다. 이것이 .NET의 장점인 것이다.
그렇다면, 만일 taeyo.aspx 페이지의 소스를 개발자가 수정하였다면 어떻게 될까? taeyo.aspx 라는 것의 컴파일된 관리 코드가 이미 어셈블리 캐쉬에 있는데, 원본 소스는 수정되었다. 이럴 경우 사용자는 수정된 소스에 의한 결과가 아닌 수정되기 이전의 결과를 볼 수 있다는 이야기인가?
그럴 경우, 현명한 ASP.NET은 수정사항을 감지하고, 어셈블리 캐쉬에 있던 해당 IL을 삭제하게 된다. 그리고, 수정된 taeyo.aspx 페이지의 첫 요청시 다시 처음부터 흐름을 시작하게 된다. 즉, 컴파일 단계를 다시금 거쳐서 어셈블리 캐쉬에 수정된 IL을 다시 올려놓는다는 이야기이다.
이 얼마나 현명한 ASP.NET 인가?
단, 만일 aspx 페이지가 코드 비하인드로 구성되어진다면, 그러한 경우, 클래스 파일이 수정될 경우는 개발자가 직접 그 클래스 파일을 컴파일해야 한다. 코드 비하인드에 대해서는 이후 자세하게 이야기할 것이니 지금은 그런 경우도 있다는 것만 알아두도록 하자.
결과적으로, 대부분의 aspx 페이지의 첫 요청은 개발자인 여러분들이 결과를 확인하면서 이루어질 것이다. 고로, 다른 일반 사용자들은 언제나 어셈블리 캐쉬에 있는 관리코드를 사용하게 될 것이고, 상당히 빠르게 결과를 받아볼 수 있게 될 것이다. 이것이 ASP.NET 이 빠르다는 근거인 것이다.
물론, 위의 실행 구조에서 빠진 부분이 하나 있다. 그것은 Output Cache 라는 것인데, 이는 위의 흐름보다 더욱 빠르게 사용자에게 응답을 해주기 위한 방법이다. Output Cache도 한 챕터를 차지할 만큼의 분량이기에 여기서 자세하게 이야기하기에는 무리가 따르지만, 간략히 설명하자면, 이는 사용자에게 최종으로 넘겨줄 두번째 컴파일 버전의 결과물을 캐쉬에 저장해 두는 방법이다. Output Cache 라는 특별한 캐쉬구역에 저장해 두게 되면, 사용자의 요청은 파싱, 코드 컴파일 단계, 런타임 컴파일 단계등을 거치지 않고, Output Cache 구역에 존재하고 있는 결과물로써 대단히 빠르게 응답해 줄 수 있게 된다. 그림으로 설명하자면 다음과 같은 흐름을 가지게 된다.
자. 이제 ASP.NET의 Execution Model 에 대한 이야기도 여러분이 충분히 이해한 것 같다. 물론, 여러분이 빨리 ASP.NET 코드를 작성하고 싶어하는 마음은 때오도 알고 있다. 하지만, 누누히 강조하였지만 이러한 기본적인 지식이 없이는 반쪽짜리 프로그램밖에 작성할 수 없다는 사실을 인지하기 바라는 마음이다.
출처 : taeyo.pe.kr'.NET 정리' 카테고리의 다른 글
asp.net 의 웹폼에 대하여.. (0) 2010.02.25 ASP.NET Development Model (0) 2010.02.18 NET Framework Class Library (0) 2010.02.18 .NET 플래폼의 구조 (0) 2010.02.18 .NET 프레임워크 (0) 2010.02.18