개인적으로 캐시를 서비스 레이어에서 할 지 HttpClient에서 할 지 고민됩니다.
클라이언트 측에서 캐시를 한다는 생각 자체를 해 본 적이 없었는데, 많이 흥미로운 주제네요.
저자는 Http Get 요청에 대해 캐시가 유용하다고 말하고 있는데,
One thing that is missing from the out-of-the box behaviours is caching of GET requests (only ones that can be cached!), …
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (_cache.TryGetValue(request.RequestUri!, out var response) && response is HttpResponseMessage res)
{
_logger.LogInformation($"Getting response from cache for {request.RequestUri}");
}
else
{
res = await base.SendAsync(request, cancellationToken);
res.EnsureSuccessStatusCode();
res.Content = new NoDisposeStreamContent(res.Content);
_cache.Set(request.RequestUri!, res, DateTimeOffset.Now.Add(_duration));
_logger.LogInformation($"Adding response for {request.RequestUri} to cache for {_duration}");
}
return res;
}
아무리 Get 이라도, 이 캐시를 쓸 때는 좀 신중해야 할 필요가 있을 것 같은데, 주로 어떤 항목에 사용하시는지 여쭤봐도 될까요?
MSA로 k8s를 사용하다 보니 서비스간 원격 호출을 사용하는 경우가 종종 있습니다.
pod에서 response를 캐싱하지만 추가로 원격 호출을 하지 않고 캐싱된 데이터를 사용하는 것도 생각해 보는 중입니다.
결국은 클라이언트가 캐시를 한다는 기본 구조는 동일한 것 같은데, 제가 염려하는 바는 클라이언트 캐시의 유효성입니다.
원글의 저자는 캐시의 기본 수명을 한 시간으로 설정하고 있는데,
public class CachingHandler : DelegatingHandler
{
private static readonly TimeSpan _defaultDuration = TimeSpan.FromHours(1);
이 값은 보통 서버 측(파드 측) 캐싱 예제에서 많이 보이더군요.
그런데, 서버는 실제 데이터를 관리하므로, 기본 값이 큰 의미가 없습니다.
Get/Post/Put/Delete 을 처리할 때 마다 캐시를 업데이트 할 수 있으니까요.
그런데, 클라이언트 측은 그렇지가 않죠.
쿠버네티스까지 동원될 정도로 거대 사이트면 데이터의 업데이트가 매우 잦을 것이고, 클라이언트 측 캐시는 쉽게 무효화될 것이라는 것이 제 추측입니다.
(이 것이 분산 캐시를 채택하는 이유라고 생각합니다)
클라이언트 캐시의 유효성을 담보하는 다른 수단이라도 있으신지요?
염려되는 상황은 원격 호출로 인한 오류 발생이 더 큽니다.
pod 끼리 상호 통신을 하면서 서버이자 클라이언트가 되는데요.
원격 호출을 줄여서 얻는 이득이 더 큰 부분에 캐싱을 어떻게 할 까 고민하던 중이었어요.
갱신이 불필요한 기준정보 같은 건 한번 입력하면 바뀌는 일이 없지만 GET은 매우 빈번해서
요 부분은 제가 고려하지 못한 부분이네요.
만약 캐시한다면 캐시 헤더를 기반으로 Response 캐시할 수도 있고, 혹은 라이브러리를 통해서 캐시하도록 하는 방식도 있으니 고민할 거리가 많을 것 같습니다.
Cache-Control 과 캐시 헤더를 통한 HttpClient 캐시 글
https://mac-blog.org.ua/dotnet-http-client-cache/
WebSocket 기반 RPC와 인메모리 캐시로 통신 레이어 따로 구현
stale-while-revalidate 기반으로 간단하게 구현한 라이브러리