ASP.NET을 사용하여 웹 응용 프로그램을 작성하는 것이 얼마나 쉬운지 놀라울 정도입니다. 이러한 단순성 때문에 많은 개발자는 더 나은 성능을 위해 애플리케이션을 구성하는 데 시간을 투자하지 않습니다. 이 기사에서는 고성능 웹 애플리케이션 작성을 위한 10가지 팁을 다룰 것입니다. 그러나 이러한 응용 프로그램은 웹 응용 프로그램의 일부일 뿐이므로 이러한 제안을 ASP.NET 응용 프로그램으로 제한하지는 않겠습니다. 이 기사는 웹 애플리케이션 성능 조정에 대한 최종 가이드가 아닙니다. 책 전체에서 이 주제를 쉽게 다룰 수는 없습니다. 이 기사를 훌륭한 출발점으로 생각하십시오.
워커홀릭이 되기 전에는 암벽등반을 즐기곤 했어요. 큰 등반을 하기 전에 나는 가이드북에 있는 경로를 주의 깊게 살펴보고 이전 방문객의 추천 사항을 읽는 것부터 시작합니다. 그러나 가이드가 아무리 훌륭하더라도 특별히 도전적인 등반을 시도하기 전에는 실제 암벽 등반 경험이 필요합니다. 마찬가지로 성능 문제를 해결하거나 처리량이 높은 사이트를 실행하는 경우에만 고성능 웹 응용 프로그램을 작성하는 방법을 배울 수 있습니다.
저의 개인적인 경험은 Microsoft의 ASP.NET 부서에서 인프라 프로그램 관리자로 근무하면서 얻은 것입니다. 그곳에서 저는 www.ASP.NET을 실행 및 관리하고 잘 알려진 여러 서버 중 하나인 커뮤니티 서버 설계를 도왔습니다.
ASP.NET 애플리케이션(ASP.NET 포럼, .Text 및 nGallery가 하나의 플랫폼으로 결합됨) 나에게 도움이 되었던 몇 가지 팁이 당신에게도 도움이 될 것이라고 확신합니다.
애플리케이션을 여러 논리적 계층으로 나누는 것을 고려해야 합니다. 3계층(또는 n계층) 물리적 아키텍처라는 용어를 들어보셨을 것입니다. 이는 일반적으로 프로세스 및/또는 하드웨어 간의 기능을 물리적으로 분리하는 규정된 아키텍처 접근 방식입니다. 시스템을 확장해야 할 경우 더 많은 하드웨어를 쉽게 추가할 수 있습니다. 그러나 프로세스 및 시스템 점프와 관련된 성능 저하가 있으므로 피해야 합니다. 따라서 가능하다면 동일한 응용 프로그램에서 ASP.NET 페이지와 관련 구성 요소를 함께 실행해 보십시오.
코드 분리와 계층 간의 경계로 인해 웹 서비스나 원격을 사용하면 성능이 20% 이상 저하됩니다.
데이터 계층은 약간 다릅니다. 일반적으로 데이터베이스 전용 하드웨어를 보유하는 것이 더 낫기 때문입니다. 그러나 프로세스를 데이터베이스로 점프하는 데 드는 비용은 여전히 높기 때문에 코드를 최적화할 때 가장 먼저 고려해야 할 문제는 데이터 계층의 성능입니다.
애플리케이션의 성능 수정 사항을 살펴보기 전에 먼저 애플리케이션을 프로파일링하여 특정 문제를 식별해야 합니다. 가비지 수집을 수행하는 데 필요한 시간 비율을 나타내는 것과 같은 주요 성능 카운터는 응용 프로그램이 주요 시간을 소비하는 위치를 찾는 데도 유용합니다. 그러나 시간이 어디에 소비되는지는 종종 매우 직관적이지 않습니다.
이 문서에서는 두 가지 유형의 성능 개선, 즉 대규모 최적화(예: ASP.NET 캐싱 사용)와 반복되는 소규모 최적화에 대해 설명합니다. 이러한 작은 최적화는 때때로 특히 흥미롭습니다. 코드를 조금만 변경하면 많은 시간을 벌 수 있습니다. 대규모 최적화를 사용하면 전반적인 성능이 크게 향상될 수 있습니다. 작은 최적화를 사용하면 특정 요청에 대해 몇 밀리초만 절약할 수 있지만 매일 모든 요청을 합산하면 엄청난 개선이 될 수 있습니다.
데이터 계층 성능
애플리케이션 성능 조정과 관련하여 작업 우선 순위를 지정하는 데 사용할 수 있는 딥스틱 테스트가 있습니다. 코드가 데이터베이스에 액세스합니까? 그렇다면, 어떤 빈도로? 이와 동일한 테스트를 웹 서비스나 원격 기능을 사용하는 코드에도 적용할 수 있지만 이 문서에서는 이에 대해 다루지 않습니다.
특정 코드 경로에서 데이터베이스 요청이 필요하고 다른 영역(예: 문자열 조작)을 먼저 최적화해야 한다고 생각하는 경우 중지한 후 이 딥스틱 테스트를 수행하십시오. 성능 문제가 심각하지 않은 경우 데이터베이스에 소요되는 시간, 반환되는 데이터의 양, 데이터베이스 간 왕복 빈도를 최적화하는 데 시간을 투자하는 것이 좋습니다.
이러한 일반적인 정보를 염두에 두고 애플리케이션 성능을 향상시키는 데 도움이 될 수 있는 10가지 팁을 살펴보겠습니다. 먼저, 가장 큰 변화를 가져올 수 있는 변화에 대해 이야기하겠습니다.
팁 1 - 여러 결과 세트 반환
데이터베이스에 대한 요청 경로가 여러 개 있는지 확인하려면 데이터베이스 코드를 주의 깊게 살펴보세요. 이러한 각 왕복은 애플리케이션이 처리할 수 있는 초당 요청 수를 줄입니다. 하나의 데이터베이스 요청으로 여러 결과 세트를 반환하면 데이터베이스와 통신하는 데 필요한 전체 시간을 절약할 수 있습니다. 동시에 요청 관리 시 데이터베이스 서버의 작업을 줄여 시스템의 확장성을 높입니다.
동적 SQL을 사용하여 여러 결과 집합을 반환하는 것이 가능하지만 내가 선호하는 방법은 저장 프로시저를 사용하는 것입니다. 비즈니스 로직이 저장 프로시저에 상주해야 하는지에 관해 약간의 논쟁이 있지만, 저장 프로시저의 로직이 반환되는 데이터를 제한할 수 있다면 더 좋을 것이라고 생각합니다(데이터 세트의 크기를 줄이고, 저장 프로시저에 소요되는 시간을 줄입니다). 논리 계층) 데이터를 선별할 필요 없이 네트워크)가 선호되어야 합니다.
SqlCommand 인스턴스와 해당 ExecuteReader 메서드를 사용하여 강력한 형식의 비즈니스 클래스를 채울 때 NextResult를 호출하여 결과 집합 포인터를 앞으로 이동할 수 있습니다. 그림 1은 유형 클래스를 사용하여 여러 ArrayList를 채우는 샘플 세션을 보여줍니다. 데이터베이스에서 필요한 데이터만 반환하면 서버의 메모리 할당이 더욱 줄어듭니다.
그림 1 DataReader에서 여러 결과 집합 추출
// 첫 번째 결과 집합을 읽습니다.
reader = command.ExecuteReader();
// 해당 결과 집합에서 데이터를 읽습니다.
동안(reader.Read()) {
공급자.추가(PopulateSupplierFromIDataReader(reader));
}
// 다음 결과 집합을 읽습니다.
reader.NextResult();
// 두 번째 결과 집합에서 데이터를 읽습니다.
동안(reader.Read()) {
products.Add(PopulateProductFromIDataReader( 리더 ));
}
팁 2 - 페이지 매김 데이터 액세스
ASP.NET DataGrid에는 데이터 페이지 매김 지원이라는 멋진 기능이 있습니다. DataGrid에서 페이징을 활성화하면 한 번에 고정된 수의 레코드가 표시됩니다. 또한 레코드 간 탐색을 용이하게 하기 위해 DataGrid 하단에 페이징 UI가 표시됩니다. 페이징 UI를 사용하면 표시된 데이터를 앞뒤로 탐색할 수 있으며 한 번에 고정된 수의 레코드를 표시할 수 있습니다.
작은 반전도 있습니다. DataGrid를 사용하여 페이지 매김을 수행하려면 모든 데이터가 그리드에 바인딩되어야 합니다. 예를 들어 데이터 레이어가 모든 데이터를 반환해야 하는 경우 DataGrid는 현재 페이지를 기반으로 표시된 모든 레코드를 필터링합니다. DataGrid를 통해 페이징할 때 100,000개의 레코드가 반환되면 각 요청에 대해 99,975개의 레코드가 삭제됩니다(페이지 크기가 25개 레코드라고 가정). 레코드 수가 증가하면 각 요청과 함께 점점 더 많은 데이터를 전송해야 하므로 애플리케이션 성능이 저하됩니다.
더 나은 성능의 페이지 매김 코드를 작성하는 가장 좋은 방법은 저장 프로시저를 사용하는 것입니다. 그림 2는 Northwind 데이터베이스의 Orders 테이블을 페이징하기 위한 저장 프로시저의 예를 보여줍니다. 즉, 이 시점에서 해야 할 일은 페이지 인덱스와 페이지 크기를 전달하는 것뿐입니다. 그런 다음 적절한 결과 집합이 계산되어 반환됩니다.
그림 2 Orders 테이블을 통한 페이징
생성 절차 northwind_OrdersPaged
(
@PageIndex 정수,
@PageSize 정수
)
처럼
시작하다
@PageLowerBound int 선언
@PageUpperBound int 선언
DECLARE @RowsToReturn int
-- 먼저 행 개수를 설정합니다.
SET @RowsToReturn = @PageSize * (@PageIndex + 1)
SET ROWCOUNT @RowsToReturn
-- 페이지 경계를 설정합니다.
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1
-- 선택 결과를 저장할 임시 테이블을 만듭니다.
테이블 생성 #페이지인덱스
(
IndexId int IDENTITY (1, 1) NOT NULL,
주문 ID 정수
)
- 임시 테이블에 삽입
#PageIndex(OrderID)에 삽입
선택하다
주문ID
에서
명령
주문 방법
OrderID DESC
-- 총 개수 반환
SELECT COUNT(OrderID) FROM Orders
-- 페이징된 결과 반환
선택하다
영형.*
에서
주문 O,
#PageIndex 페이지 인덱스
어디
O.OrderID = PageIndex.OrderID AND
PageIndex.IndexID > @PageLowerBound AND
PageIndex.IndexID < @PageUpperBound
주문 방법
PageIndex.IndexID
END
커뮤니티 서버에서는 모든 데이터 페이징을 완료하기 위해 페이징 서버 컨트롤을 작성했습니다. 앞으로 보게 되겠지만 팁 1에서 설명한 개념을 사용하여 저장 프로시저에서 총 레코드 수와 요청된 데이터라는 두 가지 결과 집합을 반환합니다.
반환되는 총 레코드 수는 실행된 쿼리에 따라 달라질 수 있습니다. 예를 들어 WHERE 절을 사용하여 반환되는 데이터를 제한할 수 있습니다. 페이지가 매겨진 UI에 표시되는 총 페이지 수를 계산하려면 반환될 총 레코드 수를 알아야 합니다. 예를 들어 총 1,000,000개의 레코드가 있고 WHERE 절을 사용하여 이를 1000개의 레코드로 필터링하려는 경우 페이징 UI를 올바르게 렌더링하려면 페이징 논리가 총 레코드 수를 알아야 합니다.
팁 3 — 연결 풀링
웹 응용 프로그램과 SQL Server 간에 TCP 연결을 설정하는 것은 리소스를 많이 사용하는 작업일 수 있습니다. Microsoft 개발자들은 한동안 연결 풀링을 사용해 데이터베이스 연결을 재사용할 수 있었습니다. 모든 요청에 대해 새 TCP 연결을 설정하는 대신 연결 풀에 연결이 없을 때만 새 연결을 설정합니다. 연결이 닫히면 TCP 연결을 완전히 끊는 대신 데이터베이스에 대한 연결을 유지하는 연결 풀로 돌아갑니다.
물론 연결 누출이 발생하는 경우에는 주의해야 합니다. 연결 사용을 마친 후에는 연결을 닫으십시오. 반복합니다. Microsoft® .NET Framework의 가비지 수집에 대해 누가 뭐라고 말하든 사용이 끝나면 연결에 대해 명시적으로 Close 또는 Dispose를 호출해야 합니다. 미리 결정된 시간에 연결을 지우고 닫는 CLR(공용 언어 런타임)을 신뢰하지 마십시오. CLR은 결국 클래스를 삭제하고 연결을 강제로 닫지만 개체의 가비지 수집이 실제로 발생하는 시기는 보장되지 않습니다.
연결 풀링을 최적의 방식으로 사용하려면 따라야 할 몇 가지 규칙이 있습니다. 먼저 연결을 열고 작업을 수행한 다음 연결을 닫습니다. 꼭 필요한 경우 요청당 연결을 여러 번 열고 닫으세요(팁 1 적용 권장). 하지만 연결을 항상 열어 두지 말고 다양한 방법을 사용하여 연결을 전달하세요. 둘째, 동일한 연결 문자열(통합 인증을 사용하는 경우 동일한 스레드 ID)을 사용합니다. 예를 들어 로그인한 사용자를 기반으로 연결 문자열을 사용자 지정하는 등 동일한 연결 문자열을 사용하지 않으면 연결 풀이 제공하는 것과 동일한 최적화 값을 얻을 수 없습니다. 통합 인증을 사용하면서 동시에 다수의 사용자를 사칭하는 경우 연결 풀의 효율성도 크게 저하됩니다. .NET CLR 데이터 성능 카운터는 연결 풀링과 관련된 성능 문제를 추적하려고 할 때 유용할 수 있습니다.
애플리케이션이 다른 프로세스에서 실행되는 데이터베이스와 같은 리소스에 연결할 때마다 해당 리소스에 연결하는 데 걸리는 시간, 데이터를 보내거나 검색하는 데 걸리는 시간, 왕복 횟수에 중점을 두어 최적화해야 합니다. 애플리케이션에서 모든 종류의 프로세스 호핑을 최적화하는 것이 더 나은 성능을 얻기 위한 첫 번째 포인트입니다.
애플리케이션 계층에는 데이터 계층에 연결하고 데이터를 의미 있는 클래스 인스턴스 및 비즈니스 프로세스로 변환하는 논리가 포함되어 있습니다. 예를 들어, 포럼 또는 스레드 컬렉션을 채우려는 커뮤니티 서버는 비즈니스 규칙(예: 권한)을 적용하고 가장 중요한 것은 캐싱 논리를 수행하는 것입니다.
팁 4 - ASP.NET 캐싱 API
응용 프로그램 코드를 작성하기 전에 가장 먼저 해야 할 일 중 하나는 ASP.NET 캐싱 기능을 최대한 활용하도록 응용 프로그램 계층을 구성하는 것입니다.
구성 요소가 ASP.NET 응용 프로그램에서 실행되는 경우 응용 프로그램 프로젝트에 System.Web.dll에 대한 참조만 포함하면 됩니다. 캐시에 액세스해야 하는 경우 HttpRuntime.Cache 속성을 사용하세요. 이 개체는 Page.Cache 및 HttpContext.Cache를 통해서도 액세스할 수 있습니다.
데이터 캐싱에는 몇 가지 규칙이 있습니다. 첫째, 데이터가 여러 번 사용될 가능성이 있는 경우 캐싱을 사용하는 것이 좋은 대안입니다. 둘째, 데이터가 일반적이고 특정 요청이나 사용자에 국한되지 않는 경우에도 캐싱에 적합한 후보입니다. 데이터가 사용자나 요청에 특정하지만 수명이 긴 경우에도 캐시할 수 있지만 자주 사용되지는 않을 수 있습니다. 셋째, 종종 간과되는 규칙은 때로는 너무 많은 캐시를 캐시할 수 있다는 것입니다. 일반적으로 x86 컴퓨터에서는 메모리 부족 오류 가능성을 줄이려면 800MB 이하의 전용 바이트로 프로세스를 실행하는 것이 좋습니다. 따라서 캐시에는 제한이 있어야 합니다. 즉, 계산 결과를 재사용할 수 있지만 해당 계산에 10개의 매개변수가 사용되는 경우 10개의 순열을 캐시하려고 하여 문제가 발생할 수 있습니다. ASP.NET 지원에 대한 가장 일반적인 요청 중 하나는 특히 대규모 데이터 세트의 경우 과도한 캐싱으로 인해 발생하는 메모리 부족 오류입니다.
캐싱에는 알아야 할 몇 가지 훌륭한 기능이 있습니다. 첫째, 캐시는 가장 최근에 사용된 알고리즘을 구현하여 ASP.NET이 메모리가 덜 효율적으로 실행될 때 캐시 제거(사용하지 않는 항목을 캐시에서 자동으로 제거)를 강제로 수행할 수 있도록 합니다. 둘째, 캐시는 강제로 만료될 수 있는 만료된 종속성을 지원합니다. 이러한 종속성에는 시간, 키 및 파일이 포함됩니다. 시간이 자주 사용되지만 ASP.NET 2.0에서는 데이터베이스 캐시 무효화라는 새롭고 더욱 강력한 무효화 유형이 도입되었습니다. 데이터베이스의 데이터가 변경되면 캐시에 있는 항목을 자동으로 삭제하는 것을 말합니다. 데이터베이스 캐시 무효화에 대한 자세한 내용은 2004년 7월 MSDN Magazine의 Dino Esposito Cutting Edge 칼럼을 참조하십시오. 캐시 아키텍처를 이해하려면 아래 다이어그램을 참조하세요.
팁 6 — 백그라운드 처리
코드로 가는 경로는 최대한 빨라야 합니다. 그렇죠? 매 요청마다 또는 n번 요청마다 한 번씩 수행되는 작업에 많은 리소스가 필요하다고 느낄 때가 있을 수 있습니다. 이메일을 보내거나 들어오는 데이터를 분석하고 검증하는 것이 몇 가지 예입니다.
ASP.NET 포럼 1.0을 분석하고 커뮤니티 서버를 구성하는 콘텐츠를 다시 설계할 때 새로운 게시 코드 경로를 추가하는 것이 매우 느리다는 사실을 발견했습니다. 새 게시물이 추가될 때마다 애플리케이션은 먼저 중복된 게시물이 없는지 확인한 다음 "나쁜 단어" 필터를 사용하여 게시물을 분석하고, 게시된 문자 이모티콘을 분석하고, 게시물에 태그를 지정하고 색인을 생성한 다음, 요청 시 게시 적절한 대기열로 이동하여 첨부 파일을 확인한 후 최종 게시 시 즉시 모든 구독자에게 이메일 알림을 보냅니다. 분명히 많은 내용이 관련되어 있습니다.
조사 결과, 대부분의 시간이 로직을 인덱싱하고 이메일을 보내는 데 소요되는 것으로 나타났습니다. 게시물 색인화는 매우 시간이 많이 걸리는 작업이며, 내장된 System.Web.Mail 기능이 SMYP 서버에 연결한 다음 지속적으로 이메일을 보내는 것으로 밝혀졌습니다. 특정 게시물이나 주제 영역에 대한 구독자 수가 증가하면 AddPost 기능을 실행하는 데 시간이 점점 더 오래 걸립니다.
모든 요청에 이메일 인덱싱이 필요한 것은 아닙니다. 이상적으로는 이 작업을 일괄 처리하여 한 번에 25개의 게시물을 색인화하거나 5분마다 모든 이메일을 보내는 것을 원합니다. 우리는 Visual Studio® 2005에서 사용된 데이터 캐시 무효화의 프로토타입을 만들기 위해 이전에 사용한 코드를 사용하기로 결정했습니다.
System.Threading 네임스페이스의 Timer 클래스는 매우 유용하지만 적어도 웹 개발자들 사이에서는 .NET Framework에서 잘 알려져 있지 않습니다. 일단 생성되면 이 Timer 클래스는 ThreadPool의 스레드에 대해 구성 가능한 간격으로 지정된 콜백을 호출합니다. 즉, ASP.NET 응용 프로그램에 대한 요청이 들어오지 않고도 실행되도록 코드를 설정할 수 있으며 이는 백그라운드 처리에 이상적입니다. 이 백그라운드 프로세스에서 색인화 또는 이메일 전송과 같은 작업을 수행할 수도 있습니다.
그러나 이 기술에는 몇 가지 문제점이 있습니다. 애플리케이션 도메인이 제거되면 이 타이머 인스턴스는 해당 이벤트 실행을 중지합니다. 또한 CLR에는 프로세스당 스레드 수에 대한 엄격한 표준이 있기 때문에 타이머에 완료할 스레드가 없어 서버의 로드가 어느 정도 지연되는 상황이 있을 수 있습니다. ASP.NET은 프로세스에서 특정 수의 스레드를 사용 가능하게 유지하고 요청 처리에 전체 스레드 중 일부만 사용하여 이러한 상황이 발생할 가능성을 최소화하려고 합니다. 그러나 비동기 작업이 많은 경우에는 문제가 될 수 있습니다.
여기에는 이 코드를 위한 공간이 충분하지 않지만 www.rob-howard.net에서 읽을 수 있는 예제를 다운로드할 수 있습니다. Blackbelt TechEd 2004 프레젠테이션의 슬라이드와 데모를 확인해 보세요.
팁 7 — 페이지 출력 캐싱 및 프록시 서버
ASP.NET은 프레젠테이션 계층입니다(또는 프레젠테이션 계층이어야 함). 이는 페이지, 사용자 컨트롤, 서버 컨트롤(HttpHandler 및 HttpModules) 및 이들이 생성하는 콘텐츠로 구성됩니다. 출력(HTML, XML, 이미지 또는 기타 데이터)을 생성하는 ASP.NET 페이지가 있고 모든 요청에 대해 이 코드를 실행하면 동일한 출력이 생성되는 경우 A에 사용할 수 있는 도구가 있습니다. 페이지 출력 캐싱에 대한 훌륭한 대안입니다.
페이지 상단에 다음 내용 줄을 추가하세요. <%@ Page OutputCache VaryByParams="none" Duration="60" %>
이 페이지에 대한 출력을 한 번 효율적으로 생성한 다음 최대 60초 동안 여러 번 재사용할 수 있습니다. 이때 페이지가 다시 실행되고 출력이 ASP.NET 캐시에 다시 추가됩니다. 이 동작은 일부 하위 수준 프로그래밍 API를 사용하여 수행할 수도 있습니다. 방금 언급한 VaryByParams 속성과 같이 출력 캐싱에 대해 구성 가능한 여러 설정이 있습니다. VaryByParams는 방금 요청되었지만 HTTP GET 또는 HTTP POST 매개변수를 지정하여 캐시 항목을 변경할 수도 있습니다. 예를 들어, default.aspx?Report=1 또는 default.aspx?Report=2에 대한 출력을 캐시하려면 VaryByParam="Report"를 설정하기만 하면 됩니다. 세미콜론으로 구분된 목록을 지정하여 추가 매개변수를 지정할 수 있습니다.
많은 사람들은 출력 캐싱을 사용할 때 ASP.NET 페이지가 Microsoft Internet Security and Acceleration Server 또는 Akamai에서 사용하는 것과 같은 캐싱 서버의 다운스트림에 있는 일부 HTTP 헤더도 생성한다는 사실을 모릅니다. HTTP 캐시 헤더를 설정하면 이러한 네트워크 리소스에 문서를 캐시할 수 있으며 원본 서버로 돌아가지 않고도 클라이언트 요청을 충족할 수 있습니다.
따라서 페이지 출력 캐싱을 사용하면 응용 프로그램의 효율성이 높아지지는 않지만 다운스트림 캐싱 기술이 문서를 캐시하므로 서버의 로드가 줄어들 수 있습니다. 물론 이는 익명 콘텐츠일 수도 있습니다. 다운스트림으로 이동하면 해당 요청을 다시는 볼 수 없으며 더 이상 해당 콘텐츠에 대한 액세스를 방지하기 위한 인증을 수행할 수 없습니다.
팁 8 - IIS 6.0을 실행하세요(커널 캐싱에만 사용하세요)
IIS 6.0(Windows Server? 2003)을 실행하지 않는 경우 Microsoft 웹 서버의 뛰어난 성능 향상 기능을 놓치고 있는 것입니다. 팁 7에서는 출력 캐싱에 대해 설명했습니다. IIS 5.0에서 요청은 IIS를 거쳐 ASP.NET으로 전달됩니다. 캐싱과 관련하여 ASP.NET의 HttpModule은 요청을 수신하고 캐시 내용을 반환합니다.
IIS 6.0을 사용하는 경우 ASP.NET에 대한 코드 변경이 필요하지 않은 커널 캐시라는 멋진 작은 기능을 찾을 수 있습니다. ASP.NET에서 출력 캐싱을 요청하면 IIS 커널 캐시는 캐시된 데이터의 복사본을 받습니다. 요청이 네트워크 드라이버에서 오면 커널 수준 드라이버(컨텍스트를 사용자 모드로 전환하지 않음)가 요청을 수신하고 캐시된 데이터를 캐시된 경우 응답으로 플러시한 다음 실행을 완료합니다. 즉, IIS 및 ASP.NET 출력 캐싱과 함께 커널 모드 캐싱을 사용하면 놀라운 성능 결과를 얻을 수 있습니다. Visual Studio 2005에서 ASP.NET을 개발하는 동안 저는 ASP.NET 성능을 담당하는 프로그램 관리자였습니다. 특정 작업은 개발자가 수행하지만 저는 매일 진행되는 모든 보고를 보게 됩니다. 커널 모드 캐시 결과는 항상 가장 흥미롭습니다. 가장 일반적인 특징은 네트워크가 요청/응답으로 넘쳐나는 반면 IIS는 약 5%의 CPU 사용량으로 실행된다는 것입니다. 정말 충격적이네요! 물론 IIS 6.0을 사용하는 다른 이유도 있지만 커널 모드 캐싱이 가장 확실한 이유입니다.
팁 9 - Gzip 압축 사용
gzip을 사용하는 것이 반드시 서버 성능을 높이는 방법은 아니지만(CPU 사용량이 증가할 수 있으므로) gzip 압축을 사용하면 서버에서 전송하는 바이트 수를 줄일 수 있습니다. 이로 인해 페이지 속도가 증가하고 대역폭 사용량이 감소합니다. 전송되는 데이터, 압축 가능한 정도 및 클라이언트 브라우저의 지원 여부(IIS는 Internet Explorer 6.0 및 Firefox와 같이 gzip 압축을 지원하는 클라이언트에만 gzip 압축 콘텐츠를 보냅니다)에 따라 서버에서 서비스를 제공할 수 있습니다. 더 많은 요청. 실제로 반환되는 데이터 양을 줄일 때마다 거의 초당 요청 수가 늘어납니다.
Gzip 압축은 IIS 6.0에 내장되어 있으며 IIS 5.0에서 사용되는 gzip 압축보다 성능이 훨씬 좋습니다. 이는 좋은 소식입니다. 불행하게도 IIS 6.0에서 gzip 압축을 켜려고 하면 IIS의 속성 대화 상자에서 해당 설정을 찾지 못할 수도 있습니다. IIS 팀은 뛰어난 gzip 기능을 서버에 구축했지만 이를 활성화하기 위한 관리 UI를 포함하는 것을 잊어버렸습니다. gzip 압축을 활성화하려면 (심심해지지 않도록) IIS 6.0의 XML 구성 설정을 자세히 살펴봐야 합니다. 덧붙여서 OrcsWeb에서 호스팅되는 www.asp.net 서버에서 이 문제를 제기하는 데 도움을 준 OrcsWeb의 Scott Forsyth에게 감사의 뜻을 전합니다.
이 문서에서는 단계를 설명하지 않습니다. IIS6 압축에서 Brad Wilson의 문서를 읽어보세요. IIS에서 ASPX 압축 활성화에는 ASPX 압축 활성화에 대한 기술 자료 문서도 있습니다. 그러나 일부 구현 세부 사항으로 인해 동적 압축과 커널 캐싱은 IIS 6.0에서 동시에 존재할 수 없습니다.
팁 10 - 서버 컨트롤 뷰 상태
뷰 상태는 생성된 페이지의 숨겨진 출력 필드에 일부 상태 데이터를 저장하는 ASP.NET의 흥미로운 이름입니다. 페이지가 서버에 다시 게시되면 서버는 이 보기 상태 데이터를 구문 분석하고 유효성을 검사하고 페이지의 컨트롤 트리에 다시 적용할 수 있습니다. 상태 보기는 상태가 클라이언트에 지속되도록 하고 이 상태를 저장하는 데 쿠키나 서버 메모리가 필요하지 않기 때문에 매우 강력한 기능입니다. 많은 ASP.NET 서버 컨트롤은 뷰 상태를 사용하여 데이터 페이지를 매길 때 표시되는 현재 페이지를 저장하는 등 페이지 요소와 상호 작용하는 동안 생성된 설정을 유지합니다.
그러나 뷰 상태를 사용하는 데에는 몇 가지 단점도 있습니다. 첫째, 서비스가 제공되거나 요청될 때마다 페이지의 전체 로드가 증가합니다. 서버에 다시 게시된 뷰 상태 데이터를 직렬화하거나 역직렬화할 때도 추가 오버헤드가 발생합니다. 마지막으로 뷰 상태는 서버의 메모리 할당을 증가시킵니다.
여러 서버 컨트롤은 필요하지 않은 경우에도 뷰 상태를 과도하게 사용하는 경향이 있으며 그 중 가장 유명한 컨트롤은 DataGrid입니다. ViewState 속성의 기본 동작은 켜져 있지만 필요하지 않은 경우 컨트롤이나 페이지 수준에서 끌 수 있습니다. 컨트롤 내에서 EnableViewState 속성을 false로 설정하거나 다음 설정을 사용하여 페이지에서 전체적으로 설정합니다.
<%@ 페이지 EnableViewState="false" %>
페이지를 다시 게시하지 않거나 요청이 있을 때마다 페이지의 컨트롤을 항상 다시 생성하는 경우 페이지 수준에서 보기 상태를 비활성화해야 합니다.
고성능 ASP.NET 응용 프로그램을 작성할 때 도움이 되는 몇 가지 팁을 제공했습니다. 이 기사의 앞부분에서 언급했듯이 이것은 ASP.NET 성능에 대한 최종 설명이 아니라 예비 가이드입니다. (ASP.NET 응용 프로그램 성능 향상에 대한 자세한 내용은 ASP.NET 성능 향상을 참조하십시오.) 특정 성능 문제를 해결하는 가장 좋은 방법은 사용자의 경험을 통해서만 찾을 수 있습니다. 하지만 이러한 팁은 여행에 대한 좋은 지침이 될 것입니다. 소프트웨어 개발에는 절대적인 요소가 거의 없습니다. 모든 애플리케이션은 고유합니다.