ASP.NET Core의 캐싱 분산Distributed caching in ASP.NET Core

작성자: Steve SmithLuke LathamBy Steve Smith and Luke Latham

분산된 캐시에 액세스 하는 응용 프로그램 서버 외부 서비스로 일반적으로 유지 관리 하는 여러 앱 서버에서 공유 캐시가입니다.A distributed cache is a cache shared by multiple app servers, typically maintained as an external service to the app servers that access it. 앱은 클라우드 서비스 또는 서버 팜을 호스팅하는 경우에 특히 분산된 캐시는 성능 및 ASP.NET Core 앱의 확장성을 개선할 수 있습니다.A distributed cache can improve the performance and scalability of an ASP.NET Core app, especially when the app is hosted by a cloud service or a server farm.

분산된 캐시에는 개별 앱 서버에서 캐시 된 데이터가 저장 된 다른 캐싱 시나리오를 통해 몇 가지 장점이 있습니다.A distributed cache has several advantages over other caching scenarios where cached data is stored on individual app servers.

캐시 된 데이터를 분산 하는 경우, 데이터:When cached data is distributed, the data:

  • 됩니다 일관 된 (일치)에서 여러 서버에 요청 합니다.Is coherent (consistent) across requests to multiple servers.
  • 서버 다시 시작 되 고 앱 배포도 계속 유지 됩니다.Survives server restarts and app deployments.
  • 로컬 메모리를 사용 하지 않습니다.Doesn't use local memory.

분산된 캐시 구성은 특정 구현 합니다.Distributed cache configuration is implementation specific. 이 문서에서는 SQL Server를 구성 하 고 Redis cache를 배포 하는 방법을 설명 합니다.This article describes how to configure SQL Server and Redis distributed caches. 제 3 자 구현도 같은 사용할 수 있습니다 NCache (github NCache).Third party implementations are also available, such as NCache (NCache on GitHub). 어떤 구현의 선택 하는 것에 관계 없이 앱을 사용 하 여 캐시 상호 작용을 IDistributedCache 인터페이스입니다.Regardless of which implementation is selected, the app interacts with the cache using the IDistributedCache interface.

샘플 코드 살펴보기 및 다운로드(다운로드 방법)View or download sample code (how to download)

전제 조건Prerequisites

SQL Server를 사용 하 여 분산 캐시에 대 한 참조를 Microsoft.AspNetCore.App 메타 패키지 에 대 한 패키지 참조를 추가 또는 합니다 Microsoft.Extensions.Caching.SqlServer 패키지 합니다.To use a SQL Server distributed cache, reference the Microsoft.AspNetCore.App metapackage or add a package reference to the Microsoft.Extensions.Caching.SqlServer package.

Redis를 사용 하 여 분산 캐시에 대 한 참조를 Microsoft.AspNetCore.App 메타 패키지 에 대 한 패키지 참조를 추가 하 고는 Microsoft.Extensions.Caching.Redis 패키지 합니다.To use a Redis distributed cache, reference the Microsoft.AspNetCore.App metapackage and add a package reference to the Microsoft.Extensions.Caching.Redis package. Redis 패키지에 포함 되어 있지는 Microsoft.AspNetCore.App 패키지를 프로젝트 파일의 Redis 패키지를 개별적으로 참조 해야 하므로 합니다.The Redis package isn't included in the Microsoft.AspNetCore.App package, so you must reference the Redis package separately in your project file.

SQL Server를 사용 하 여 분산 캐시에 대 한 참조를 Microsoft.AspNetCore.All 메타 패키지 에 대 한 패키지 참조를 추가 또는 합니다 Microsoft.Extensions.Caching.SqlServer 패키지 합니다.To use a SQL Server distributed cache, reference the Microsoft.AspNetCore.All metapackage or add a package reference to the Microsoft.Extensions.Caching.SqlServer package.

Redis를 사용 하 여 분산 캐시에 대 한 참조를 Microsoft.AspNetCore.All 메타 패키지 패키지 참조를 추가 하거나 합니다 Microsoft.Extensions.Caching.Redis 패키지 합니다.To use a Redis distributed cache, reference the Microsoft.AspNetCore.All metapackage or add a package reference to the Microsoft.Extensions.Caching.Redis package. Redis 패키지에 포함 됩니다 Microsoft.AspNetCore.All 패키지를 프로젝트 파일에서 별도로 Redis 패키지를 참조할 필요가 없습니다.The Redis package is included in Microsoft.AspNetCore.All package, so you don't need to reference the Redis package separately in your project file.

SQL Server를 사용 하 여 분산 캐시, 패키지 참조를 추가 합니다 Microsoft.Extensions.Caching.SqlServer 패키지 있습니다.To use a SQL Server distributed cache, add a package reference to the Microsoft.Extensions.Caching.SqlServer package.

분산 캐시는 Redis를 사용 하도록, 패키지 참조를 추가 합니다 Microsoft.Extensions.Caching.Redis 패키지 있습니다.To use a Redis distributed cache, add a package reference to the Microsoft.Extensions.Caching.Redis package.

IDistributedCache 인터페이스IDistributedCache interface

IDistributedCache 인터페이스 분산된 캐시 구현에서 항목을 조작 하려면 다음 메서드를 제공 합니다.The IDistributedCache interface provides the following methods to manipulate items in the distributed cache implementation:

  • GetGetAsync – 문자열 키를 받아서으로 캐시 된 항목을 검색 합니다는 byte[] 경우 캐시에서 발견 합니다.Get, GetAsync – Accepts a string key and retrieves a cached item as a byte[] array if found in the cache.
  • SetSetAsync – 항목을 추가 (으로 byte[] 배열) 문자열 키를 사용 하 여 캐시 합니다.Set, SetAsync – Adds an item (as byte[] array) to the cache using a string key.
  • Refresh하십시오 RefreshAsync – (있는 경우) 해당 상대 (sliding) 만료 시간 제한 다시 설정 하 고 키를 기반으로 캐시에서 항목을 새로 고칩니다.Refresh, RefreshAsync – Refreshes an item in the cache based on its key, resetting its sliding expiration timeout (if any).
  • Remove하십시오 RemoveAsync – 해당 문자열 키를 기반으로 캐시 항목을 제거 합니다.Remove, RemoveAsync – Removes a cache item based on its string key.

분산된 캐싱 서비스를 설정 합니다.Establish distributed caching services

등록의 구현을 IDistributedCache 에서 Startup.ConfigureServices합니다.Register an implementation of IDistributedCache in Startup.ConfigureServices. 이 항목에서 설명 하는 프레임 워크에서 제공한 구현은 다음과 같습니다.Framework-provided implementations described in this topic include:

분산된 메모리 내 캐시Distributed Memory Cache

메모리 내 분산 캐시 (AddDistributedMemoryCache)의 프레임 워크에서 제공한 구현인 IDistributedCache 메모리에 항목을 저장 하는 합니다.The Distributed Memory Cache (AddDistributedMemoryCache) is a framework-provided implementation of IDistributedCache that stores items in memory. 분산 메모리 내 캐시는 실제 분산된 캐시 되지 않습니다.The Distributed Memory Cache isn't an actual distributed cache. 캐시 된 항목은 앱이 실행 하는 서버에서 앱 인스턴스에 의해 저장 됩니다.Cached items are stored by the app instance on the server where the app is running.

메모리 내 분산 캐시는 유용한 구현 합니다.The Distributed Memory Cache is a useful implementation:

  • 개발 및 테스트 시나리오입니다.In development and testing scenarios.
  • 프로덕션 및 메모리 사용량에서 단일 서버를 사용할 경우 문제가 되지 않습니다.When a single server is used in production and memory consumption isn't an issue. 데이터 저장소를 캐시 메모리 캐시 Distributed 요약을 구현 합니다.Implementing the Distributed Memory Cache abstracts cached data storage. 허용을 구현 하기 위한 진정한 여러 노드 또는 내결함성 제공 해야 할 경우에 나중에 캐싱 솔루션 배포 합니다.It allows for implementing a true distributed caching solution in the future if multiple nodes or fault tolerance become necessary.

샘플 앱을 사용 하면 앱 개발 환경에서 실행 될 때 메모리 내 분산 캐시 사용:The sample app makes use of the Distributed Memory Cache when the app is run in the Development environment:

public void ConfigureServices(IServiceCollection services)
{
    if (_hostContext.IsDevelopment())
    {
        services.AddDistributedMemoryCache();
    }
    else
    {
        services.AddDistributedSqlServerCache(options =>
        {
            options.ConnectionString = 
                _config["DistCache_ConnectionString"];
            options.SchemaName = "dbo";
            options.TableName = "TestCache";
        });
    }

분산 된 SQL 서버 캐시Distributed SQL Server Cache

분산 된 SQL Server 캐시 구현 (AddDistributedSqlServerCache) SQL Server 데이터베이스를 백업 저장소로 사용 하 여 분산된 캐시를 허용 합니다.The Distributed SQL Server Cache implementation (AddDistributedSqlServerCache) allows the distributed cache to use a SQL Server database as its backing store. 테이블을 만들려면 SQL Server 캐시 된 항목의 SQL Server 인스턴스를 사용할 수는 sql-cache 도구입니다.To create a SQL Server cached item table in a SQL Server instance, you can use the sql-cache tool. 도구 이름 및 지정 된 스키마를 사용 하 여 테이블을 만듭니다.The tool creates a table with the name and schema that you specify.

추가 SqlConfig.Tools<ItemGroup> 프로젝트 파일과 실행 요소의 dotnet restore합니다.Add SqlConfig.Tools to the <ItemGroup> element of the project file and run dotnet restore.

<ItemGroup>
  <DotNetCliToolReference Include="Microsoft.Extensions.Caching.SqlConfig.Tools"
                          Version="2.0.2" />
</ItemGroup>

SQL Server에서 실행 하 여 테이블을 만들기는 sql-cache create 명령입니다.Create a table in SQL Server by running the sql-cache create command. SQL Server 인스턴스를 제공 (Data Source), 데이터베이스 (Initial Catalog), 스키마 (예를 들어 dbo)을 및 테이블 이름 (예를 들어 TestCache):Provide the SQL Server instance (Data Source), database (Initial Catalog), schema (for example, dbo), and table name (for example, TestCache):

dotnet sql-cache create "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DistCache;Integrated Security=True;" dbo TestCache

도구 성공 했음을 나타내는 메시지가 기록 됩니다.A message is logged to indicate that the tool was successful:

Table and index were created successfully.

생성 된 테이블을 sql-cache 도구는 다음 스키마를 갖습니다.The table created by the sql-cache tool has the following schema:

Sql Server 캐시 테이블

참고

앱의 인스턴스를 사용 하 여 캐시 값을 조작 해야 IDistributedCache이 아니라는 SqlServerCache합니다.An app should manipulate cache values using an instance of IDistributedCache, not a SqlServerCache.

샘플 앱을 구현 하는 SqlServerCache 비 개발 환경에서:The sample app implements SqlServerCache in a non-Development environment:

public void ConfigureServices(IServiceCollection services)
{
    if (_hostContext.IsDevelopment())
    {
        services.AddDistributedMemoryCache();
    }
    else
    {
        services.AddDistributedSqlServerCache(options =>
        {
            options.ConnectionString = 
                _config["DistCache_ConnectionString"];
            options.SchemaName = "dbo";
            options.TableName = "TestCache";
        });
    }

참고

A ConnectionString (및 필요에 따라 SchemaNameTableName)는 일반적으로 소스 제어 외부 저장 (에서 예를 들어 저장 합니다 암호 관리자 또는 appsettings.json / appsettings 합니다. {Environment}.json 파일).A ConnectionString (and optionally, SchemaName and TableName) are typically stored outside of source control (for example, stored by the Secret Manager or in appsettings.json/appsettings.{Environment}.json files). 연결 문자열을 소스 제어 시스템에서 유지 해야 하는 자격 증명을 포함할 수 있습니다.The connection string may contain credentials that should be kept out of source control systems.

분산된 Redis CacheDistributed Redis Cache

Redis는 분산 캐시로 흔히 사용되는 오픈 소스 메모리 내 데이터 저장소입니다.Redis is an open source in-memory data store, which is often used as a distributed cache. Redis를 로컬로 사용할 수 있습니다 하 고 구성할 수 있습니다는 Azure Redis Cache Azure에서 호스팅되는 ASP.NET Core 앱에 대 한 합니다.You can use Redis locally, and you can configure an Azure Redis Cache for an Azure-hosted ASP.NET Core app. 앱 구성 사용 하 여 캐시 구현 된 RedisCache 인스턴스 (AddDistributedRedisCache):An app configures the cache implementation using a RedisCache instance (AddDistributedRedisCache):

services.AddDistributedRedisCache(options =>
{
    options.Configuration = "localhost";
    options.InstanceName = "SampleInstance";
});

로컬 컴퓨터에 Redis를 설치 합니다.To install Redis on your local machine:

분산된 캐시 사용Use the distributed cache

사용 하 여 IDistributedCache 인터페이스의 인스턴스를 요청 하십시오 IDistributedCache 앱에서 모든 생성자에서.To use the IDistributedCache interface, request an instance of IDistributedCache from any constructor in the app. 제공 하는 인스턴스 종속성 주입 (DI)합니다.The instance is provided by dependency injection (DI).

앱을 시작 하는 경우 IDistributedCache 삽입 되어 Startup.Configure입니다.When the app starts, IDistributedCache is injected into Startup.Configure. 현재 사용 하 여 캐시 됩니다 IApplicationLifetime (자세한 내용은 참조 하십시오 웹 호스트: IApplicationLifetime 인터페이스):The current time is cached using IApplicationLifetime (for more information, see Web Host: IApplicationLifetime interface):

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
    IApplicationLifetime lifetime, IDistributedCache cache)
{
    lifetime.ApplicationStarted.Register(() =>
    {
        var currentTimeUTC = DateTime.UtcNow.ToString();
        byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
        var options = new DistributedCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromSeconds(20));
        cache.Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
    });

샘플 앱 삽입 IDistributedCacheIndexModel 인덱스 페이지를 사용 합니다.The sample app injects IDistributedCache into the IndexModel for use by the Index page.

인덱스 페이지가 로드 될 때마다 캐시에서 캐시 된 시간에 대 한 확인란이 OnGetAsync합니다.Each time the Index page is loaded, the cache is checked for the cached time in OnGetAsync. 캐시 된 시간 만료 되지 않았으면, 시간이 표시 됩니다.If the cached time hasn't expired, the time is displayed. 20 초에 마지막으로 캐시 된 시간 (이 페이지를 로드 하는 마지막 시간) 액세스 된 이후 경과 된 경우 페이지에 표시 됩니다 캐시 된 시간이 만료합니다.If 20 seconds have elapsed since the last time the cached time was accessed (the last time this page was loaded), the page displays Cached Time Expired.

즉시 선택 하 여 현재 시간으로 캐시 된 시간을 업데이트 합니다 캐시 된 시간 재설정 단추입니다.Immediately update the cached time to the current time by selecting the Reset Cached Time button. 단추 트리거는 OnPostResetCachedTime 처리기 메서드.The button triggers the OnPostResetCachedTime handler method.

public class IndexModel : PageModel
{
    private readonly IDistributedCache _cache;

    public IndexModel(IDistributedCache cache)
    {
        _cache = cache;
    }

    public string CachedTimeUTC { get; set; }

    public async Task OnGetAsync()
    {
        CachedTimeUTC = "Cached Time Expired";
        var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");

        if (encodedCachedTimeUTC != null)
        {
            CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
        }
    }

    public async Task<IActionResult> OnPostResetCachedTime()
    {
        var currentTimeUTC = DateTime.UtcNow.ToString();
        byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
        var options = new DistributedCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromSeconds(20));
        await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);

        return RedirectToPage();
    }
}

참고

IDistributedCache 인스턴스를 Singleton이나 Scoped 수명으로 사용할 필요는 없습니다(적어도 기본 구현일 경우).There's no need to use a Singleton or Scoped lifetime for IDistributedCache instances (at least for the built-in implementations).

만들 수도 있습니다는 IDistributedCache DI를 사용 하는 대신 해야 할 수 있습니다 하지만 코드에서 인스턴스를 만드는 코드를 만들 수 테스트 하기가 때마다 인스턴스를 위반 합니다 명시적 종속성 원칙합니다.You can also create an IDistributedCache instance wherever you might need one instead of using DI, but creating an instance in code can make your code harder to test and violates the Explicit Dependencies Principle.

권장 사항Recommendations

구현의 결정할 때 IDistributedCache 앱에 가장 적합 한 다음 사항을 고려 합니다.When deciding which implementation of IDistributedCache is best for your app, consider the following:

  • 기존 인프라Existing infrastructure
  • 성능 요구 사항Performance requirements
  • 비용Cost
  • 팀 환경Team experience

일반적으로 캐시 된 데이터의 빠른 검색을 위해 메모리 내 저장소 캐싱 솔루션에 의존 하지만 메모리가 제한 된 리소스 및 확장 비용이 많이 듭니다.Caching solutions usually rely on in-memory storage to provide fast retrieval of cached data, but memory is a limited resource and costly to expand. 전용 저장소는 일반적으로 캐시에 데이터를 사용 합니다.Only store commonly used data in a cache.

일반적으로 Redis cache는 더 높은 처리량 및 SQL Server 캐시 보다 더 낮은 대기 시간을 제공합니다.Generally, a Redis cache provides higher throughput and lower latency than a SQL Server cache. 그러나 벤치 마크는 일반적으로 캐싱 전략의 성능 특징을 결정 해야 합니다.However, benchmarking is usually required to determine the performance characteristics of caching strategies.

분산된 캐시 백업 저장소로 SQL Server를 사용 하면 캐시 및 앱의 일반 데이터 저장소에 대 한 동일한 데이터베이스의 사용 및 검색 둘 다의 성능 저하 될 수 있습니다.When SQL Server is used as a distributed cache backing store, use of the same database for the cache and the app's ordinary data storage and retrieval can negatively impact the performance of both. 백업 저장소는 분산된 캐시에 대 한 전용된 SQL Server 인스턴스를 사용 하는 것이 좋습니다.We recommend using a dedicated SQL Server instance for the distributed cache backing store.

추가 자료Additional resources