.Net 솔루션에서 Redis를 사용하는 방법
여기에서 마지막으로 글을 쓰는 것이 오랜만입니다.
음, 지난번 이후로 저는 .Net 및 인프라/DevOps 문제에 대해 많은 작업을 시작했습니다. 내 일상의 첫 번째이자 가장 일반적인 문제 중 하나는 Redis를 사용하여 API 결과를 캐싱하는 방법을 구현하는 것입니다.
교훈적인 목적으로 캐시는 임시 데이터 저장 장소입니다. 이 데이터는 모든 종류의 응용 프로그램에서 사용되며 이를 구현하면 대역폭 절약, 더 빠른 응답 시간, 더 적은 데이터베이스 적중 등과 같은 많은 이점을 얻을 수 있지만 신중하게 구현하지 않으면 많은 피해를 줄 수 있습니다.
이 게시물을 위해 만든 코드는 in this GitHub repository 에서 찾을 수 있습니다. 거대한 포켓몬 데이터베이스인 PokéAPI을 사용하는 API를 찾을 수 있습니다. 공정 사용 정책은 "요청할 때마다 리소스를 로컬로 캐시합니다."라고 말합니다. 이것이 이 프로젝트에 완벽한 API인 이유입니다.
최종 폴더 구조는 다음과 같습니다.
ExemploRedis/
├─ Controllers/
│ ├─ PokemonController.cs
├─ Extensions/
│ ├─ DistributedCacheExtension.cs
├─ Services/
│ ├─ Interfaces/
│ │ ├─ ICacheService.cs
│ │ ├─ IPokemonService.cs
│ ├─ PokemonCacheService.cs
│ ├─ PokemonService.cs
├─ Pokemon.cs
Pokemon.cs에는 PokéApi가 반환하는 속성이 있습니다. 간단하게 3가지 속성만 추가했습니다.
public class Pokemon
{
public int Id { get; set; }
public string Name { get; set; }
public int Weight { get; set; }
}
Redis를 사용하기 위해 Microsoft.Extensions.Caching.Redis NuGet 패키지를 추가했습니다. 이를 통해 Redis 서비스를 추가하기 위해 Extension/DistributedCacheExtension.cs를 만들었습니다.
public static IServiceCollection AddDistributedCache(
this IServiceCollection services,
IConfiguration configuration)
{
services.AddDistributedRedisCache(options =>
{
options.Configuration =
configuration.GetConnectionString("Redis");
options.InstanceName =
configuration["Redis:InstanceName"];
});
return services;
}
구성 옵션은 자명합니다: 연결 문자열 및 인스턴스 이름.
그런 다음 다음과 같이 Startup.cs에 추가했습니다.
services.AddDistributedCache(Configuration);
Redis를 구성한 후 데이터를 가져오고 보내는 데 도움이 되는 서비스를 개발했습니다(코드 반복 방지). 상호 작용:
public interface ICacheService<T>
{
Task<T> Get(int id);
Task Set(T content);
}
서비스:
public class PokemonCacheService : ICacheService<Pokemon>
{
private readonly IDistributedCache _distributedCache;
private readonly DistributedCacheEntryOptions _options;
private const string Prefix = "pokemon_";
public PokemonCacheService(IDistributedCache distributedCache)
{
_distributedCache = distributedCache;
_options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromSeconds(120),
SlidingExpiration = TimeSpan.FromSeconds(60)
};
}
public async Task<Pokemon> Get(int id)
{
var key = Prefix + id;
var cache = await _distributedCache.GetStringAsync(key);
if (cache is null)
{
return null;
}
var pokemon = JsonConvert.DeserializeObject<Pokemon>
(cache);
return pokemon;
}
public async Task Set(Pokemon content)
{
var key = Prefix + content.Id;
var pokemonString = JsonConvert.SerializeObject(content);
await _distributedCache.SetStringAsync(key, pokemonString,
_options);
}
}
단계별 분석:
private readonly IDistributedCache _distributedCache;
private readonly DistributedCacheEntryOptions _options;
private const string Prefix = "pokemon_";
public PokemonCacheService(IDistributedCache distributedCache)
{
_distributedCache = distributedCache;
_options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromSeconds(120),
SlidingExpiration = TimeSpan.FromSeconds(60)
};
}
처음 2개의 필드인 _distributedCache 및 _options는 Redis 구성에 연결됩니다. IDistributedCache는 종속성 주입을 통해 Redis에 액세스하는 인터페이스입니다. DistributedCacheEntryOptions는 AbsoluteExpirationRelativeToNow 및 SlidingExpiration을 추가하는 역할을 하는 클래스로, 각각 데이터가 저장되는 총 시간과 액세스되지 않고 저장되는 총 시간(절대 시간보다 크지 않음)을 의미합니다. 접두사는 저장된 포켓몬에 접근하기 위한 키를 만드는 데 사용되는 문자열입니다.
메서드 가져오기:
public async Task<Pokemon> Get(int id)
{
var key = Prefix + id;
var cache = await _distributedCache.GetStringAsync(key);
if (cache is null)
{
return null;
}
var pokemon = JsonConvert.DeserializeObject<Pokemon>(cache);
return pokemon;
}
키는 IDistributedCache 인터페이스에서 GetStringAsync(key) 메서드를 사용하여 데이터를 찾는 데 사용됩니다. null인 경우 반환합니다(예외 또는 유효성을 검사하는 다른 방법일 수 있음). 그렇지 않으면 결과 문자열이 역직렬화됩니다.
설정 방법:
public async Task Set(Pokemon content)
{
var key = Prefix + content.Id;
var pokemonString = JsonConvert.SerializeObject(content);
await _distributedCache.SetStringAsync(key, pokemonString,
_options);
}
키는 직렬화된 포켓몬 개체로 SetStringAsync() 메서드에 사용됩니다. _options(만료 시간에 대한 것)도 여기에서 사용됩니다.
모든 준비가 완료되면 PokéApi를 사용하는 서비스를 만들었습니다. 상호 작용:
public interface IPokemonService
{
Task<Pokemon> GetPokemon(int id);
}
서비스:
public class PokemonService : IPokemonService
{
private readonly HttpClient _httpClient;
public PokemonService(HttpClient httpClient)
{
_httpClient = httpClient;
_httpClient.BaseAddress = new
Uri("https://pokeapi.co/api/v2/");
}
public async Task<Pokemon> GetPokemon(int id)
{
var response = await
_httpClient.GetAsync($"pokemon/{id}");
var content = await response.Content.ReadAsStringAsync();
var pokemon = JsonConvert.DeserializeObject<Pokemon>
(content);
return pokemon;
}
}
매우 간단한 서비스입니다. HttpClient와 PokéApi를 호출하고 포켓몬을 반환하는 GetPokemon(int id) 메서드가 있습니다. 다음과 같이 주입되었습니다.
services.AddHttpClient<IPokemonService, PokemonService();
그리고 마지막 부분에서는 컨트롤러를 만들었습니다.
[ApiController]
[Route("api/[controller]")]
public class PokemonController : ControllerBase
{
private readonly IPokemonService _pokemonService;
private readonly ICacheService<Pokemon> _pokemonCacheService;
public PokemonController(IPokemonService pokemonService,
ICacheService<Pokemon> pokemonCacheService)
{
_pokemonService = pokemonService;
_pokemonCacheService = pokemonCacheService;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
Pokemon pokemon = await _pokemonCacheService.Get(id);
if (pokemon is null)
{
pokemon = await _pokemonService.GetPokemon(id);
await _pokemonCacheService.Set(pokemon);
}
return Ok(pokemon);
}
}
그리고 이것이다. 전체 코드를 받는 것을 잊지 마십시오here. Redis 사용에 도움이 되는 docker-compose.yml 파일이 있습니다.
Reference
이 문제에 관하여(.Net 솔루션에서 Redis를 사용하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/lukesilva/how-to-use-redis-in-a-net-solution-2e8k텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)