Содержание
Распределенный кэш (Distributed Cache) — кэш хранящийся в какой-либо внешней службе и, если один сервер сохранил элемент кэша, то другие серверы могут его использовать. Например, в ASP.NET Core для распределенного кэша может использоваться такой сервис, как Redis.
Распределенное кэширование (Distributed Cache)
Распределенное кэширование данных полезно применять в том случае, если необходимо, чтобы элементы кэша были согласованными при запросах к нескольким серверам. Распределенный кэш хранится в какой-либо внешней службе и, если один сервер сохранил элемент кэша, то другие серверы могут его использовать. На данный момент в ASP.NET Core имеются следующие готовые реализации распределенного кэша:
- Распределенный кэш Redis
- Распределенный кэш памяти
- Распределенный кэш SQL Server
- Распределенный кэш NCache
- Распределенный кэш Azure CosmosDB
Все эти реализации реализуют IDistributedCache – интерфейс, представляющий собой распределённый кэш. При этом стоит отметить, что распределенный кэш памяти, по сути, не является распределенным кэшем. На самом деле – это обычный кэш в памяти, но работа с ним ведется с использованием методов распределенного кэширования. Такой тип кэша полезно использовать для тестирования приложения при работе с распределенным кэшем. Мы же с вами рассмотрим одну из реализаций распределенного кэша – распределенный кэш Redis. Для начала, рассмотрим какие методы предоставляет нам интерфейс IDistributedCache.
Интерфейс IDistributedCache
Для управления распределенным кэшем IDistributedCache предоставляет различные методы, основные из которых следующие:
| Метод | Описание |
Get(string key) |
возвращает значение с указанным ключом. Значение возвращается в виде массива байтов byte[]? |
Refresh(string key) |
обновляет значение в кэше по ключу, сбрасывая его срок кэширования |
Remove(string key) |
удаляет значение с указанным ключом. |
Set(string key, byte[] value, DistributedCacheEntryOptions options) |
устанавливает значение с указанным ключом. В качестве значения выступает массив байтов |
SetString(string key, string value) |
устанавливает значение с указанным ключом. В качестве значения выступает строка |
GetString(string key) |
возвращает значение с указанным ключом. Значение возвращается в виде строки |
Для каждого метода из таблицы также предусмотрена его асинхронная версия, например GetAsync(), SetAsync() и т.д.
Как можно видеть из таблицы, при работе с распределенным кэшем мы можем оперировать строками или массивами байтов, например, если мы хотим кэшировать файл.
Теперь попробуем использовать распределенный кэш на основе Redis в нашем приложении. Для этого нам придётся произвести небольшие настройки своего рабочего пространства и, как минимум, установить на свой компьютер Redis.
Установка Redis в Windows
Для установки Redis для Windows необходимо скачать установочный файл с GitHub (https://github.com/tporadowski/redis/releases). На момент написания этой части, актуальной была версия Redis 5.0.14.1.
Сама установка максимально простая – необходимо, как обычно, согласиться с условиями лицензии, а также указать порт для Redis, который можно оставить значение по умолчанию, как и прочие предложенные настройки. После успешной установки Redis на свой компьютер, можно перейти в папку с установкой и запустить сервер
При запуске этого файла из командной строки Windows вы должны увидеть следующий вывод консоли
Теперь мы можем подключиться к Redis и использовать его в качестве распределенного кэша. Для этого мы должны произвести те же действия, что и при работе с кэшем в памяти, то есть:
- Подключить сервис кэширования
- Используя сервис кэширования добавлять/удалять/обновлять элементы кэша.
Подключение к Redis из приложения ASP.NET Core
Для подключения к Redis из приложения ASP.NET Core необходимо установить nuget-пакет Microsoft.Extensions.Caching.StackExchangeRedis. Теперь создадим новое приложение ASP.NET Core Web API, перейдем в файл Program.cs и подключим сервис распределенного кэширования
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// добавление распределенного кэширования
builder.Services.AddStackExchangeRedisCache(options => {
options.Configuration = "localhost";
options.InstanceName = "local";
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Сама настройка сервиса кэширования выглядит достаточно просто, так как мы используем распределенный кэш на том же компьютере, что и приложение. В действительности класс RedisCacheOptions, объект которого мы используем в делегате при вызове метода расширения AddStackExchangeRedisCache(), содержит довольно много настроек – строки подключения, порты, учетные данные пользователя Redis и так далее. Так что, если вам потребуется использовать Redis, расположенный на другом сервере в сети, то вы наверняка найдете все необходимые настройки в RedisCacheOptions.
Теперь воспользуемся этим сервисом кэширования в нашем приложении.
Использование распределенного кэша
Изменим контроллер WeatherForecastController так, чтобы в его работе использовался распределенный кэш
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
private readonly IDistributedCache _cache;
public WeatherForecastController(ILogger<WeatherForecastController> logger, IDistributedCache cache)
{
_logger = logger;
_cache = cache;
}
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
var data = await _cache.GetStringAsync("forecast");
if (string.IsNullOrEmpty(data))
{
var entryOptions = new DistributedCacheEntryOptions();
entryOptions.SetAbsoluteExpiration(TimeSpan.FromSeconds(30));
entryOptions.SetSlidingExpiration(TimeSpan.FromSeconds(10));
var forecastArray = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
await _cache.SetStringAsync("forecast", JsonSerializer.Serialize(forecastArray), entryOptions);
_logger.LogInformation($"Прогноз погоды помещен в кэш");
return forecastArray;
}
else
{
_logger.LogWarning($"Прогноз погоды получен из кэша");
return JsonSerializer.Deserialize<WeatherForecast[]>(data);
}
}
}
Теперь в контроллере запрашивается сервис IDistributedCache и, соответственно, немного меняется логика работы с элементами кэша. Так, используя Redis, мы можем добавлять в кэш строки или массивы байтов, а мы, по сути, работаем со строками, то и для записи в кэш мы используем асинхронный метод GetStringAsync(), предварительно сериализовав объект:
await _cache.SetStringAsync("forecast", JsonSerializer.Serialize(forecastArray), entryOptions);
Также стоит обратить внимание на то, что при работе с распределенным кэшем, в нашем распоряжении намного меньше опций по настройке каждого элемента. Так, класс DistributedCacheEntryOptions содержит всего три свойства
| Название | Тип | Описание |
AbsoluteExpiration |
DateTimeOffset? |
Абсолютная дата истечения срока действия для записи в кэше. |
AbsoluteExpirationRelativeToNow |
TimeSpan? |
Абсолютное время истечения срока действия относительно текущего момента |
SlidingExpiration |
TimeSpan? |
Определяет в течение какого времени запись в кэше может быть неактивной, прежде чем она будет удалена. Это значение не продлит время жизни записи сверх установленного значения в свойствах AbsoluteExpiration и AbsoluteExpirationRelativeToNow. |
Теперь можно запустить приложение и проверить его работу. Приложение будет работать также, как и прежде с кэшем в памяти. Чтобы проверить, что элементы кэша действительно записываются, достаточно запустить утилиту redis-cli.exe
И выполнить в ней команду
keys *
эта команда выведет в консоль все ключи элементов кэша. Если кэш пуст, то выполнение команды будет выглядеть следующим образом
Если же в кэше будут содержаться какие-либо элементы, то вы увидите следующую информацию
Чтобы посмотреть, что именно содержит тот или иной элемент кэша, необходимо выполнить команду:
hgetall [ключ]
Итого
В этой части мы в общих чертах рассмотрели использование распределенного кэша с использованием Redis. Распределенный кэш имеет меньше настроек, чем кэш в памяти, однако его преимущество заключается в том, что такой кэш может использоваться на нескольких компьютерах одновременно.




