애플리케이션 시작 시 데이터 캐싱(C#)

작성자 : Scott Mitchell

PDF 다운로드

모든 웹 애플리케이션에서 일부 데이터는 자주 사용되며 일부 데이터는 자주 사용되지 않습니다. 캐싱이라는 기술인 자주 사용되는 데이터를 미리 로드하여 ASP.NET 애플리케이션의 성능을 향상시킬 수 있습니다. 이 자습서에서는 애플리케이션 시작 시 캐시에 데이터를 로드하는 사전 로드에 대한 한 가지 방법을 보여 줍니다.

소개

이전의 두 자습서에서는 프레젠테이션 및 캐싱 계층의 캐싱 데이터를 살펴보았습니다. ObjectDataSource를 사용하여 데이터 캐싱에서 ObjectDataSource의 캐싱 기능을 사용하여 프레젠테이션 계층에서 데이터를 캐시하는 방법을 살펴보았습니다. 아키텍처의 데이터 캐싱은 별도의 새 캐싱 계층에서 캐싱을 검사했습니다. 이 두 자습서는 모두 데이터 캐시 작업에 사후 로드를 사용했습니다. 사후 로드를 사용하면 데이터가 요청 될 때마다 시스템에서 먼저 캐시에 있는지 확인합니다. 그렇지 않은 경우 데이터베이스와 같은 원래 원본에서 데이터를 잡은 다음 캐시에 저장합니다. 반응형 로드의 기본 이점은 구현의 용이성입니다. 그 단점 중 하나는 요청에서 고르지 않은 성능입니다. 이전 자습서의 캐싱 계층을 사용하여 제품 정보를 표시하는 페이지를 상상해 보십시오. 이 페이지를 처음으로 방문하거나 메모리 제약 조건 또는 지정된 만료로 인해 캐시된 데이터가 제거된 후 처음으로 방문한 경우 데이터베이스에서 데이터를 검색해야 합니다. 따라서 이러한 사용자 요청은 캐시에서 처리할 수 있는 사용자 요청보다 오래 걸립니다.

사전 로드 는 필요하기 전에 캐시된 데이터를 로드하여 요청 간에 성능을 원활하게 하는 대체 캐시 관리 전략을 제공합니다. 일반적으로 자동 관리 로드는 기본 데이터에 대한 업데이트가 있을 때 주기적으로 확인하거나 알림을 수신하는 일부 프로세스를 사용합니다. 그런 다음 이 프로세스는 캐시를 최신 상태로 유지하도록 업데이트합니다. 자동 관리 로드는 기본 데이터가 느린 데이터베이스 연결, 웹 서비스 또는 기타 특히 느린 데이터 원본에서 오는 경우에 특히 유용합니다. 그러나 자동 관리 로드에 대한 이 방법은 변경 내용을 검사 캐시를 업데이트하는 프로세스를 만들고 관리하고 배포해야 하므로 구현하기가 더 어렵습니다.

자동 관리 로드의 또 다른 특징과 이 자습서에서 살펴볼 형식은 애플리케이션 시작 시 캐시에 데이터를 로드하는 것입니다. 이 방법은 데이터베이스 조회 테이블의 레코드와 같은 정적 데이터를 캐싱하는 데 특히 유용합니다.

참고

사전 및 사후 로드의 차이점과 장단점 및 구현 권장 사항 목록은 .NET Framework 애플리케이션에 대한 캐싱 아키텍처 가이드의 캐시 내용 관리 섹션을 참조하세요.

1단계: 애플리케이션 시작 시 캐시할 데이터 결정

이전 두 자습서에서 검사한 반응형 로드를 사용하는 캐싱 예제는 주기적으로 변경될 수 있고 생성하는 데 매우 오래 걸리지 않는 데이터와 잘 작동합니다. 그러나 캐시된 데이터가 변경되지 않는 경우 사후 로드에 사용되는 만료는 불필요합니다. 마찬가지로 캐시되는 데이터를 생성하는 데 시간이 매우 오래 걸리는 경우 요청이 비어 있는 캐시를 찾는 사용자는 기본 데이터가 검색되는 동안 긴 대기 시간을 견뎌야 합니다. 애플리케이션 시작 시 생성하는 데 매우 오랜 시간이 걸리는 정적 데이터 및 데이터를 캐싱하는 것이 좋습니다.

데이터베이스에는 동적이고 자주 변경되는 값이 많지만 대부분은 정적 데이터의 양이 상당히 많습니다. 예를 들어 거의 모든 데이터 모델에는 고정된 선택 집합의 특정 값을 포함하는 하나 이상의 열이 있습니다. Patients 데이터베이스 테이블에는 PrimaryLanguage 영어, 스페인어, 프랑스어, 러시아어, 일본어 등의 값 집합이 있는 열이 있을 수 있습니다. 종종 이러한 유형의 열은 조회 테이블을 사용하여 구현됩니다. 테이블에 영어 또는 프랑스어 Patients 문자열을 저장하는 대신 두 번째 테이블이 만들어집니다. 일반적으로 두 개의 열(고유 식별자 및 문자열 설명)과 가능한 각 값에 대한 레코드가 있습니다. 테이블의 Patients 열은 PrimaryLanguage 해당 고유 식별자를 조회 테이블에 저장합니다. 그림 1에서 환자 John Doe의 기본 언어는 영어이고 에드 존슨은 러시아어입니다.

언어 테이블은 환자 테이블에서 사용하는 조회 테이블입니다.

그림 1: 테이블은 Languages 테이블에서 사용하는 Patients 조회 테이블입니다.

새 환자를 편집하거나 만들기 위한 사용자 인터페이스에는 테이블의 레코드 Languages 로 채워진 허용 가능한 언어의 드롭다운 목록이 포함됩니다. 캐싱이 없으면 이 인터페이스를 방문할 때마다 시스템에서 테이블을 쿼리 Languages 해야 합니다. 조회 테이블 값이 매우 드물게 변경되므로 이는 낭비되고 불필요합니다.

이전 자습서에서 Languages 검사한 것과 동일한 반응형 로드 기술을 사용하여 데이터를 캐시할 수 있습니다. 그러나 반응형 로드는 정적 조회 테이블 데이터에 필요하지 않은 시간 기반 만료를 사용합니다. 사후 로드를 사용하여 캐싱하는 것이 캐싱이 전혀 캐싱하지 않는 것보다 낫지만, 가장 좋은 방법은 애플리케이션 시작 시 조회 테이블 데이터를 캐시에 사전에 로드하는 것입니다.

이 자습서에서는 조회 테이블 데이터 및 기타 정적 정보를 캐시하는 방법을 살펴보겠습니다.

2단계: 데이터를 캐시하는 다양한 방법 검사

다양한 방법을 사용하여 ASP.NET 애플리케이션에서 프로그래밍 방식으로 정보를 캐시할 수 있습니다. 이전 자습서에서 데이터 캐시를 사용하는 방법을 이미 살펴보았습니다. 또는 정적 멤버 또는 애플리케이션 상태를 사용하여 프로그래밍 방식으로 개체를 캐시할 수 있습니다.

클래스를 사용하는 경우 일반적으로 클래스에 액세스하려면 먼저 클래스를 인스턴스화해야 합니다. 예를 들어 비즈니스 논리 계층의 클래스 중 하나에서 메서드를 호출하려면 먼저 클래스의 instance 만들어야 합니다.

ProductsBLL productsAPI = new ProductsBLL();
productsAPI.SomeMethod();
productsAPI.SomeProperty = "Hello, World!";

SomeMethod를 호출하거나 SomeProperty로 작업하려면 먼저 키워드(keyword) 사용하여 new 클래스의 instance 만들어야 합니다. SomeMethodSomeProperty는 특정 instance 연결됩니다. 이러한 멤버의 수명은 연결된 개체의 수명에 연결됩니다. 반면에 정적 멤버는 클래스의 모든 인스턴스 간에 공유되는 변수, 속성 및 메서드이며, 따라서 클래스만큼 수명이 있습니다. 정적 멤버는 키워드(keyword) static로 표시됩니다.

정적 멤버 외에도 애플리케이션 상태를 사용하여 데이터를 캐시할 수 있습니다. 각 ASP.NET 애플리케이션은 애플리케이션의 모든 사용자 및 페이지에서 공유되는 이름/값 컬렉션을 유지 관리합니다. 이 컬렉션은 클래스의 Application 속성을 사용하여 HttpContext액세스할 수 있으며 다음과 같이 ASP.NET 페이지의 코드 숨김 클래스에서 사용할 수 있습니다.

Application["key"] = value;
object value = Application["key"];

데이터 캐시는 데이터 캐싱을 위한 훨씬 더 풍부한 API를 제공하여 시간 및 종속성 기반 만료, 캐시 항목 우선 순위 등에 대한 메커니즘을 제공합니다. 정적 멤버 및 애플리케이션 상태를 사용하면 페이지 개발자가 이러한 기능을 수동으로 추가해야 합니다. 그러나 애플리케이션 시작 시 애플리케이션의 수명 동안 데이터를 캐싱할 때 데이터 캐시의 장점은 moot입니다. 이 자습서에서는 정적 데이터를 캐싱하는 세 가지 기술을 모두 사용하는 코드를 살펴보겠습니다.

3단계: 테이블 데이터 캐싱Suppliers

지금까지 구현한 Northwind 데이터베이스 테이블에는 기존 조회 테이블이 포함되지 않습니다. 값이 비정적인 DAL 모든 모델 테이블에 구현된 4개의 DataTable입니다. 이 자습서에서는 DAL에 새 DataTable을 추가한 다음 새 클래스 및 메서드를 BLL에 추가하는 데 시간을 할애하는 대신 테이블의 데이터가 정적인 것처럼 가장 Suppliers 해 보겠습니다. 따라서 애플리케이션 시작 시 이 데이터를 캐시할 수 있습니다.

시작하려면 폴더에 라는 StaticCache.cs 새 클래스를 CL 만듭니다.

CL 폴더에 StaticCache.cs 클래스 만들기

그림 2: 폴더에 StaticCache.csCL 클래스 만들기

시작 시 데이터를 적절한 캐시 저장소에 로드하는 메서드와 이 캐시에서 데이터를 반환하는 메서드를 추가해야 합니다.

[System.ComponentModel.DataObject]
public class StaticCache
{
    private static Northwind.SuppliersDataTable suppliers = null;
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using a static member variable
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        suppliers = suppliersBLL.GetSuppliers();
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return suppliers;
    }
}

위의 코드는 정적 멤버 변수 를 suppliers사용하여 메서드에서 SuppliersBLL 호출 LoadStaticCache() 되는 클래스의 GetSuppliers() 메서드 결과를 저장합니다. LoadStaticCache() 메서드는 애플리케이션을 시작하는 동안 호출됩니다. 애플리케이션 시작 시 이 데이터가 로드되면 공급자 데이터로 작업해야 하는 모든 페이지에서 클래스의 GetSuppliers() 메서드를 호출할 StaticCache 수 있습니다. 따라서 공급자를 가져오기 위한 데이터베이스 호출은 애플리케이션 시작 시 한 번만 발생합니다.

정적 멤버 변수를 캐시 저장소로 사용하는 대신 애플리케이션 상태 또는 데이터 캐시를 사용할 수 있습니다. 다음 코드는 애플리케이션 상태를 사용하도록 다시 학습된 클래스를 보여줍니다.

[System.ComponentModel.DataObject]
public class StaticCache
{
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using application state
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        HttpContext.Current.Application["key"] = suppliersBLL.GetSuppliers();
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return HttpContext.Current.Application["key"] as Northwind.SuppliersDataTable;
    }
}

에서 LoadStaticCache()공급자 정보는 애플리케이션 변수 에 저장됩니다. 에서 적절한 형식(Northwind.SuppliersDataTable) GetSuppliers()으로 반환됩니다. 를 사용하여 Application["key"]ASP.NET 페이지의 코드 숨김 클래스에서 애플리케이션 상태에 액세스할 수 있지만 아키텍처에서 현재 HttpContext를 가져오기 위해 사용해야 HttpContext.Current.Application["key"] 합니다.

마찬가지로 다음 코드와 같이 데이터 캐시를 캐시 저장소로 사용할 수 있습니다.

[System.ComponentModel.DataObject]
public class StaticCache
{
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using the data cache
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        HttpRuntime.Cache.Insert(
          /* key */                "key", 
          /* value */              suppliers, 
          /* dependencies */       null, 
          /* absoluteExpiration */ Cache.NoAbsoluteExpiration, 
          /* slidingExpiration */  Cache.NoSlidingExpiration, 
          /* priority */           CacheItemPriority.NotRemovable, 
          /* onRemoveCallback */   null);
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return HttpRuntime.Cache["key"] as Northwind.SuppliersDataTable;
    }
}

시간 기반 만료 없이 데이터 캐시에 항목을 추가하려면 및 System.Web.Caching.Cache.NoSlidingExpiration 값을 입력 매개 변수로 사용합니다System.Web.Caching.Cache.NoAbsoluteExpiration. 캐시 항목의 우선 순위를 지정할 수 있도록 데이터 캐시 메서드의 Insert 이 특정 오버로드가 선택되었습니다. 우선 순위는 사용 가능한 메모리가 부족할 때 캐시에서 청소할 항목을 결정하는 데 사용됩니다. 여기서는 이 NotRemovable캐시 항목이 청소되지 않도록 하는 우선 순위 를 사용합니다.

참고

이 자습서의 다운로드는 StaticCache 정적 멤버 변수 접근 방식을 사용하여 클래스를 구현합니다. 애플리케이션 상태 및 데이터 캐시 기술에 대한 코드는 클래스 파일의 주석에서 사용할 수 있습니다.

4단계: 애플리케이션 시작 시 코드 실행

웹 애플리케이션이 처음 시작될 때 코드를 실행하려면 라는 Global.asax특수 파일을 만들어야 합니다. 이 파일에는 애플리케이션, 세션 및 요청 수준 이벤트에 대한 이벤트 처리기가 포함될 수 있으며 애플리케이션이 시작될 때마다 실행될 코드를 추가할 수 있습니다.

Visual Studio의 Global.asax 솔루션 탐색기 웹 사이트 프로젝트 이름을 마우스 오른쪽 단추로 클릭하고 새 항목 추가를 선택하여 웹 애플리케이션의 루트 디렉터리에 파일을 추가합니다. 새 항목 추가 대화 상자에서 전역 애플리케이션 클래스 항목 유형을 선택한 다음 추가 단추를 클릭합니다.

참고

프로젝트에 파일이 이미 Global.asax 있는 경우 전역 애플리케이션 클래스 항목 유형이 새 항목 추가 대화 상자에 나열되지 않습니다.

웹 애플리케이션의 루트 디렉터리에 Global.asax 파일 추가

그림 3: 웹 애플리케이션의 루트 디렉터리에 파일 추가 Global.asax (전체 크기 이미지를 보려면 클릭)

기본 Global.asax 파일 템플릿에는 서버 쪽 <script> 태그 내에 다음 5개의 메서드가 포함됩니다.

  • Application_Start 는 웹 애플리케이션이 처음 시작될 때 실행됩니다.
  • Application_End 는 애플리케이션이 종료되는 경우 실행됩니다.
  • Application_Error 는 처리되지 않은 예외가 애플리케이션에 도달할 때마다 실행됩니다.
  • Session_Start 은 새 세션을 만들 때 실행됩니다.
  • Session_End 는 세션이 만료되거나 중단되었을 때 실행됩니다.

Application_Start 이벤트 처리기는 애플리케이션의 수명 주기 동안 한 번만 호출됩니다. 애플리케이션은 애플리케이션에서 ASP.NET 리소스가 처음 요청될 때 시작되며 애플리케이션이 다시 시작될 때까지 계속 실행되며, 이는 폴더의 내용을 수정하거나, 폴더의 /Bin 내용을 App_Code 수정Global.asax하거나, 파일을 수정하는 Web.config 등의 다른 원인 중에서 발생할 수 있습니다. 애플리케이션 수명 주기에 대한 자세한 내용은 ASP.NET 애플리케이션 수명 주기 개요를 참조하세요.

이러한 자습서에서는 메서드에 코드를 Application_Start 추가하기만 하면 되므로 다른 자습서를 자유롭게 제거할 수 있습니다. 에서 Application_Start공급자 정보를 로드하고 캐시하는 클래스의 LoadStaticCache() 메서드를 호출 StaticCache 하기만 하면 됩니다.

<%@ Application Language="C#" %>
<script runat="server">
    void Application_Start(object sender, EventArgs e) 
    {
        StaticCache.LoadStaticCache();
    }
</script>

이제 모든 작업을 마쳤습니다. 애플리케이션 시작 시 메서드는 LoadStaticCache() BLL에서 공급자 정보를 잡고 정적 멤버 변수(또는 클래스에서 사용한 캐시 저장소)에 StaticCache 저장합니다. 이 동작을 확인하려면 메서드에서 중단점을 설정하고 애플리케이션을 Application_Start 실행합니다. 중단점이 애플리케이션 시작 시 적중됩니다. 그러나 후속 요청으로 인해 메서드가 Application_Start 실행되지는 않습니다.

중단점을 사용하여 Application_Start 이벤트 처리기가 실행되고 있는지 확인

그림 4: 중단점을 사용하여 이벤트 처리기가 실행되고 있는지 Application_Start 확인합니다(전체 크기 이미지를 보려면 클릭).

참고

디버깅을 Application_Start 처음 시작할 때 중단점에 도달하지 않으면 애플리케이션이 이미 시작되었기 때문입니다. 또는 Web.config 파일을 수정하여 애플리케이션을 강제로 다시 시작한 다음 다시 시도합니다Global.asax. 이러한 파일 중 하나의 끝에 빈 줄을 추가(또는 제거)하여 애플리케이션을 빠르게 다시 시작할 수 있습니다.

5단계: 캐시된 데이터 표시

이 시점에서 StaticCache 클래스에는 메서드를 통해 액세스할 수 있는 애플리케이션 시작 시 캐시된 공급자 데이터의 버전이 GetSuppliers() 있습니다. 프레젠테이션 계층에서 이 데이터를 사용하려면 ObjectDataSource를 사용하거나 프로그래밍 방식으로 ASP.NET 페이지의 코드 숨김 클래스에서 클래스 GetSuppliers() 의 메서드를 호출 StaticCache 할 수 있습니다. ObjectDataSource 및 GridView 컨트롤을 사용하여 캐시된 공급자 정보를 표시하는 방법을 살펴보겠습니다.

먼저 폴더에서 AtApplicationStartup.aspxCaching 페이지를 엽니다. 도구 상자에서 디자이너로 GridView를 끌어 속성을 IDSuppliers설정합니다. 다음으로 GridView의 스마트 태그에서 라는 SuppliersCachedDataSource새 ObjectDataSource를 만들도록 선택합니다. 클래스 GetSuppliers() 의 메서드를 사용하도록 ObjectDataSource를 StaticCache 구성합니다.

StaticCache 클래스를 사용하도록 ObjectDataSource 구성

그림 5: 클래스를 사용하도록 StaticCache ObjectDataSource 구성(전체 크기 이미지를 보려면 클릭)

GetSuppliers() 메서드를 사용하여 캐시된 공급업체 데이터 검색

그림 6: 메서드를 GetSuppliers() 사용하여 캐시된 공급업체 데이터 검색(전체 크기 이미지를 보려면 클릭)

마법사를 완료한 후 Visual Studio는 의 각 데이터 필드에 SuppliersDataTable대해 BoundFields를 자동으로 추가합니다. GridView 및 ObjectDataSource의 선언적 태그는 다음과 유사합니다.

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="SupplierID" DataSourceID="SuppliersCachedDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CompanyName" HeaderText="CompanyName" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="Address" HeaderText="Address" 
            SortExpression="Address" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
        <asp:BoundField DataField="Phone" HeaderText="Phone" 
            SortExpression="Phone" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersCachedDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="StaticCache" />

그림 7은 브라우저를 통해 볼 때 페이지를 보여줍니다. 출력은 BLL의 SuppliersBLL 클래스에서 데이터를 가져왔을 때와 동일하지만 클래스를 StaticCache 사용하면 애플리케이션 시작 시 캐시된 공급자 데이터가 반환됩니다. 클래스의 GetSuppliers() 메서드에서 StaticCache 중단점을 설정하여 이 동작을 확인할 수 있습니다.

캐시된 공급자 데이터가 GridView에 표시됩니다.

그림 7: 캐시된 공급업체 데이터가 GridView에 표시됩니다(전체 크기 이미지를 보려면 클릭).

요약

대부분의 모든 데이터 모델에는 일반적으로 조회 테이블 형식으로 구현되는 상당한 양의 정적 데이터가 포함되어 있습니다. 이 정보는 정적이므로 이 정보를 표시해야 할 때마다 데이터베이스에 지속적으로 액세스할 이유가 없습니다. 또한 정적 특성으로 인해 데이터를 캐싱할 때 만료가 필요하지 않습니다. 이 자습서에서는 이러한 데이터를 가져와서 데이터 캐시, 애플리케이션 상태 및 정적 멤버 변수를 통해 캐시하는 방법을 알아보았습니다. 이 정보는 애플리케이션 시작 시 캐시되며 애플리케이션 수명 동안 캐시에 유지됩니다.

이 자습서와 지난 두 가지에서는 애플리케이션 수명 기간 동안 데이터를 캐싱하고 시간 기반 만료를 사용하는 방법에 대해 살펴보았습니다. 그러나 데이터베이스 데이터를 캐싱할 때 시간 기반 만료가 이상적이지 않을 수 있습니다. 캐시를 주기적으로 플러시하는 대신 기본 데이터베이스 데이터가 수정될 때만 캐시된 항목을 제거할 수 있습니다. 이 이상적인 방법은 SQL 캐시 종속성을 사용하여 가능하며, 다음 자습서에서 살펴보겠습니다.

행복한 프로그래밍!

저자 정보

7개의 ASP/ASP.NET 책의 저자이자 4GuysFromRolla.com 창립자인 Scott Mitchell은 1998년부터 Microsoft 웹 기술로 작업해 왔습니다. Scott은 독립 컨설턴트, 트레이너 및 작가로 일합니다. 그의 최신 책은 샘스 티치 유어셀프 ASP.NET 24시간 만에 2.0입니다. 그는 에서mitchell@4GuysFromRolla.com 또는 에서 찾을 http://ScottOnWriting.NET수있는 자신의 블로그를 통해 도달 할 수 있습니다.

특별 감사

이 자습서 시리즈는 많은 유용한 검토자가 검토했습니다. 이 자습서의 수석 검토자는 테레사 머피와 잭 존스였습니다. 예정된 MSDN 문서를 검토하는 데 관심이 있으신가요? 그렇다면 에 줄을 놓습니다 mitchell@4GuysFromRolla.com.