다음을 통해 공유


분산 캐싱(Azure를 사용하여 Real-World Cloud Apps 빌드)

작성자 : Rick Anderson, Tom Dykstra

수정 프로젝트 다운로드 또는 전자책 다운로드

Azure 전자책 을 사용하여 Real World Cloud Apps 빌드 는 Scott Guthrie가 개발한 프레젠테이션을 기반으로 합니다. 클라우드용 웹앱을 성공적으로 개발하는 데 도움이 될 수 있는 13개의 패턴과 사례를 설명합니다. 전자책에 대한 자세한 내용은 첫 번째 장을 참조하세요.

이전 장에서는 일시적인 오류 처리를 살펴보고 회로 차단기 전략으로 캐싱을 언급했습니다. 이 장에서는 캐싱 사용 시기, 캐싱을 사용하는 일반적인 패턴 및 Azure에서 구현하는 방법을 포함하여 캐싱에 대한 자세한 배경을 제공합니다.

분산 캐싱이란?

캐시는 메모리에 데이터를 저장하여 일반적으로 액세스하는 애플리케이션 데이터에 대한 높은 처리량, 짧은 대기 시간 액세스를 제공합니다. 클라우드 앱의 경우 가장 유용한 캐시 유형은 분산 캐시입니다. 즉, 데이터는 개별 웹 서버의 메모리에 저장되지 않고 다른 클라우드 리소스에 저장되며 캐시된 데이터는 애플리케이션의 모든 웹 서버(또는 애플리케이션에서 사용되는 다른 클라우드 VM)에서 사용할 수 있습니다.

동일한 캐시 서버에 액세스하는 여러 웹 서버를 보여 주는 다이어그램

애플리케이션이 서버를 추가하거나 제거하여 확장되거나 업그레이드 또는 오류로 인해 서버가 교체되는 경우 캐시된 데이터는 애플리케이션을 실행하는 모든 서버에서 계속 액세스할 수 있습니다.

영구 데이터 저장소의 대기 시간이 긴 데이터 액세스를 방지함으로써 캐싱은 애플리케이션 응답성을 크게 향상시킬 수 있습니다. 예를 들어 캐시에서 데이터를 검색하는 것은 관계형 데이터베이스에서 데이터를 검색하는 것보다 훨씬 빠릅니다.

캐싱의 측면 이점은 영구 데이터 저장소에 대한 트래픽을 줄여 영구 데이터 저장소에 대한 데이터 송신 요금이 있을 때 비용이 낮아질 수 있다는 것입니다.

분산 캐싱을 사용하는 경우

캐싱은 데이터 쓰기보다 더 많은 읽기를 수행하는 애플리케이션 워크로드와 데이터 모델이 캐시에 데이터를 저장하고 검색하는 데 사용하는 키/값 organization 지원하는 경우에 가장 적합합니다. 또한 애플리케이션 사용자가 많은 공통 데이터를 공유할 때 더 유용합니다. 예를 들어 각 사용자가 일반적으로 해당 사용자에게 고유한 데이터를 검색하는 경우 캐시는 많은 이점을 제공하지 않습니다. 캐싱이 매우 유용한 예는 데이터가 자주 변경되지 않고 모든 고객이 동일한 데이터를 보고 있기 때문에 제품 카탈로그입니다.

영구 데이터 저장소의 처리량 제한 및 대기 시간 지연이 전체 애플리케이션 성능에 대한 제한이 커짐에 따라 캐싱의 이점은 애플리케이션 스케일링이 늘어나면서 점점 더 측정할 수 있게 됩니다. 그러나 성능 이외의 다른 이유로 캐싱을 구현할 수도 있습니다. 사용자에게 표시될 때 완벽하게 최신 상태가 될 필요가 없는 데이터의 경우 캐시 액세스는 영구 데이터 저장소가 응답하지 않거나 사용할 수 없는 경우에 대한 회로 차단기 역할을 할 수 있습니다.

캐시에서 데이터를 검색하려면 먼저 캐시에 저장해야 합니다. 캐시에 필요한 데이터를 가져오기 위한 몇 가지 전략이 있습니다.

  • 주문형/캐시 제외

    애플리케이션은 캐시에서 데이터를 검색하려고 시도하며 캐시에 데이터("누락")가 없는 경우 애플리케이션은 다음에 사용할 수 있도록 캐시에 데이터를 저장합니다. 다음에 애플리케이션이 동일한 데이터를 얻으려고 시도하면 캐시에서 찾고 있는 항목("적중")을 찾습니다. 데이터베이스에서 변경된 캐시된 데이터를 가져오지 않도록 하려면 데이터 저장소를 변경할 때 캐시를 무효화합니다.

  • 백그라운드 데이터 푸시

    백그라운드 서비스는 정기적인 일정에 따라 데이터를 캐시에 푸시하고 앱은 항상 캐시에서 가져옵니다. 이 방법은 항상 최신 데이터를 반환할 필요가 없는 대기 시간이 긴 데이터 원본에서 잘 작동합니다.

  • 회로 차단기

    애플리케이션은 일반적으로 영구 데이터 저장소와 직접 통신하지만 영구 데이터 저장소에 가용성 문제가 있는 경우 애플리케이션은 캐시에서 데이터를 검색합니다. 캐시를 따로 사용하거나 백그라운드 데이터 푸시 전략을 사용하여 데이터를 캐시에 넣었을 수 있습니다. 이는 성능 향상 전략이 아닌 오류 처리 전략입니다.

캐시의 데이터를 최신 상태로 유지하기 위해 애플리케이션에서 데이터를 만들거나 업데이트하거나 삭제할 때 관련 캐시 항목을 삭제할 수 있습니다. 애플리케이션에서 약간 오래된 데이터를 가져오는 것이 괜찮은 경우 구성 가능한 만료 시간을 사용하여 이전 캐시 데이터의 수에 대한 제한을 설정할 수 있습니다.

절대 만료(캐시 항목이 생성된 이후의 시간) 또는 슬라이딩 만료(캐시 항목에 마지막으로 액세스한 이후의 시간)를 구성할 수 있습니다. 절대 만료는 캐시 만료 메커니즘에 따라 데이터가 너무 부실해지는 것을 방지하는 경우에 사용됩니다. 수정 앱에서는 부실 캐시 항목을 수동으로 제거하고 슬라이딩 만료를 사용하여 최신 데이터를 캐시에 유지합니다. 선택한 만료 정책에 관계없이 캐시의 메모리 제한에 도달하면 캐시에서 가장 오래된(가장 최근에 사용한 항목 또는 LRU) 항목이 자동으로 제거됩니다.

수정 앱에 대한 샘플 캐시 배제 코드

다음 샘플 코드에서는 수정 작업을 검색할 때 캐시를 먼저 검사. 작업이 캐시에 있으면 반환됩니다. 찾을 수 없으면 데이터베이스에서 가져와서 캐시에 저장합니다. 메서드에 캐싱을 추가하기 위해 FindTaskByIdAsync 수행한 변경 내용이 강조 표시됩니다.

public async Task<FixItTask> FindTaskByIdAsync(int id)
 {
    FixItTask fixItTask = null;
    Stopwatch timespan = Stopwatch.StartNew();
    string hitMiss = "Hit";

    try
    {
       fixItTask = (FixItTask)cache.Get(id.ToString());
       if (fixItTask == null)
       {
          fixItTask = await db.FixItTasks.FindAsync(id);
          cache.Put(id.ToString(), fixItTask);
          hitMiss = "Miss";
       }

       timespan.Stop();
       log.TraceApi("SQL Database", "FixItTaskRepository.FindTaskByIdAsync", timespan.Elapsed, 
                    "cache {0}, id={1}", hitMiss, id);
    }
    catch (Exception e)
    {
       log.Error(e, "Error in FixItTaskRepository.FindTaskByIdAsynx(id={0})", id);
    }

    return fixItTask;
 }

수정 작업을 업데이트하거나 삭제할 때 캐시된 작업을 무효화(제거)해야 합니다. 그렇지 않으면 나중에 해당 작업을 읽으려는 시도는 캐시에서 이전 데이터를 계속 가져옵니다.

public async Task UpdateAsync(FixItTask taskToSave)
{
   Stopwatch timespan = Stopwatch.StartNew();

   try
   {
      cache.Remove(taskToSave.FixItTaskId.ToString());
      db.Entry(taskToSave).State = EntityState.Modified;
      await db.SaveChangesAsync();

      timespan.Stop();
      log.TraceApi("SQL Database", "FixItTaskRepository.UpdateAsync", timespan.Elapsed, "taskToSave={0}", taskToSave);
   }
   catch (Exception e)
   {
      log.Error(e, "Error in FixItTaskRepository.UpdateAsync(taskToSave={0})", taskToSave);
   }
}

간단한 캐싱 코드를 설명하는 샘플입니다. 캐싱은 다운로드 가능한 수정 프로젝트에서 구현되지 않았습니다.

Azure 캐싱 서비스

Azure는 다음과 같은 캐싱 서비스를 제공합니다. Azure Redis CacheAzure Managed Cache. Azure Redis Cache는 인기 있는 오픈 소스 Redis Cache를 기반으로 하며 대부분의 캐싱 시나리오에서 가장 먼저 선택됩니다.

캐시 공급자를 사용하여 세션 상태 ASP.NET

웹 개발 모범 사례 챕터에서 설명한 대로 모범 사례는 세션 상태를 사용하지 않는 것입니다. 애플리케이션에 세션 상태가 필요한 경우 다음 모범 사례는 스케일 아웃(웹 서버의 여러 인스턴스)을 사용하도록 설정하지 않으므로 기본 메모리 내 공급자를 방지하는 것입니다. ASP.NET SQL Server 세션 상태 공급자를 사용하면 여러 웹 서버에서 실행되는 사이트에서 세션 상태를 사용할 수 있지만 메모리 내 공급자에 비해 대기 시간이 더 많이 발생합니다. 세션 상태를 사용해야 하는 경우 가장 좋은 해결 방법은 Azure Cache용 세션 상태 공급자와 같은 캐시 공급자를 사용하는 것입니다.

요약

응답 시간과 확장성을 개선하고 데이터베이스를 사용할 수 없을 때 앱이 읽기 작업에 계속 응답할 수 있도록 수정 앱에서 캐싱을 구현하는 방법을 살펴보았습니다. 다음 챕터에서는 확장성을 더욱 개선하고 앱이 쓰기 작업에 대해 계속 응답하도록 하는 방법을 보여 줍니다.

리소스

캐싱에 대한 자세한 내용은 다음 리소스를 참조하세요.

설명서

동영상

  • FailSafe: 확장 가능하고 복원력 있는 Cloud Services 빌드합니다. 울리히 호만, 마크 메르쿠리, 마크 심스의 9부작 시리즈. 클라우드 앱을 설계하는 방법에 대한 400 수준 보기를 제공합니다. 이 시리즈는 이론과 이유에 초점을 맞추고; 자세한 방법은 Mark Simms의 빌드 빅 시리즈를 참조하세요. 1:24:14부터 시작되는 에피소드 3의 캐싱 토론을 참조하세요.
  • 큰 빌드: Azure 고객으로부터 배운 교훈 - 1부. Simon Davies가 46:00부터 분산 캐싱에 대해 설명합니다. Failsafe 시리즈와 비슷하지만 자세한 방법 세부 정보로 이동합니다. 이 프레젠테이션은 2012년 10월 31일에 제공되었으므로 2013년에 도입된 Azure App Service Web Apps 캐싱 서비스를 다루지 않습니다.

코드 샘플