Содержание
Распределенный кэш (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. Распределенный кэш имеет меньше настроек, чем кэш в памяти, однако его преимущество заключается в том, что такой кэш может использоваться на нескольких компьютерах одновременно.