2023. 6. 19. 17:19ㆍLanguage/C#
개요
프로젝트의 성능을 향상 시키기 위해서 캐싱을 많이 사용합니다. 캐싱으로 유명한 Redis를 사용 할 수도 있지만, 작은 프로젝트에서는 Redis를 따로 사용하지 못하는 경우도 있습니다.
그래서 C#에서는 캐시를 구현 할 수 있는 MemoryCache 클래스를 제공합니다.
이 클래스는 객체의 삽입, 갱신, 삭제와 같은 작업을 메모리상에서 처리하기 때문에 데이터베이스에 부담을 줄이고 좀 더 개발하기 편하게 해줍니다.
IMemoryCache
IMemoryCache는 Microsoft.Extensions.Caching.Memory
패키지에서 사용 할 수 있습니다.
간단하게 Visual Studio를 사용해서 .NET 7 ASP.NET Core 웹 API 프로젝트를 생성해서 진행하도록 하겠습니다.
프로젝트를 생성하면 Controllers 폴더에 WeatherForecastController.cs
파일이 존재합니다.
프로젝트를 실행시켜 보면 Swagger가 실행되며 /WeatherForecast
주소로 HttpGet을 통해 데이터를 받아 올 수 있습니다.
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get(int param)
{
return Enumerable.Range(1, param).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(param)),
TemperatureC = param + 20,
Summary = Summaries[param]
}).ToArray();
}
Get 메서드에 파라미터를 넣어 해당 파라미터로 조회 할 때 같은 값이 나오도록 수정했습니다.
이제 저 param
이 캐싱의 Key가 되어 사용 됩니다.
DI 추가하기
IMemoryCache
는 아래와 같이 Program.cs
에 간단하게 DI를 할 수 있습니다.
builder.Services.AddMemoryCache();
그리고 생성자를 통해 객체를 받습니다.
private readonly ILogger<WeatherForecastController> _logger;
private readonly IMemoryCache _memoryCache;
public WeatherForecastController(
ILogger<WeatherForecastController> logger,
IMemoryCache memoryCache
)
{
_memoryCache = memoryCache;
_logger = logger;
}
캐싱 구현하기
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get(int param)
{
var cachedResult = _memoryCache.Get<IEnumerable<WeatherForecast>>(param);
if( cachedResult is null )
{
var result = Enumerable.Range(1, param).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(param)),
TemperatureC = param + 20,
Summary = Summaries[param]
}).ToArray();
_memoryCache.Set(param, result);
return result;
}
return cachedResult;
}
위 코드는 간단 합니다. _memoryCache.Get<IEnumerable<WeatherForecast>>(param);
를 통해 캐싱 되어 있는 데이터가 있는지 확인해서 없으면 생성해서 반환하고 있으면 캐싱 된 데이터를 바로 반환하면 됩니다.
MemoryCacheEntryOptions
캐싱이 데이터베이스에 부담을 줄이고 속도를 개선 할 수 있지만, 메모리의 한계와 캐싱 된 데이터를 갱신 해야하기 때문에 특정 시점에 캐싱 된 데이터를 삭제해야 합니다.
그러기 위해서는 MemoryCacheEntryOptions
을 통해 간단하게 구현 할 수 있습니다.
AbsoluteExpiration
DateTimeOffset 타입의 절대 만료 시각을 설정합니다. 만료 시각이 지나게 되면 캐시에서 해당 데이터가 삭제됩니다.
// 10분 이후에 만료됨
var options = new MemoryCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(10)
};
AbsoluteExpirationRelativeToNow
현재 시각(DateTimeOffset.Now)을 기준으로 상대적인 만료 시각을 설정합니다. 만료 시각이 지나게 되면 캐시에서 해당 데이터가 삭제됩니다.
// 10분 이후에 만료됨
var options = new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
};
SlidingExpiration
마지막으로 캐시된 시각 이후에 지정한 시간(TimeSpan)이 경과하면 만료됩니다. 이 시간이 지나기 전에 해당 데이터가 다시 캐시되면 만료 시간이 다시 시작됩니다.
// 데이터에 대한 마지막 접근 이후 10분이 지나면 만료됨
var options = new MemoryCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromMinutes(10)
};
Priority
캐시 데이터에 대한 우선순위를 나타내는 CacheItemPriority 열거형입니다. 캐시 데이터에 어떤 우선순위를 부여하면 메모리 부족 상황에서 캐시 데이터를 삭제할 때 이 우선순위에 따라 삭제할 데이터를 결정합니다.
// 우선 순위가 높음 (캐시를 보관하려는 가치가 높음)
var options = new MemoryCacheEntryOptions
{
Priority = CacheItemPriority.High
};
Size
캐시 데이터의 크기 (바이트)를 설정합니다. 이 속성으로 캐시 데이터 총 크기의 상한선을 설정할 수 있는데, 이 설정에 따라 캐시 데이터가 메모리에 남아있을 수 있는지 여부를 결정합니다.
// 최대 크기 1KB 를 허용함
var options = new MemoryCacheEntryOptions
{
SizeLimit = 1024
};
PostEvictionCallbacks
캐시에서 데이터가 제거될 때 실행될 콜백들을 저장할 수 있는 PostEvictionDelegate 델리게이트의 리스트입니다. 예를 들어 캐시된 데이터가 제거되면 로그 기록 등의 작업을 실행할 수 있습니다.
// 데이터가 제거될 때 로그 기록 실행
var options = new MemoryCacheEntryOptions
{
PostEvictionCallbacks =
{
new PostEvictionCallbackRegistration
{
EvictionCallback = (key, value, reason, state) =>
{
Console.WriteLine($"[{DateTime.Now}] 캐시 제거 - Reason: {reason}, Key: {key}, Value: {value}");
}
}
}
};
'Language > C#' 카테고리의 다른 글
Task vs. ValueTask (0) | 2023.06.17 |
---|---|
dotnet cli nuget 저장소 지정 (0) | 2023.06.16 |
.NET AOP DynamicProxy (0) | 2023.06.05 |
StringBuilder vs String Join (0) | 2023.06.04 |
상속에서 Dispose 패턴 (0) | 2023.05.31 |