ASP.NET Core 분산 캐싱

모신 나시르스만디아

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

분산 캐시는 여러 앱 서버에서 공유하는 캐시로, 일반적으로 액세스하는 앱 서버에 외부 서비스로 유지 관리됩니다. 분산 캐시는 특히 앱이 클라우드 서비스 또는 서버 팜에서 호스팅되는 경우 ASP.NET Core 앱의 성능과 확장성을 향상시킬 수 있습니다.

분산 캐시는 개별 앱 서버에 캐시된 데이터가 저장되는 다른 캐싱 시나리오에 비해 여러 가지 이점을 제공합니다.

캐시된 데이터를 배포하는 경우 데이터는 다음과 같습니다.

  • 여러 서버에 대한 여러 요청에서 일관됩니다.
  • 서버를 다시 시작하고 앱을 배포할 때 유지됩니다.
  • 로컬 메모리를 사용하지 않습니다.

분산 캐시 구성은 구현별로 다릅니다. 이 문서에서는 SQL Server 및 Redis 분산 캐시를 구성하는 방법을 설명합니다. NCache와 같은 타사 구현도 사용할 수 있습니다(GitHub의 NCache). 선택한 구현과 관계없이 앱은 IDistributedCache 인터페이스를 사용하여 캐시와 상호 작용합니다.

샘플 코드 보기 및 다운로드(다운로드 방법)

필수 조건

사용되는 분산 캐시 공급자에 대한 패키지 참조를 추가합니다.

IDistributedCache 인터페이스

IDistributedCache 인터페이스는 분산 캐시 구현에서 항목을 조작하는 다음과 같은 메서드를 제공합니다.

  • Get, GetAsync: 문자열 키를 허용하고 캐시된 항목을 캐시에 있는 경우 byte[] 배열로 검색합니다.
  • Set, SetAsync : 문자열 키를 사용하여 캐시에 항목(byte[] 배열로)을 추가합니다.
  • Refresh, RefreshAsync: 해당 키를 기준으로 캐시의 항목을 새로 고쳐 상대 만료 시간 제한(있는 경우)을 다시 설정합니다.
  • Remove, RemoveAsync: 해당 문자열 키를 기준으로 캐시 항목을 제거합니다.

분산 캐싱 서비스 설정

Program.cs에서 IDistributedCache에 대한 구현을 등록합니다. 이 항목에서 설명하는 프레임워크 제공 구현에는 다음이 포함됩니다.

분산 Redis Cache

프로덕션 앱은 가장 성능이 좋은 분산 Redis Cache를 사용하는 것이 좋습니다. 자세한 내용은 권장 사항 참조하세요.

Redis는 분산 캐시로 자주 사용되는 오픈 소스 메모리 내 데이터 저장소입니다. Azure 호스팅 ASP.NET Core 앱에 대해 Azure Cache for Redis를 구성하고 로컬 개발에 Azure Cache for Redis를 사용할 수 있습니다.

앱은 인스턴스를 사용하여 캐시 구현을 RedisCache 호출 AddStackExchangeRedisCache하여 구성합니다. 출력 캐싱의AddStackExchangeRedisOutputCache 경우 .

  1. Azure Cache for Redis를 만듭니다.
  2. 기본 연결 문자열(StackExchange.Redis)을 구성에 복사합니다.
    • 로컬 개발: 비밀 관리자를 사용하여 연결 문자열을 저장합니다.
    • Azure: 연결 문자열을 App Service 구성 또는 다른 보안 저장소에 저장합니다.

다음 코드는 Azure Cache for Redis를 사용하도록 설정합니다.

builder.Services.AddStackExchangeRedisCache(options =>
 {
     options.Configuration = builder.Configuration.GetConnectionString("MyRedisConStr");
     options.InstanceName = "SampleInstance";
 });

위의 코드에서는 기본 연결 문자열(StackExchange.Redis)이 키 이름 MyRedisConStr로 구성에 저장되었다고 가정합니다.

자세한 내용은 Azure Cache for Redis를 참조하세요.

로컬 Redis Cache에 대한 대체 접근 방식에 대한 설명은 이 GitHub 문제를 참조하세요.

분산 메모리 캐시

분산 메모리 캐시(AddDistributedMemoryCache)는 메모리에 항목을 저장하는 IDistributedCache의 프레임워크 제공 구현입니다. 분산 메모리 캐시는 실제 분산된 캐시가 아닙니다. 캐시된 항목은 앱이 실행되고 있는 서버의 앱 인스턴스에 의해 저장됩니다.

분산 메모리 캐시는 다음과 같은 경우 유용합니다.

  • 개발 및 테스트 시나리오에서.
  • 프로덕션 환경에서 단일 서버를 사용하고 메모리 소비가 문제가 되지 않는 경우. 분산 메모리 캐시를 구현할 때 캐시된 데이터 스토리지를 추상화합니다. 이를 통해 나중에 여러 노드 또는 내결함성이 필요한 경우 진정한 분산 캐싱 솔루션을 구현할 수 있습니다.

샘플 앱은 앱이 Program.cs의 개발 환경에서 실행될 때 분산 메모리 캐시를 사용합니다.

builder.Services.AddDistributedMemoryCache();

분산 SQL Server 캐시

분산 SQL Server 캐시 구현(AddDistributedSqlServerCache)을 사용하면 분산 캐시에서 SQL Server 데이터베이스를 백업 저장소로 사용할 수 있습니다. SQL Server 인스턴스에서 캐시된 SQL Server 항목 테이블을 만들려면 sql-cache 도구를 사용할 수 있습니다. 이 도구는 사용자가 지정한 이름 및 스키마를 사용하여 테이블을 만듭니다.

sql-cache create 명령을 실행하여 SQL Server에서 테이블을 만듭니다. SQL Server 인스턴스(Data Source), 데이터베이스(Initial Catalog), 스키마(예: dbo) 및 테이블 이름(예: TestCache)을 제공합니다.

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

도구가 성공했음을 나타내는 메시지가 기록됩니다.

Table and index were created successfully.

sql-cache 도구에서 만든 테이블에는 다음 스키마가 있습니다.

SqlServer 캐시 테이블

참고 항목

앱은 SqlServerCache가 아닌 IDistributedCache의 인스턴스를 사용하여 캐시 값을 조작해야 합니다.

샘플 앱은 Program.cs의 개발 이외의 환경에서 SqlServerCache를 구현합니다.

builder.Services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString(
        "DistCache_ConnectionString");
    options.SchemaName = "dbo";
    options.TableName = "TestCache";
});

참고 항목

ConnectionString(선택적으로 SchemaNameTableName)은 일반적으로 소스 제어 외부에 저장됩니다(예: Secret Manager 또는 appsettings.json/appsettings.{Environment}.json 파일에 저장됨). 연결 문자열에는 원본 제어 시스템에서 유지되어야 하는 자격 증명이 포함될 수 있습니다.

분산 NCache 캐시

NCache는 원래 .NET 및 .NET Core에서 개발된 오픈 소스 메모리 내 분산 캐시입니다. NCache는 로컬에서 작동하고 Azure 또는 다른 호스팅 플랫폼에서 실행되는 ASP.NET Core 앱에 대한 분산 캐시 클러스터로 구성됩니다.

로컬 컴퓨터에 NCache를 설치 및 구성하려면 Windows를 위한 시작 가이드(.NET 및 .NET Core)를 참조하세요.

NCache를 구성하려면 다음을 수행합니다.

  1. NCache 오픈 소스 NuGet을 설치합니다.
  2. 캐시 클러스터를 client.ncconf에 구성합니다.
  3. 다음 코드를 Program.cs에 추가합니다.
builder.Services.AddNCacheDistributedCache(configuration =>
{
    configuration.CacheName = "democache";
    configuration.EnableLogs = true;
    configuration.ExceptionsEnabled = true;
});

분산 Azure CosmosDB 캐시

Azure Cosmos DB 는 ASP.NET Core에서 인터페이스를 사용하여 IDistributedCache 세션 상태 공급자로 사용할 수 있습니다. Azure Cosmos DB는 중요 업무용 애플리케이션의 데이터에 대한 고가용성, 확장성 및 짧은 대기 시간 액세스를 제공하는 최신 앱 개발을 위한 완전 관리형 NoSQL 및 관계형 데이터베이스입니다.

Microsoft.Extensions.Caching.Cosmos NuGet 패키지를 설치한 후 다음과 같이 Azure Cosmos DB 분산 캐시를 구성합니다.

기존 클라이언트 다시 사용

분산 캐시를 구성하는 가장 쉬운 방법은 기존 Azure Cosmos DB 클라이언트를 다시 사용하는 것입니다. 이 경우 공급자가 CosmosClient 삭제될 때 인스턴스가 삭제되지 않습니다.

services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
    cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
    cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
    cacheOptions.CosmosClient = existingCosmosClient;
    cacheOptions.CreateIfNotExists = true;
});

새 클라이언트 만들기

또는 새 클라이언트를 인스턴스화합니다. 이 경우 공급자가 CosmosClient 삭제되면 인스턴스가 삭제됩니다.

services.AddCosmosCache((CosmosCacheOptions cacheOptions) =>
{
    cacheOptions.ContainerName = Configuration["CosmosCacheContainer"];
    cacheOptions.DatabaseName = Configuration["CosmosCacheDatabase"];
    cacheOptions.ClientBuilder = new CosmosClientBuilder(Configuration["CosmosConnectionString"]);
    cacheOptions.CreateIfNotExists = true;
});

분산 캐시 사용

IDistributedCache 인터페이스를 사용하려면 앱에서 IDistributedCache의 인스턴스를 요청합니다. 인스턴스는 DI(종속성 주입)에서 제공됩니다.

샘플 앱이 시작되면 IDistributedCacheProgram.cs에 삽입됩니다. 현재 시간은 IHostApplicationLifetime을 사용하여 캐시됩니다(자세한 내용은 제네릭 호스트: IHostApplicationLifetime 참조).

app.Lifetime.ApplicationStarted.Register(() =>
{
    var currentTimeUTC = DateTime.UtcNow.ToString();
    byte[] encodedCurrentTimeUTC = System.Text.Encoding.UTF8.GetBytes(currentTimeUTC);
    var options = new DistributedCacheEntryOptions()
        .SetSlidingExpiration(TimeSpan.FromSeconds(20));
    app.Services.GetService<IDistributedCache>()
                              .Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});

샘플 앱은 인덱스 페이지에서 사용할 수 있도록 IDistributedCacheIndexModel에 삽입합니다.

인덱스 페이지가 로드될 때마다 OnGetAsync에서 캐시된 시간에 대한 캐시를 확인합니다. 캐시된 시간이 만료되지 않은 경우 시간이 표시됩니다. 캐시된 시간에 마지막으로 액세스한 후 20초가 경과한 경우(이 페이지가 마지막으로 로드된 시간) 페이지에는 캐시된 시간 만료가 표시됩니다.

캐시된 시간 다시 설정 단추를 선택하여 캐시된 시간을 현재 시간으로 즉시 업데이트합니다. 단추는 OnPostResetCachedTime 처리기 메서드를 트리거합니다.

public class IndexModel : PageModel
{
    private readonly IDistributedCache _cache;

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

    public string? CachedTimeUTC { get; set; }
    public string? ASP_Environment { get; set; }

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

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

        ASP_Environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
        if (String.IsNullOrEmpty(ASP_Environment))
        {
            ASP_Environment = "Null, so Production";
        }
    }

    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 인스턴스에 대해 싱글톤 또는 범위 수명을 사용할 필요가 없습니다.

DI를 사용하는 대신 IDistributedCache 인스턴스를 만들 수도 있지만, 코드에서 인스턴스를 만들면 코드를 테스트하는 것이 어렵고 명시적 종속성 원칙을 위반하게 될 수 있습니다.

권장 사항

앱에 가장 적합한 IDistributedCache의 구현을 결정할 때 다음 사항을 고려합니다.

  • 기존 인프라
  • 성능 요구 사항
  • 비용
  • 팀 환경

캐싱 솔루션은 일반적으로 메모리 내 스토리지를 사용하여 캐시된 데이터를 신속하게 검색하지만 메모리는 제한된 리소스이며 확장하는 데 비용이 많이 듭니다. 일반적으로 사용되는 데이터만 캐시에 저장합니다.

대부분의 앱에서 Redis 캐시는 SQL Server 캐시보다 더 높은 처리량과 짧은 대기 시간을 제공합니다. 그러나 캐싱 전략의 성능 특성을 확인하려면 벤치마킹을 사용하는 것이 좋습니다.

SQL Server를 분산 캐시 백업 저장소로 사용하는 경우 캐시에 대해 동일한 데이터베이스를 사용하고 앱의 일반 데이터 스토리지 및 검색을 사용하면 두 성능에 부정적인 영향을 줄 수 있습니다. 분산 캐시 백업 저장소에 전용 SQL Server 인스턴스를 사용하는 것이 좋습니다.

추가 리소스

분산 캐시는 여러 앱 서버에서 공유하는 캐시로, 일반적으로 액세스하는 앱 서버에 외부 서비스로 유지 관리됩니다. 분산 캐시는 특히 앱이 클라우드 서비스 또는 서버 팜에서 호스팅되는 경우 ASP.NET Core 앱의 성능과 확장성을 향상시킬 수 있습니다.

분산 캐시는 개별 앱 서버에 캐시된 데이터가 저장되는 다른 캐싱 시나리오에 비해 여러 가지 이점을 제공합니다.

캐시된 데이터를 배포하는 경우 데이터는 다음과 같습니다.

  • 여러 서버에 대한 여러 요청에서 일관됩니다.
  • 서버를 다시 시작하고 앱을 배포할 때 유지됩니다.
  • 로컬 메모리를 사용하지 않습니다.

분산 캐시 구성은 구현별로 다릅니다. 이 문서에서는 SQL Server 및 Redis 분산 캐시를 구성하는 방법을 설명합니다. NCache와 같은 타사 구현도 사용할 수 있습니다(GitHub의 NCache). 선택한 구현과 관계없이 앱은 IDistributedCache 인터페이스를 사용하여 캐시와 상호 작용합니다.

샘플 코드 보기 및 다운로드(다운로드 방법)

필수 조건

사용되는 분산 캐시 공급자에 대한 패키지 참조를 추가합니다.

IDistributedCache 인터페이스

IDistributedCache 인터페이스는 분산 캐시 구현에서 항목을 조작하는 다음과 같은 메서드를 제공합니다.

  • Get, GetAsync: 문자열 키를 허용하고 캐시된 항목을 캐시에 있는 경우 byte[] 배열로 검색합니다.
  • Set, SetAsync : 문자열 키를 사용하여 캐시에 항목(byte[] 배열로)을 추가합니다.
  • Refresh, RefreshAsync: 해당 키를 기준으로 캐시의 항목을 새로 고쳐 상대 만료 시간 제한(있는 경우)을 다시 설정합니다.
  • Remove, RemoveAsync: 해당 문자열 키를 기준으로 캐시 항목을 제거합니다.

분산 캐싱 서비스 설정

Program.cs에서 IDistributedCache에 대한 구현을 등록합니다. 이 항목에서 설명하는 프레임워크 제공 구현에는 다음이 포함됩니다.

분산 Redis Cache

프로덕션 앱은 가장 성능이 좋은 분산 Redis Cache를 사용하는 것이 좋습니다. 자세한 내용은 권장 사항 참조하세요.

Redis는 분산 캐시로 자주 사용되는 오픈 소스 메모리 내 데이터 저장소입니다. Azure에서 호스팅되는 ASP.NET Core 앱에 대한 Azure Redis Cache를 구성하고 로컬 개발에 Azure Redis Cache를 사용할 수 있습니다.

앱은 RedisCache 인스턴스(AddStackExchangeRedisCache)를 사용하여 캐시 구현을 구성합니다.

  1. Azure Cache for Redis를 만듭니다.
  2. 기본 연결 문자열(StackExchange.Redis)을 구성에 복사합니다.
    • 로컬 개발: 비밀 관리자를 사용하여 연결 문자열을 저장합니다.
    • Azure: 연결 문자열을 App Service 구성 또는 다른 보안 저장소에 저장합니다.

다음 코드는 Azure Cache for Redis를 사용하도록 설정합니다.

builder.Services.AddStackExchangeRedisCache(options =>
 {
     options.Configuration = builder.Configuration.GetConnectionString("MyRedisConStr");
     options.InstanceName = "SampleInstance";
 });

위의 코드에서는 기본 연결 문자열(StackExchange.Redis)이 키 이름 MyRedisConStr로 구성에 저장되었다고 가정합니다.

자세한 내용은 Azure Cache for Redis를 참조하세요.

로컬 Redis Cache에 대한 대체 접근 방식에 대한 설명은 이 GitHub 문제를 참조하세요.

분산 메모리 캐시

분산 메모리 캐시(AddDistributedMemoryCache)는 메모리에 항목을 저장하는 IDistributedCache의 프레임워크 제공 구현입니다. 분산 메모리 캐시는 실제 분산된 캐시가 아닙니다. 캐시된 항목은 앱이 실행되고 있는 서버의 앱 인스턴스에 의해 저장됩니다.

분산 메모리 캐시는 다음과 같은 경우 유용합니다.

  • 개발 및 테스트 시나리오에서.
  • 프로덕션 환경에서 단일 서버를 사용하고 메모리 소비가 문제가 되지 않는 경우. 분산 메모리 캐시를 구현할 때 캐시된 데이터 스토리지를 추상화합니다. 이를 통해 나중에 여러 노드 또는 내결함성이 필요한 경우 진정한 분산 캐싱 솔루션을 구현할 수 있습니다.

샘플 앱은 앱이 Program.cs의 개발 환경에서 실행될 때 분산 메모리 캐시를 사용합니다.

builder.Services.AddDistributedMemoryCache();

분산 SQL Server 캐시

분산 SQL Server 캐시 구현(AddDistributedSqlServerCache)을 사용하면 분산 캐시에서 SQL Server 데이터베이스를 백업 저장소로 사용할 수 있습니다. SQL Server 인스턴스에서 캐시된 SQL Server 항목 테이블을 만들려면 sql-cache 도구를 사용할 수 있습니다. 이 도구는 사용자가 지정한 이름 및 스키마를 사용하여 테이블을 만듭니다.

sql-cache create 명령을 실행하여 SQL Server에서 테이블을 만듭니다. SQL Server 인스턴스(Data Source), 데이터베이스(Initial Catalog), 스키마(예: dbo) 및 테이블 이름(예: TestCache)을 제공합니다.

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

도구가 성공했음을 나타내는 메시지가 기록됩니다.

Table and index were created successfully.

sql-cache 도구에서 만든 테이블에는 다음 스키마가 있습니다.

SqlServer 캐시 테이블

참고 항목

앱은 SqlServerCache가 아닌 IDistributedCache의 인스턴스를 사용하여 캐시 값을 조작해야 합니다.

샘플 앱은 Program.cs의 개발 이외의 환경에서 SqlServerCache를 구현합니다.

builder.Services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString(
        "DistCache_ConnectionString");
    options.SchemaName = "dbo";
    options.TableName = "TestCache";
});

참고 항목

ConnectionString(선택적으로 SchemaNameTableName)은 일반적으로 소스 제어 외부에 저장됩니다(예: Secret Manager 또는 appsettings.json/appsettings.{Environment}.json 파일에 저장됨). 연결 문자열에는 원본 제어 시스템에서 유지되어야 하는 자격 증명이 포함될 수 있습니다.

분산 NCache 캐시

NCache는 원래 .NET 및 .NET Core에서 개발된 오픈 소스 메모리 내 분산 캐시입니다. NCache는 로컬에서 작동하고 Azure 또는 다른 호스팅 플랫폼에서 실행되는 ASP.NET Core 앱에 대한 분산 캐시 클러스터로 구성됩니다.

로컬 컴퓨터에 NCache를 설치 및 구성하려면 Windows를 위한 시작 가이드(.NET 및 .NET Core)를 참조하세요.

NCache를 구성하려면 다음을 수행합니다.

  1. NCache 오픈 소스 NuGet을 설치합니다.
  2. 캐시 클러스터를 client.ncconf에 구성합니다.
  3. 다음 코드를 Program.cs에 추가합니다.
builder.Services.AddNCacheDistributedCache(configuration =>
{
    configuration.CacheName = "democache";
    configuration.EnableLogs = true;
    configuration.ExceptionsEnabled = true;
});

분산 캐시 사용

IDistributedCache 인터페이스를 사용하려면 앱에서 IDistributedCache의 인스턴스를 요청합니다. 인스턴스는 DI(종속성 주입)에서 제공됩니다.

샘플 앱이 시작되면 IDistributedCacheProgram.cs에 삽입됩니다. 현재 시간은 IHostApplicationLifetime을 사용하여 캐시됩니다(자세한 내용은 제네릭 호스트: IHostApplicationLifetime 참조).

app.Lifetime.ApplicationStarted.Register(() =>
{
    var currentTimeUTC = DateTime.UtcNow.ToString();
    byte[] encodedCurrentTimeUTC = System.Text.Encoding.UTF8.GetBytes(currentTimeUTC);
    var options = new DistributedCacheEntryOptions()
        .SetSlidingExpiration(TimeSpan.FromSeconds(20));
    app.Services.GetService<IDistributedCache>()
                              .Set("cachedTimeUTC", encodedCurrentTimeUTC, options);
});

샘플 앱은 인덱스 페이지에서 사용할 수 있도록 IDistributedCacheIndexModel에 삽입합니다.

인덱스 페이지가 로드될 때마다 OnGetAsync에서 캐시된 시간에 대한 캐시를 확인합니다. 캐시된 시간이 만료되지 않은 경우 시간이 표시됩니다. 캐시된 시간에 마지막으로 액세스한 후 20초가 경과한 경우(이 페이지가 마지막으로 로드된 시간) 페이지에는 캐시된 시간 만료가 표시됩니다.

캐시된 시간 다시 설정 단추를 선택하여 캐시된 시간을 현재 시간으로 즉시 업데이트합니다. 단추는 OnPostResetCachedTime 처리기 메서드를 트리거합니다.

public class IndexModel : PageModel
{
    private readonly IDistributedCache _cache;

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

    public string? CachedTimeUTC { get; set; }
    public string? ASP_Environment { get; set; }

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

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

        ASP_Environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
        if (String.IsNullOrEmpty(ASP_Environment))
        {
            ASP_Environment = "Null, so Production";
        }
    }

    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 인스턴스에 대해 싱글톤 또는 범위 수명을 사용할 필요가 없습니다.

DI를 사용하는 대신 IDistributedCache 인스턴스를 만들 수도 있지만, 코드에서 인스턴스를 만들면 코드를 테스트하는 것이 어렵고 명시적 종속성 원칙을 위반하게 될 수 있습니다.

권장 사항

앱에 가장 적합한 IDistributedCache의 구현을 결정할 때 다음 사항을 고려합니다.

  • 기존 인프라
  • 성능 요구 사항
  • 비용
  • 팀 환경

캐싱 솔루션은 일반적으로 메모리 내 스토리지를 사용하여 캐시된 데이터를 신속하게 검색하지만 메모리는 제한된 리소스이며 확장하는 데 비용이 많이 듭니다. 일반적으로 사용되는 데이터만 캐시에 저장합니다.

대부분의 앱에서 Redis 캐시는 SQL Server 캐시보다 더 높은 처리량과 짧은 대기 시간을 제공합니다. 그러나 캐싱 전략의 성능 특성을 확인하려면 벤치마킹을 사용하는 것이 좋습니다.

SQL Server를 분산 캐시 백업 저장소로 사용하는 경우 캐시에 대해 동일한 데이터베이스를 사용하고 앱의 일반 데이터 스토리지 및 검색을 사용하면 두 성능에 부정적인 영향을 줄 수 있습니다. 분산 캐시 백업 저장소에 전용 SQL Server 인스턴스를 사용하는 것이 좋습니다.

추가 리소스

분산 캐시는 여러 앱 서버에서 공유하는 캐시로, 일반적으로 액세스하는 앱 서버에 외부 서비스로 유지 관리됩니다. 분산 캐시는 특히 앱이 클라우드 서비스 또는 서버 팜에서 호스팅되는 경우 ASP.NET Core 앱의 성능과 확장성을 향상시킬 수 있습니다.

분산 캐시는 개별 앱 서버에 캐시된 데이터가 저장되는 다른 캐싱 시나리오에 비해 여러 가지 이점을 제공합니다.

캐시된 데이터를 배포하는 경우 데이터는 다음과 같습니다.

  • 여러 서버에 대한 여러 요청에서 일관됩니다.
  • 서버를 다시 시작하고 앱을 배포할 때 유지됩니다.
  • 로컬 메모리를 사용하지 않습니다.

분산 캐시 구성은 구현별로 다릅니다. 이 문서에서는 SQL Server 및 Redis 분산 캐시를 구성하는 방법을 설명합니다. NCache와 같은 타사 구현도 사용할 수 있습니다(GitHub의 NCache). 선택한 구현과 관계없이 앱은 IDistributedCache 인터페이스를 사용하여 캐시와 상호 작용합니다.

샘플 코드 보기 및 다운로드(다운로드 방법)

필수 조건

SQL Server 분산 캐시를 사용하려면 패키지 참조를 Microsoft.Extensions.Caching.SqlServer 패키지에 추가합니다.

Redis 분산 캐시를 사용하려면 패키지 참조를 Microsoft.Extensions.Caching.StackExchangeRedis 패키지에 추가합니다.

NCache 분산 캐시를 사용하려면 패키지 참조를 NCache.Microsoft.Extensions.Caching.OpenSource 패키지에 추가합니다.

IDistributedCache 인터페이스

IDistributedCache 인터페이스는 분산 캐시 구현에서 항목을 조작하는 다음과 같은 메서드를 제공합니다.

  • Get, GetAsync: 문자열 키를 허용하고 캐시된 항목을 캐시에 있는 경우 byte[] 배열로 검색합니다.
  • Set, SetAsync : 문자열 키를 사용하여 캐시에 항목(byte[] 배열로)을 추가합니다.
  • Refresh, RefreshAsync: 해당 키를 기준으로 캐시의 항목을 새로 고쳐 상대 만료 시간 제한(있는 경우)을 다시 설정합니다.
  • Remove, RemoveAsync: 해당 문자열 키를 기준으로 캐시 항목을 제거합니다.

분산 캐싱 서비스 설정

Startup.ConfigureServices에서 IDistributedCache에 대한 구현을 등록합니다. 이 항목에서 설명하는 프레임워크 제공 구현에는 다음이 포함됩니다.

분산 메모리 캐시

분산 메모리 캐시(AddDistributedMemoryCache)는 메모리에 항목을 저장하는 IDistributedCache의 프레임워크 제공 구현입니다. 분산 메모리 캐시는 실제 분산된 캐시가 아닙니다. 캐시된 항목은 앱이 실행되고 있는 서버의 앱 인스턴스에 의해 저장됩니다.

분산 메모리 캐시는 다음과 같은 경우 유용합니다.

  • 개발 및 테스트 시나리오에서.
  • 프로덕션 환경에서 단일 서버를 사용하고 메모리 소비가 문제가 되지 않는 경우. 분산 메모리 캐시를 구현할 때 캐시된 데이터 스토리지를 추상화합니다. 이를 통해 나중에 여러 노드 또는 내결함성이 필요한 경우 진정한 분산 캐싱 솔루션을 구현할 수 있습니다.

샘플 앱은 앱이 Startup.ConfigureServices의 개발 환경에서 실행될 때 분산 메모리 캐시를 사용합니다.

services.AddDistributedMemoryCache();

분산 SQL Server 캐시

분산 SQL Server 캐시 구현(AddDistributedSqlServerCache)을 사용하면 분산 캐시에서 SQL Server 데이터베이스를 백업 저장소로 사용할 수 있습니다. SQL Server 인스턴스에서 캐시된 SQL Server 항목 테이블을 만들려면 sql-cache 도구를 사용할 수 있습니다. 이 도구는 사용자가 지정한 이름 및 스키마를 사용하여 테이블을 만듭니다.

sql-cache create 명령을 실행하여 SQL Server에서 테이블을 만듭니다. SQL Server 인스턴스(Data Source), 데이터베이스(Initial Catalog), 스키마(예: dbo) 및 테이블 이름(예: TestCache)을 제공합니다.

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

도구가 성공했음을 나타내는 메시지가 기록됩니다.

Table and index were created successfully.

sql-cache 도구에서 만든 테이블에는 다음 스키마가 있습니다.

SqlServer 캐시 테이블

참고 항목

앱은 SqlServerCache가 아닌 IDistributedCache의 인스턴스를 사용하여 캐시 값을 조작해야 합니다.

샘플 앱은 Startup.ConfigureServices의 개발 이외의 환경에서 SqlServerCache를 구현합니다.

services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = 
        _config["DistCache_ConnectionString"];
    options.SchemaName = "dbo";
    options.TableName = "TestCache";
});

참고 항목

ConnectionString(선택적으로 SchemaNameTableName)은 일반적으로 소스 제어 외부에 저장됩니다(예: Secret Manager 또는 appsettings.json/appsettings.{Environment}.json 파일에 저장됨). 연결 문자열에는 원본 제어 시스템에서 유지되어야 하는 자격 증명이 포함될 수 있습니다.

분산 Redis Cache

Redis는 분산 캐시로 자주 사용되는 오픈 소스 메모리 내 데이터 저장소입니다. Azure에서 호스팅되는 ASP.NET Core 앱에 대한 Azure Redis Cache를 구성하고 로컬 개발에 Azure Redis Cache를 사용할 수 있습니다.

앱은 RedisCache 인스턴스(AddStackExchangeRedisCache)를 사용하여 캐시 구현을 구성합니다.

  1. Azure Cache for Redis를 만듭니다.
  2. 기본 연결 문자열(StackExchange.Redis)을 구성에 복사합니다.
    • 로컬 개발: 비밀 관리자를 사용하여 연결 문자열을 저장합니다.
    • Azure: 연결 문자열을 App Service 구성 또는 다른 보안 저장소에 저장합니다.

다음 코드는 Azure Cache for Redis를 사용하도록 설정합니다.

public void ConfigureServices(IServiceCollection services)
{
    if (_hostContext.IsDevelopment())
    {
        services.AddDistributedMemoryCache();
    }
    else
    {
        services.AddStackExchangeRedisCache(options =>
        {
            options.Configuration = _config["MyRedisConStr"];
            options.InstanceName = "SampleInstance";
        });
    }

    services.AddRazorPages();
}

위의 코드에서는 기본 연결 문자열(StackExchange.Redis)이 키 이름 MyRedisConStr로 구성에 저장되었다고 가정합니다.

자세한 내용은 Azure Cache for Redis를 참조하세요.

로컬 Redis Cache에 대한 대체 접근 방식에 대한 설명은 이 GitHub 문제를 참조하세요.

분산 NCache 캐시

NCache는 원래 .NET 및 .NET Core에서 개발된 오픈 소스 메모리 내 분산 캐시입니다. NCache는 로컬에서 작동하고 Azure 또는 다른 호스팅 플랫폼에서 실행되는 ASP.NET Core 앱에 대한 분산 캐시 클러스터로 구성됩니다.

로컬 컴퓨터에 NCache를 설치 및 구성하려면 Windows를 위한 시작 가이드(.NET 및 .NET Core)를 참조하세요.

NCache를 구성하려면 다음을 수행합니다.

  1. NCache 오픈 소스 NuGet을 설치합니다.

  2. 캐시 클러스터를 client.ncconf에 구성합니다.

  3. 다음 코드를 Startup.ConfigureServices에 추가합니다.

    services.AddNCacheDistributedCache(configuration =>    
    {        
        configuration.CacheName = "demoClusteredCache";
        configuration.EnableLogs = true;
        configuration.ExceptionsEnabled = true;
    });
    

분산 캐시 사용

IDistributedCache 인터페이스를 사용하려면 앱의 모든 생성자에서 IDistributedCache의 인스턴스를 요청합니다. 인스턴스는 DI(종속성 주입)에서 제공됩니다.

샘플 앱이 시작되면 IDistributedCacheStartup.Configure에 삽입됩니다. 현재 시간은 IHostApplicationLifetime을 사용하여 캐시됩니다(자세한 내용은 제네릭 호스트: IHostApplicationLifetime 참조).

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, 
    IHostApplicationLifetime 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에 삽입합니다.

인덱스 페이지가 로드될 때마다 OnGetAsync에서 캐시된 시간에 대한 캐시를 확인합니다. 캐시된 시간이 만료되지 않은 경우 시간이 표시됩니다. 캐시된 시간에 마지막으로 액세스한 후 20초가 경과한 경우(이 페이지가 마지막으로 로드된 시간) 페이지에는 캐시된 시간 만료가 표시됩니다.

캐시된 시간 다시 설정 단추를 선택하여 캐시된 시간을 현재 시간으로 즉시 업데이트합니다. 단추는 OnPostResetCachedTime 처리기 메서드를 트리거합니다.

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 인스턴스에 대해 싱글톤 또는 범위가 지정된 수명을 사용할 필요는 없습니다(최소한 기본 제공 구현의 경우).

DI를 사용하는 대신 IDistributedCache 인스턴스를 만들 수도 있지만, 코드에서 인스턴스를 만들면 코드를 테스트하는 것이 어렵고 명시적 종속성 원칙을 위반하게 될 수 있습니다.

권장 사항

앱에 가장 적합한 IDistributedCache의 구현을 결정할 때 다음 사항을 고려합니다.

  • 기존 인프라
  • 성능 요구 사항
  • 비용
  • 팀 환경

캐싱 솔루션은 일반적으로 메모리 내 스토리지를 사용하여 캐시된 데이터를 신속하게 검색하지만 메모리는 제한된 리소스이며 확장하는 데 비용이 많이 듭니다. 일반적으로 사용되는 데이터만 캐시에 저장합니다.

일반적으로 Redis Cache는 SQL Server 캐시보다 높은 처리량과 짧은 대기 시간을 제공합니다. 그러나 일반적으로 벤치마킹은 캐싱 전략의 성능 특성을 결정하는 데 필요합니다.

SQL Server를 분산 캐시 백업 저장소로 사용하는 경우 캐시에 대해 동일한 데이터베이스를 사용하고 앱의 일반 데이터 스토리지 및 검색을 사용하면 두 성능에 부정적인 영향을 줄 수 있습니다. 분산 캐시 백업 저장소에 전용 SQL Server 인스턴스를 사용하는 것이 좋습니다.

추가 리소스