Распределенное кэширование (Distributed Cache)

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

  1. Подключить сервис кэширования
  2. Используя сервис кэширования добавлять/удалять/обновлять элементы кэша.

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

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии