NCache Entity Framework Core(EF Core)용 분산형 인메모리 캐시 공급자인 `CacheProvider`는 쿼리 결과를 캐싱하여 데이터베이스 병목 현상을 해소합니다. 하지만 몇 가지 한계점이 있습니다. 트랜잭션이 많은 EF Core 애플리케이션은 과도한 데이터베이스 쿼리로 인해 데이터베이스 계층에서 성능 문제가 발생할 가능성이 높습니다. 애플리케이션 계층은 수평 확장이 가능하지만, 데이터베이스 계층은 병목 현상을 일으킵니다.
NCache, 100% 네이티브 .NET 분산 캐시는 자주 액세스하는 데이터를 캐싱하고 데이터베이스 쿼리를 오프로드하여 EF Core 애플리케이션을 향상시킵니다. 이를 통해 성능과 확장성이 향상되고 데이터베이스의 전체 부하가 줄어듭니다.
NCache 확장하다 EF 코어 C# 확장 메서드를 사용하면 기존 논리를 수정하지 않고도 원활한 캐싱이 가능합니다.
거래 데이터에는 고객 정보, 주문, 거래 내역 등 자주 변경되는 레코드가 포함됩니다. 자주 액세스하는 이러한 데이터를 단기적으로 캐싱하면 데이터베이스 쿼리가 감소하고, 응답 시간이 단축되며, 경합이 최소화됩니다.
행동 양식: 캐시에서(), FromCacheAsync()
FromCache(): 캐시가 있으면 쿼리 결과를 검색하고, 그렇지 않으면 데이터베이스에서 가져와 나중에 사용할 수 있도록 캐시에 저장합니다. 캐시에서() 그룹화, 오름차순 정렬, 내림차순 정렬, 합계, 최소값, 최대값, 평균, 개수, 포함, 유사값 및 FirstOrDefault 함수를 지원합니다.
var resultSet = (from cust in context.Customers
where cust.CustomerId == someCustomerId
select cust).FromCache(options).ToList();
참조 데이터에는 제품 카탈로그나 조회 값과 같은 비교적 정적인 데이터 세트가 포함됩니다. 이러한 데이터를 장기간 캐싱하면 중복된 데이터베이스 쿼리를 제거하여 애플리케이션 속도를 향상시킬 수 있습니다.
행동 양식: 로드인투캐시(), LoadIntoCacheAsync()
로드인투캐시(): 전체 데이터 세트를 캐시에 로드하여 후속 쿼리가 데이터베이스가 아닌 캐시에서 직접 데이터를 검색할 수 있도록 합니다.
var resultSet = (from custOrder in context.Orders
where custOrder.Customer.CustomerId == someCustomerId
select custOrder).LoadIntoCache(out string cacheKey, options);
캐시에서 직접 참조 데이터를 검색하면 애플리케이션이 데이터베이스 쿼리를 피하고 응답 시간을 개선할 수 있습니다. 그러나 정확한 결과를 보장하고 불완전한 쿼리 응답을 피하려면 전체 데이터 세트를 캐시에 미리 로드해야 합니다. (데이터베이스 호출 없이 캐시에서 직접 데이터 검색).
행동 양식: FromCacheOnly(), FromCacheOnlyAsync()
FromCacheOnly(): 캐시에서만 쿼리 결과를 가져오고 데이터베이스에는 쿼리를 실행하지 않으므로 미리 로드된 데이터세트에 대한 초고속 조회가 가능합니다. 하지만 이 기능을 효과적으로 사용하려면 쿼리 정확도를 유지하기 위해 전체 데이터세트를 캐시해야 합니다.
var resultSet = (from cust in context.Customers
where cust.CustomerId == someCustomerId
select cust).FromCacheOnly();
NCache EF Core 확장 메서드에만 의존하지 않고 캐시된 엔터티를 효율적으로 관리하기 위한 직접 API를 제공합니다. 개발자는 캐싱 API를 통해 프로그래밍 방식으로 캐시에 객체를 삽입, 업데이트 및 제거할 수 있으며, 이를 통해 고성능 애플리케이션을 위한 데이터 검색을 최적화하는 동시에 캐싱 동작을 세부적으로 제어할 수 있습니다.
캐시에서 엔터티를 직접 삽입, 제거 및 업데이트합니다.
ICache cache = CacheManager.GetCache(cacheName);
// Inserting an entity into cache
cache.Insert(customerKey, cacheItem);
지연된 쿼리 실행을 통해 애플리케이션은 다음과 같은 집계 함수를 수행할 수 있습니다. 세다(), 합집합()예산 및 평균() 데이터베이스를 반복적으로 쿼리하는 대신 캐시된 데이터에서 직접 처리합니다. 이 기능은 개수 및 합계와 같은 집계 작업을 메모리 캐시 내에서 직접 실행함으로써 대규모 데이터 세트를 클라이언트로 가져오는 데 필요한 네트워크 오버헤드를 제거합니다. 이를 통해 중복 쿼리가 줄어들고 성능이 향상되며 트랜잭션이 많은 환경에서 데이터 검색 속도가 빨라집니다.
using (var context = new NorthwindContext())
{
var resultSet = context.Products
.Where(p => p.UnitPrice == 10)
.GroupBy(p => p.ProductName)
.Select(group => group.Key)
.FromCache(out cacheKey, options)
.ToList();
}
NCache 애플리케이션이 캐시된 데이터에 대해 직접 LINQ 쿼리를 실행할 수 있도록 하여 반복적인 데이터베이스 쿼리를 수행할 필요가 없습니다. 메모리 내 처리를 활용함으로써 이러한 접근 방식은 쿼리 성능을 크게 향상시키고 데이터베이스 부하를 줄입니다. 데이터베이스에 접근하지 않고도 캐시된 데이터에 대해 직접 LINQ 쿼리를 실행할 수 있습니다.
using (var context = new NorthwindContext())
{
var result = context.Customers
.Where(b => (b.CompanyName.Contains("Alfreds Futterkist")))
.FromCacheOnly()
}
NCache 개발자가 애플리케이션 요구 사항에 따라 캐시 동작을 사용자 정의할 수 있는 캐싱 옵션을 제공합니다. 이를 통해 데이터 스토리지를 더 잘 제어하고, 만료 정책을 설정하고, 자동 무효화를 위한 SQL 종속성 추적을 활성화하고, 효율적인 검색을 위해 캐시에 데이터를 저장하는 방법을 정의할 수 있습니다.
var options = new CachingOptions
{
QueryIdentifier = "CustomerEntity",
CreateDbDependency = true,
StoreAs = StoreAs.SeperateEntities,
Priority = Runtime.CacheItemPriority.High
};
options.SetAbsoluteExpiration(DateTime.Now.AddSeconds(20));
NCache 캐시 사용량을 추적하고, 성능 지표를 측정하고, 잠재적 문제를 실시간으로 감지하는 기본 로깅 및 모니터링 기능이 포함되어 있습니다. Microsoft.Extensions.Logging과 완벽하게 통합되어 개발자가 캐시 동작을 분석하고, 문제를 해결하고, 성능을 효율적으로 최적화할 수 있습니다.
Install-Package EntityFrameworkCore.NCache
public partial class NorthwindContext : DbContext
{
...
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// Parameters specified in App.config
string cacheId = ConfigurationManager.AppSettings["CacheId"];
string connString = ConfigurationManager.AppSettings["ConnString"];
bool errorEnabled = bool.Parse(ConfigurationManager.AppSettings["ErrorEnabled"]);
int bulkInsertChunkSize = Int32.Parse(ConfigurationManager.AppSettings["BulkInsertChunkSize"]);
// Configure cache with connection retries and security
var options = new CacheConnectionOptions();
options.RetryInterval = TimeSpan.FromSeconds(3);
options.ConnectionRetries = 2;
options.ServerList = new List<ServerInfo>()
{
new ServerInfo("20.200.20.XX", 9800)
};
// Configure cache with security
options.UserCredentials = new Credentials("john_smith", "12345");
NCacheConfiguration.Configure(cacheId, DependencyType.SqlServer, options, errorEnabled, bulkInsertChunkSize);
optionsBuilder.UseSqlServer(connString);
}
}