Кэширование веб-API - Как реализовать Invalidation с использованием распределенного кэша - PullRequest
0 голосов
/ 11 декабря 2018

У меня есть API, который в настоящее время не использует кэширование.У меня есть одна промежуточная программа, которую я использую, которая генерирует заголовки кэша (Cache-Control, Expires, ETag, Last-Modified - с использованием библиотеки https://github.com/KevinDockx/HttpCacheHeaders).Он ничего не хранит, поскольку генерирует только заголовки.

Когда заголовок If-None-Match передается в запрос API, промежуточное программное обеспечение проверяет значение Etag, переданное в против текущего сгенерированного значения, и, если они совпадают, отправляет 304 без изменений в качестве ответа (httpContext.Response.StatusCode = StatusCodes.Status304NotModified;)

Я использую кэш Redis, и я не уверен, как реализовать аннулирование кэша.Я использовал пакет Microsoft.Extensions.Caching.Redis в своем проекте.Я установил Redis локально и использовал его в своем контроллере, как показано ниже:

[AllowAnonymous]
[ProducesResponseType(200)]
[Produces("application/json", "application/xml")]
public async Task<IActionResult> GetEvents([FromQuery] ParameterModel model)
        {
            var cachedEvents = await _cache.GetStringAsync("events");
            IEnumerable<Event> events = null;

            if (!string.IsNullOrEmpty(cachedEvents))
            {
                events = JsonConvert.DeserializeObject<IEnumerable<Event>>(cachedEvents);
            }
            else
            {
                events = await _eventRepository.GetEventsAsync(model);
                string item = JsonConvert.SerializeObject(events, new JsonSerializerSettings()
                {
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                });
                await _cache.SetStringAsync("events", item);
            }

            var eventsToReturn = _mapper.Map<IEnumerable<EventViewDto>>(events);
            return Ok(eventsToReturn);
        }

Обратите внимание, что _cache здесь использует IDistributedCache.Это работает, когда второй запрос попадает в кеш.Но когда Events я получаю изменения, он не учитывает измененные значения.Он обслуживает то же значение без какой-либо проверки.

Мое промежуточное программное обеспечение настроено как: промежуточное программное обеспечение заголовка кэша -> MVC.Таким образом, конвейер заголовков кэша сначала сравнивает значение Etag, отправленное клиентом, и либо решает переслать запрос в MVC, либо замыкает его с 304 неизмененным ответом.

Мой план состоял в том, чтобы добавить часть промежуточного программного обеспечения до первого заголовка кэша (т.е. Мое промежуточное программное обеспечение -> Промежуточное программное обеспечение заголовка кэша -> MVC) и дождаться ответа от промежуточного программного обеспечения заголовка кэша и проверить, получен ли ответэто 304. Если 304, перейдите в кэш и получите ответ.В противном случае обновите ответ в кеше.

Это идеальный способ сделать недействительным кеш?Есть ли лучший способ сделать это?При использовании вышеуказанного метода мне придется проверять каждый ответ 304, определять маршрут и иметь какую-то логику, чтобы проверить, какой ключ кэша использовать.Не уверен, что это лучший подход.

Если вы можете предоставить некоторые рекомендации и документацию / руководства по аннулированию кэша, это будет очень полезно.

1 Ответ

0 голосов
/ 12 декабря 2018

Вот руководство, основанное на том, как поддерживаемый мною сервис использует аннулирование кэша в системе CQRS.

Командная система получает запросы на создание, обновление, удаление от клиентов.Запрос применяется к Origin.Запрос передается слушателям.

Существует отдельная служба аннулирования, которая подписывается на список изменений.Когда получено командное событие, сконфигурированные распределенные кэши проверяются на предмет в событии.В зависимости от конкретной системы выполняются несколько различных действий.

Первый вариант - служба Invalidation удаляет элемент из распределенного кэша.Впоследствии потребители услуг, совместно использующих распределенный кеш, в конечном итоге будут страдать от пропадания кеша, извлекать элемент из хранилища и добавлять последнюю версию элемента в распределенный кеш.В этом сценарии существует условие состязания между всеми незаметными компьютерами в службах, и Origin может получить несколько запросов на один и тот же элемент в коротком окне.Если предмет дорого достать, это может затянуть оригинал.Но сценарий Invalidation очень прост.

Второй вариант - служба Invalidation отправляет запрос одной из служб, использующих тот же распределенный кеш, и запрашивает у службы игнорировать кеш и получать последнюю версию элемента изПроисхождение.Это устраняет потенциальный всплеск для нескольких дискретных машин, вызывающих Origin.Но это означает, что служба Invalidation более тесно связана с другими соответствующими службами.И у сервиса теперь есть API, который позволяет вызывающей стороне обходить свою стратегию кэширования.Доступ к некэшированному API должен быть защищен только для службы Invalidation и других авторизованных абонентов.

В любом случае все дискретные машины, которые используют одну и ту же базу данных redis, также подписываются на список изменений команд.Любая отдельная машина просто обрабатывает изменения локально, удаляя элементы из своего локального кэша.Нет ошибки, если элемент отсутствует.Предмет будет обновлен от redis или Origin по следующему запросу.Для горячих элементов это означает, что несколько запросов к Origin все еще могут быть получены с любого компьютера, на котором удален горячий элемент, а redis еще не обновлен.Для дискретных машин может быть полезно локально «кэшировать» и «извлекать элемент», которые могут ожидать все последующие запросы, а не вызывать Origin.

В дополнение к дискретным машинам и общему повторному перенаправлению, Invalidationлогика также распространяется на Akamai и аналогичные сети распространения контента.Как только кэш Redis был признан недействительным, подпрограмма Invalidation использует CDN API для очистки элемента.Akamai довольно хорошо себя ведет и при правильной настройке делает относительно небольшое количество обращений к Origin для обновленного элемента.В идеале служба уже извлекла элемент, и копии существуют как в локальных кешах дискретных машин, так и в общедоступном редисе.Аннулирование CDN может быть другим источником всплесков запросов, если не предвидеть и не спроектировать правильно.

В redis, от незаметных машин, разделяющих его, дизайн, который использует redis, чтобы указать, что элемент обновляется, также может скрывать происхождение отнесколько запросов на один и тот же товар.Простой счетчик, ключ которого основан на идентификаторе элемента и текущем временном интервале, округленном до ближайшей минуты, 30 секунд и т. Д., Может использовать команду redis INCR для машин, которые получают счетчик 1 источника доступа, в то время как все остальные ожидают.

Наконец, для горячих предметов может быть полезно иметь значение Time To Refresh, прикрепленное к предмету.Если все полезные данные имеют оболочку, аналогичную приведенной ниже, то когда элемент извлекается и время его обновления прошло, вызываемый выполняет фоновое обновление элемента.Для горячих предметов это означает, что они будут обновлены из кэша до истечения срока их действия.Для системы с интенсивным чтением и малым объемом записи кэширование элементов в течение часа со временем обновления менее часа означает, что горячие элементы обычно остаются в режиме redis.

Вот примерная оболочка для кэшированныхПредметы.Во всех случаях предполагается, что вызывающая сторона знает тип T на основе запрашиваемого ключа элемента.Предполагается, что фактическая полезная нагрузка, записанная в redis, является сериализованным байтовым массивом и, возможно, gzip-ed.SchemaVersion предоставляет подсказку о том, как создается строка redis.

interface CacheItem<T> {
  String Key {get; }
  DateTimeOffset ExpirationTime {get; }
  DateTimeOffset TimeToRefresh {get; }
  Int SchemaVersion {get;}
  T Item {get; }
}

При хранении var redisString = Gzip.Compress (NetDataContractSerializer.Serialize (cacheItem))

При извлечении элемента воссоздаетсядополнительными методами распаковки и десериализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...