출력 캐싱을 통한 성능 향상(C#)Improving Performance with Output Caching (C#)

로 마이크로 소프트by Microsoft

이 자습서에서는 출력 캐싱을 활용하여 ASP.NET MVC 웹 응용 프로그램의 성능을 크게 향상시킬 수 있는 방법을 알아봅니다.In this tutorial, you learn how you can dramatically improve the performance of your ASP.NET MVC web applications by taking advantage of output caching. 컨트롤러 작업에서 반환된 결과를 캐시하여 새 사용자가 작업을 호출할 때마다 동일한 콘텐츠를 만들 필요가 없도록 하는 방법을 알아봅니다.You learn how to cache the result returned from a controller action so that the same content does not need to be created each and every time a new user invokes the action.

이 자습서의 목표는 출력 캐시를 활용하여 ASP.NET MVC 응용 프로그램의 성능을 크게 향상시킬 수 있는 방법을 설명하는 것입니다.The goal of this tutorial is to explain how you can dramatically improve the performance of an ASP.NET MVC application by taking advantage of the output cache. 출력 캐시를 사용하면 컨트롤러 작업에서 반환되는 콘텐츠를 캐시할 수 있습니다.The output cache enables you to cache the content returned by a controller action. 이렇게 하면 동일한 컨트롤러 작업이 호출될 때마다 동일한 콘텐츠를 생성할 필요가 없습니다.That way, the same content does not need to be generated each and every time the same controller action is invoked.

예를 들어 ASP.NET MVC 응용 프로그램이 Index라는 보기의 데이터베이스 레코드 목록을 표시한다고 가정해 보겠습니다.Imagine, for example, that your ASP.NET MVC application displays a list of database records in a view named Index. 일반적으로 사용자가 Index 뷰를 반환하는 컨트롤러 작업을 호출할 때마다 데이터베이스 쿼리를 실행하여 데이터베이스 레코드 집합을 데이터베이스에서 검색해야 합니다.Normally, each and every time that a user invokes the controller action that returns the Index view, the set of database records must be retrieved from the database by executing a database query.

반면에 출력 캐시를 활용하면 사용자가 동일한 컨트롤러 작업을 호출할 때마다 데이터베이스 쿼리를 실행하지 않을 수 있습니다.If, on the other hand, you take advantage of the output cache then you can avoid executing a database query every time any user invokes the same controller action. 컨트롤러 작업에서 재생성되는 대신 캐시에서 뷰를 검색할 수 있습니다.The view can be retrieved from the cache instead of being regenerated from the controller action. 캐싱을 사용하면 서버에서 중복 작업을 수행하지 않도록 할 수 있습니다.Caching enables you to avoid performing redundant work on the server.

출력 캐싱 사용Enabling Output Caching

개별 컨트롤러 작업 또는 전체 컨트롤러 클래스에 [OutputCache] 특성을 추가하여 출력 캐싱을 사용하도록 설정합니다.You enable output caching by adding an [OutputCache] attribute to either an individual controller action or an entire controller class. 예를 들어 목록 1의 컨트롤러는 Index()라는 작업을 노출합니다.For example, the controller in Listing 1 exposes an action named Index(). Index() 작업의 출력은 10초 동안 캐시됩니다.The output of the Index() action is cached for 10 seconds.

목록 1 – 컨트롤러\HomeController.csListing 1 – Controllers\HomeController.cs

using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        [OutputCache(Duration=10, VaryByParam="none")]
        public ActionResult Index()
        {
            return View();
        }
    }
}

ASP.NET MVC의 베타 버전에서는 출력 캐싱이 와 같은 http://www.MySite.com/URL에 대해 작동하지 않습니다.In the Beta versions of ASP.NET MVC, output caching does not work for a URL like http://www.MySite.com/. 대신 에 대한 http://www.MySite.com/Home/IndexURL을 입력해야 합니다.Instead, you must enter a URL like http://www.MySite.com/Home/Index.

목록 1에서 Index() 작업의 출력은 10초 동안 캐시됩니다.In Listing 1, the output of the Index() action is cached for 10 seconds. 원하는 경우 훨씬 더 긴 캐시 기간을 지정할 수 있습니다.If you prefer, you can specify a much longer cache duration. 예를 들어 컨트롤러 작업의 출력을 하루 동안 캐시하려는 경우 86400초(60초 * 60분 * 24시간)의 캐시 기간을 지정할 수 있습니다.For example, if you want to cache the output of a controller action for one day then you can specify a cache duration of 86400 seconds (60 seconds * 60 minutes * 24 hours).

지정한 시간 동안 콘텐츠가 캐시된다는 보장은 없습니다.There is no guarantee that content will be cached for the amount of time that you specify. 메모리 리소스가 부족해지면 캐시가 자동으로 콘텐츠를 제거하기 시작합니다.When memory resources become low, the cache starts evicting content automatically.

목록 1의 홈 컨트롤러는 목록 2의 인덱스 보기를 반환합니다.The Home controller in Listing 1 returns the Index view in Listing 2. 이 보기에 대해 특별한 것은 없습니다.There is nothing special about this view. 색인 보기에는 단순히 현재 시간이 표시됩니다(그림 1 참조).The Index view simply displays the current time (see Figure 1).

목록 2 – 보기\홈\인덱스.aspxListing 2 – Views\Home\Index.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Index</title>
</head>
<body>
    <div>
    
    The current time is: <%= DateTime.Now.ToString("T") %>
    
    
    </div>
</body>
</html>

그림 1 – 캐시된 인덱스 보기Figure 1 – Cached Index view

clip_image002

브라우저의 주소 표시줄에 URL /Home/Index를 입력하고 브라우저에서 새로 고침/다시로드 버튼을 반복적으로 눌러 Index() 작업을 여러 번 호출하면 인덱스 보기에 표시되는 시간이 10초 동안 변경되지 않습니다.If you invoke the Index() action multiple times by entering the URL /Home/Index in the address bar of your browser and hitting the Refresh/Reload button in your browser repeatedly, then the time displayed by the Index view won't change for 10 seconds. 뷰가 캐시되므로 동시에 표시됩니다.The same time is displayed because the view is cached.

응용 프로그램을 방문하는 모든 사람에게 동일한 보기가 캐시된다는 점을 이해하는 것이 중요합니다.It is important to understand that the same view is cached for everyone who visits your application. Index() 작업을 호출하는 모든 사용자는 인덱스 보기의 캐시된 버전과 동일한 캐시된 버전을 받게 됩니다.Anyone who invokes the Index() action will get the same cached version of the Index view. 즉, 인덱스 보기를 제공하기 위해 웹 서버가 수행해야 하는 작업량이 크게 줄어듭니다.This means that the amount of work that the web server must perform to serve the Index view is dramatically reduced.

목록 2의 보기는 정말 간단한 일을하는 일이.The view in Listing 2 happens to be doing something really simple. 뷰에 현재 시간이 표시됩니다.The view just displays the current time. 그러나 데이터베이스 레코드 집합을 표시하는 뷰를 쉽게 캐시할 수 있습니다.However, you could just as easily cache a view that displays a set of database records. 이 경우 뷰를 반환하는 컨트롤러 작업이 호출될 때마다 데이터베이스 레코드 집합을 데이터베이스에서 검색할 필요가 없습니다.In that case, the set of database records would not need to be retrieved from the database each and every time the controller action that returns the view is invoked. 캐싱을 사용하면 웹 서버와 데이터베이스 서버가 모두 수행해야 하는 작업량을 줄일 수 있습니다.Caching can reduce the amount of work that both your web server and database server must perform.

MVC 보기에서 <페이지 %@> OutputCache % 지시문을 사용하지 마십시오.Don't use the page <%@ OutputCache %> directive in an MVC view. 이 지시문은 Web Forms 세계에서 흘러넘치며 ASP.NET MVC 응용 프로그램에서 사용해서는 안 됩니다.This directive is bleeding over from the Web Forms world and should not be used in an ASP.NET MVC application.

콘텐츠가 캐시되는 위치Where Content is Cached

기본적으로 [OutputCache] 특성을 사용하면 콘텐츠가 웹 서버, 프록시 서버 및 웹 브라우저의 세 위치에 캐시됩니다.By default, when you use the [OutputCache] attribute, content is cached in three locations: the web server, any proxy servers, and the web browser. [OutputCache] 특성의 위치 속성을 수정하여 콘텐츠가 캐시되는 위치를 정확하게 제어할 수 있습니다.You can control exactly where content is cached by modifying the Location property of the [OutputCache] attribute.

위치 속성을 다음 값 중 하나로 설정할 수 있습니다.You can set the Location property to any one of the following values:

· 어떤· Any

· 클라이언트· Client

· 다운스트림· Downstream

· 서버· Server

· 없음· None

· 서버앤클라이언트· ServerAndClient

기본적으로 Location 속성에는 Any 값이 있습니다.By default, the Location property has the value Any. 그러나 브라우저에서만 캐시하거나 서버에서만 캐시하려는 상황이 있습니다.However, there are situations in which you might want to cache only on the browser or only on the server. 예를 들어 각 사용자에 대해 개인 설정된 정보를 캐싱하는 경우 서버의 정보를 캐시해서는 안 됩니다.For example, if you are caching information that is personalized for each user then you should not cache the information on the server. 다른 사용자에게 다른 정보를 표시하는 경우 클라이언트에서만 정보를 캐시해야 합니다.If you are displaying different information to different users then you should cache the information only on the client.

예를 들어 목록 3의 컨트롤러는 현재 사용자 이름을 반환하는 GetName() 이라는 작업을 노출합니다.For example, the controller in Listing 3 exposes an action named GetName() that returns the current user name. 잭이 웹 사이트에 로그인하여 GetName() 작업을 호출하면 작업이 "Hi Jack"문자열을 반환합니다.If Jack logs into the website and invokes the GetName() action then the action returns the string "Hi Jack". 그 후 Jill이 웹 사이트에 로그인하여 GetName() 작업을 호출하면 "Hi Jack"이라는 문자열도 받게 됩니다.If, subsequently, Jill logs into the website and invokes the GetName() action then she also will get the string "Hi Jack". Jack이 처음에 컨트롤러 작업을 호출한 후 모든 사용자에 대해 문자열이 웹 서버에 캐시됩니다.The string is cached on the web server for all users after Jack initially invokes the controller action.

목록 3 – 컨트롤러\BadUserController.csListing 3 – Controllers\BadUserController.cs

using System.Web.Mvc;
using System.Web.UI;

namespace MvcApplication1.Controllers
{
    public class BadUserController : Controller
    {
        [OutputCache(Duration = 3600, VaryByParam = "none")]
        public string GetName()
        {
            return "Hi " + User.Identity.Name;
        }
    }
}

대부분의 경우 목록 3의 컨트롤러가 원하는 방식으로 작동하지 않습니다.Most likely, the controller in Listing 3 does not work the way that you want. Jill에 "Hi Jack"이라는 메시지를 표시하고 싶지 는 않습니다.You don't want to display the message "Hi Jack" to Jill.

서버 캐시에서 개인 설정된 콘텐츠를 캐시해서는 안 됩니다.You should never cache personalized content in the server cache. 그러나 성능을 향상시키기 위해 브라우저 캐시에서 개인 설정된 콘텐츠를 캐시할 수 있습니다.However, you might want to cache the personalized content in the browser cache to improve performance. 브라우저에서 콘텐츠를 캐시하고 사용자가 동일한 컨트롤러 작업을 여러 번 호출하면 서버 대신 브라우저 캐시에서 콘텐츠를 검색할 수 있습니다.If you cache content in the browser, and a user invokes the same controller action multiple times, then the content can be retrieved from the browser cache instead of the server.

목록 4의 수정된 컨트롤러는 GetName() 작업의 출력을 캐시합니다.The modified controller in Listing 4 caches the output of the GetName() action. 그러나 콘텐츠는 서버가 아닌 브라우저에서만 캐시됩니다.However, the content is cached only on the browser and not on the server. 이렇게 하면 여러 사용자가 GetName() 메서드를 호출할 때 각 사용자는 다른 사용자의 사용자 이름이 아닌 자신의 사용자 이름을 가져옵니다.That way, when multiple users invoke the GetName() method, each person gets their own user name and not another person's user name.

목록 4 – 컨트롤러\UserController.csListing 4 – Controllers\UserController.cs

using System.Web.Mvc;
using System.Web.UI;

namespace MvcApplication1.Controllers
{
    public class UserController : Controller
    {
        [OutputCache(Duration=3600, VaryByParam="none", Location=OutputCacheLocation.Client, NoStore=true)]
        public string GetName()
        {
            return "Hi " + User.Identity.Name;
        }
    }
}

목록 4의 [OutputCache] 특성에는 ValueCacheLocation.Client 값으로 설정된 위치 속성이 포함되어 있습니다.Notice that the [OutputCache] attribute in Listing 4 includes a Location property set to the value OutputCacheLocation.Client. [OutputCache] 특성에는 NoStore 속성도 포함됩니다.The [OutputCache] attribute also includes a NoStore property. NoStore 속성은 프록시 서버와 브라우저에 캐시된 콘텐츠의 영구 복사본을 저장하지 않도록 알리는 데 사용됩니다.The NoStore property is used to inform proxy servers and browser that they should not store a permanent copy of the cached content.

출력 캐시 변경Varying the Output Cache

경우에 따라 동일한 콘텐츠의 다른 캐시 된 버전을 원할 수 있습니다.In some situations, you might want different cached versions of the very same content. 예를 들어 마스터/세부 정보 페이지를 만드는 경우를 가정해 보겠습니다.Imagine, for example, that you are creating a master/detail page. 마스터 페이지에는 영화 제목 목록이 표시됩니다.The master page displays a list of movie titles. 제목을 클릭하면 선택한 동영상에 대한 세부 정보가 표시됩니다.When you click a title, you get details for the selected movie.

세부 정보 페이지를 캐시하면 클릭한 동영상에 관계없이 동일한 동영상에 대한 세부 정보가 표시됩니다.If you cache the details page, then the details for the same movie will be displayed no matter which movie you click. 첫 번째 사용자가 선택한 첫 번째 동영상이 모든 향후 사용자에게 표시됩니다.The first movie selected by the first user will be displayed to all future users.

[OutputCache] 특성의 VaryByParam 속성을 활용하여 이 문제를 해결할 수 있습니다.You can fix this problem by taking advantage of the VaryByParam property of the [OutputCache] attribute. 이 속성을 사용하면 양식 매개 변수 또는 쿼리 문자열 매개 변수가 다를 때 동일한 콘텐츠의 다른 캐시된 버전을 만들 수 있습니다.This property enables you to create different cached versions of the very same content when a form parameter or query string parameter varies.

예를 들어 목록 5의 컨트롤러는 Master() 및 Details()라는 두 개의 작업을 노출합니다.For example, the controller in Listing 5 exposes two actions named Master() and Details(). 마스터() 작업은 동영상 제목 목록을 반환하고 세부 정보() 작업은 선택한 동영상에 대한 세부 정보를 반환합니다.The Master() action returns a list of movie titles and the Details() action returns the details for the selected movie.

목록 5 – 컨트롤러\영화Controller.csListing 5 – Controllers\MoviesController.cs

using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{
    public class MoviesController : Controller
    {
        private MovieDataContext _dataContext;

        public MoviesController()
        {
            _dataContext = new MovieDataContext();
        }

        [OutputCache(Duration=int.MaxValue, VaryByParam="none")]
        public ActionResult Master()
        {
            ViewData.Model = (from m in _dataContext.Movies 
                              select m).ToList();
            return View();
        }

        [OutputCache(Duration = int.MaxValue, VaryByParam = "id")]
        public ActionResult Details(int id)
        {
            ViewData.Model = _dataContext.Movies.SingleOrDefault(m => m.Id == id);
            return View();
        }


    }
}

마스터() 작업에는 값이 "none"인 VaryByParam 속성이 포함됩니다.The Master() action includes a VaryByParam property with the value "none". Master() 작업이 호출되면 동일한 캐시된 버전의 마스터 뷰가 반환됩니다.When the Master() action is invoked, the same cached version of the Master view is returned. 모든 양식 매개 변수 또는 쿼리 문자열 매개 변수는 무시됩니다(그림 2 참조).Any form parameters or query string parameters are ignored (see Figure 2).

그림 2 – /영화/마스터 보기Figure 2 – The /Movies/Master view

clip_image004

그림 3 – /영화/세부 정보 보기Figure 3 – The /Movies/Details view

clip_image006

세부 정보() 작업에는 값 "Id"가 있는 VaryByParam 속성이 포함됩니다.The Details() action includes a VaryByParam property with the value "Id". Id 매개 변수의 다른 값이 컨트롤러 작업에 전달되면 세부 정보 보기의 다른 캐시된 버전이 생성됩니다.When different values of the Id parameter are passed to the controller action, different cached versions of the Details view are generated.

VarByParam 속성을 사용하면 캐싱이 더 많아지고 더 적지 않다는 것을 이해하는 것이 중요합니다.It is important to understand that using the VaryByParam property results in more caching and not less. 세부 정보 보기의 다른 캐시된 버전이 Id 매개 변수의 각 다른 버전에 대해 만들어집니다.A different cached version of the Details view is created for each different version of the Id parameter.

[바바이파라임] 속성을 다음 값으로 설정할 수 있습니다.You can set the VaryByParam property to the following values:

*= 양식 또는 쿼리 문자열 매개 변수가 다를 때마다 다른 캐시된 버전을 만듭니다.* = Create a different cached version whenever a form or query string parameter varies.

없음 = 다른 캐시된 버전을 만들지 마십시오.none = Never create different cached versions

세미콜론 매개 변수 목록 = 목록의 양식 또는 쿼리 문자열 매개 변수가 다를 때마다 다른 캐시된 버전 만들기Semicolon list of parameters = Create different cached versions whenever any of the form or query string parameters in the list varies

캐시 프로필 만들기Creating a Cache Profile

[OutputCache] 특성의 속성을 수정하여 출력 캐시 속성을 구성하는 대신 웹 구성(web.config) 파일에서 캐시 프로필을 만들 수 있습니다.As an alternative to configuring output cache properties by modifying properties of the [OutputCache] attribute, you can create a cache profile in the web configuration (web.config) file. 웹 구성 파일에 캐시 프로필을 만들면 몇 가지 중요한 이점이 있습니다.Creating a cache profile in the web configuration file offers a couple of important advantages.

먼저 웹 구성 파일에서 출력 캐싱을 구성하여 컨트롤러 작업이 한 중앙 위치에서 콘텐츠를 캐시하는 방법을 제어할 수 있습니다.First, by configuring output caching in the web configuration file, you can control how controller actions cache content in one central location. 하나의 캐시 프로필을 만들고 프로파일을 여러 컨트롤러 또는 컨트롤러 작업에 적용할 수 있습니다.You can create one cache profile and apply the profile to several controllers or controller actions.

둘째, 응용 프로그램을 다시 컴파일하지 않고 웹 구성 파일을 수정할 수 있습니다.Second, you can modify the web configuration file without recompiling your application. 프로덕션에 이미 배포된 응용 프로그램에 대해 캐싱을 사용하지 않도록 설정해야 하는 경우 웹 구성 파일에 정의된 캐시 프로필을 수정하기만 하면 됩니다.If you need to disable caching for an application that has already been deployed to production, then you can simply modify the cache profiles defined in the web configuration file. 웹 구성 파일에 대한 모든 변경 내용이 자동으로 감지되고 적용됩니다.Any changes to the web configuration file will be detected automatically and applied.

예를 들어 <목록> 6의 웹 구성 섹션은 Cache1Hour라는 캐시 프로필을 정의합니다.For example, the <caching> web configuration section in Listing 6 defines a cache profile named Cache1Hour. 캐싱 <> 섹션은 웹 <구성 파일의 system.web> 섹션내에 나타나야 합니다.The <caching> section must appear within the <system.web> section of a web configuration file.

목록 6 – web.config에 대 한 캐싱 섹션Listing 6 – Caching section for web.config

<caching>
<outputCacheSettings>
    <outputCacheProfiles>
        <add name="Cache1Hour" duration="3600" varyByParam="none"/>
    </outputCacheProfiles>
</outputCacheSettings>
</caching>

목록 7의 컨트롤러는 [OutputCache] 특성을 사용하여 컨트롤러 작업에 Cache1Hour 프로파일을 적용하는 방법을 보여 줍니다.The controller in Listing 7 illustrates how you can apply the Cache1Hour profile to a controller action with the [OutputCache] attribute.

목록 7 – 컨트롤러\ProfileController.csListing 7 – Controllers\ProfileController.cs

using System;
using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
    public class ProfileController : Controller
    {
        [OutputCache(CacheProfile="Cache1Hour")]
        public string Index()
        {
            return DateTime.Now.ToString("T");
        }
    }
}

목록 7의 컨트롤러가 노출한 Index() 작업을 호출하면 동일한 시간이 1시간 동안 반환됩니다.If you invoke the Index() action exposed by the controller in Listing 7 then the same time will be returned for 1 hour.

요약Summary

출력 캐싱은 ASP.NET MVC 응용 프로그램의 성능을 크게 향상시키는 매우 쉬운 방법을 제공합니다.Output caching provides you with a very easy method of dramatically improving the performance of your ASP.NET MVC applications. 이 자습서에서는 [OutputCache] 특성을 사용하여 컨트롤러 작업의 출력을 캐시하는 방법을 배웠습니다.In this tutorial, you learned how to use the [OutputCache] attribute to cache the output of controller actions. 또한 기간 및 [OutputCache] 특성의 속성을 수정하여 콘텐츠가 캐시되는 방식을 수정하는 방법도 배웠습니다.You also learned how to modify properties of the [OutputCache] attribute such as the Duration and VaryByParam properties to modify how content gets cached. 마지막으로 웹 구성 파일에서 캐시 프로필을 정의하는 방법을 배웠습니다.Finally, you learned how to define cache profiles in the web configuration file.