Идея этой статьи состоит в том, чтобы разобраться в методах кэширования для веб-приложений. Кэширование — это метод, который часто используется для ускорения загрузки веб-страниц и который обязательно следует учитывать при создании веб-приложений.

В этой статье будет дан краткий обзор того, что такое кэширование и как мы его используем в FLOWN, прежде чем углубиться в технический пример с использованием приложения Next.js, размещенного на Vercel; мы предполагаем некоторые предварительные знания об этих инструментах.

Что такое кеш (но быстро)?

Кэш — это временное высокоскоростное хранилище данных, которое позволяет повторно использовать и обслуживать ранее вычисленные данные в будущем. Вы можете думать об этом как о способе «запоминания» ранее вычисленных данных.

Ниже приведена диаграмма, иллюстрирующая, что такое кэширование на базовом уровне:

Зачем нужно кэширование?

Основная цель кэширования — ускорить процесс за счет уменьшения необходимости извлечения ранее извлеченных данных. Распространенный вариант использования — ускорить загрузку веб-страниц. Представьте себе домашнюю страницу, которая загружает много данных, и для полной загрузки требуется около 1 секунды. Если данные на странице одинаковы, мы могли бы извлечь выгоду из кэширования этой страницы, чтобы она извлекалась намного быстрее при последующих запросах. Второй запрос теперь может занять 0,2 с. Вы можете думать о кеше как о способе «запомнить» то, что было ранее запрошено, чтобы в следующий раз, когда это понадобится, оно было более доступно.

Каков наш вариант использования кэширования?

В FLOWN, наряду с нашими виртуальными сеансами совместной работы, мы предлагаем нашим пользователям много контента, чтобы поддержать их в их серьезных рабочих потребностях. Этот контент обслуживается нашей CMS, где приемлема небольшая степень устаревания данных, но где контент может нуждаться в обновлении/обновлении нашей командой.

Ниже приведены некоторые показатели, которые мы отследили с помощью Vercel Analytics. Чтобы продемонстрировать пример этого, мы выбрали две страницы, которые загружают очень похожий объем данных. Глядя на первую метрику отрисовки контента между кэшированной страницей (верхний график) и некэшированной страницей (нижний график), мы видим, что кэшированная страница загружается быстрее (0,96 с против 1,23 с).

Кэш-Контроль

Браузеры могут получать заголовок Cache-Control в HTTP-запросах и ответах. «Значения» или инструкции этого заголовка называются директивами. Ниже мы рассмотрим две конкретные директивы:

max-age

max-age используется для определения устаревших данных. Если данные старше `max-age`, то данные устарели, если новее, то они свежие. Задается в секундах относительно последнего времени получения данного ответа.

Обратите внимание, что некоторые системы (например, сети доставки контента (CDN), промежуточные кэши) могут использовать общую систему кэширования и переопределять max-age аналогичной директивой: s-maxage.

stale-while-revalidate

Всегда нужно сочетать с max-age.

Два ключевых понятия здесь:

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

stale-while-revalidate будет вести себя по-разному в зависимости от свежести данных. Если данные считаются свежими, то делать нечего. Однако, если данные устарели, выполняется дополнительная проверка на возраст.

Если возраст данного ответа находится в пределах временного окна, указанного в stale-while-revalidate, то он используется для выполнения запроса браузера, в то время как выполняется запрос «повторной проверки» без задержки доступности кэшированного ответа. «Позвольте мне дать вам это, пока я схожу за последней информацией» — по существу.

Результат этого ответа повторной проверки может быть таким же, как и предыдущий ответ, но также может отличаться. Затем обновляется таймер «свежести».

Если возраст ответа выпадает как из максимального возраста, так и из stale-while-revalidate, тогда браузер не будет обслуживать какой-либо кэшированный контент и просто получит последний ответ из сети. Затем локальный кеш заполняется этим «свежим» ответом. Это похоже на сценарий, показанный на диаграмме выше.

Пример:

Cache-Control: max-age=30, stale-while-revalidate=119

В настоящее время мы используем комбинацию s-maxage и stale-while-revalidate.

Следующий.js:

Заголовок Cache-Control устанавливается по-разному в зависимости от механизма выборки данных, используемого Next.js. Я предполагаю, что некоторые предварительные знания о них здесь, но связаны с соответствующей документацией, если вам нужна дополнительная информация:

getServerSideProps или getInitialProps → используйте значение по умолчанию, установленное next start, чтобы предотвратить кеширование этих ответов. Это связано с тем, что эта страница создается каждый раз, когда она запрашивается — заголовки кэширования могут по-прежнему использоваться для каждой функции, чтобы переопределить это значение по умолчанию.

getStaticProps — поскольку эти страницы генерируются статически, они имеют значение по умолчанию:

Cache-Control: public, max-age=31536000, immutable

Если установлено revalidate, заголовок будет заменен на s-maxage=REVALIDATE_SECONDS, stale-while-revalidate.

получитьстатические пути:

При использовании динамической маршрутизации все указанные пути будут предварительно обработаны статически. Это происходит при каждой сборке, но что, если мы добавим новую страницу в набор путей и больше не будем собирать приложение?

Здесь становится полезным параметр fallback; может принимать несколько значений:

fallback: false → строятся только пути, возвращаемые getStaticPaths. Полезно для небольшого количества динамических путей или когда новые данные страницы не добавляются часто. Для добавления новых путей требуется перестройка приложения.

fallback: true → аналогично приведенному выше, но пути, не созданные во время сборки, не приведут к ошибке 404, вместо этого Next будет обслуживать резервную версию страницы. Ведет себя как fallback: blocking при переходе через next/link или next/router, т.е. навигация на стороне клиента

fallback: blocking → новые пути, не возвращенные getStaticPaths, будут генерировать HTML-объявление, кэшированное для будущих запросов. Вместо того, чтобы приводить к ошибке 404, Next.js будет SSR запрашиваемой страницы по первому запросу (нет резервного состояния). Обратите внимание, что это не будет обновлять сгенерированные страницы по умолчанию, и для этого следует использовать добавочную статическую регенерацию.

А как насчет местной среды?

Локально next dev установит следующий заголовок управления кешем:

Cache-Control: no-cache, no-store, max-age=0, must-revalidate

Это сделано для того, чтобы мы всегда получали самые свежие данные при локальной разработке.

Кэширование на Vercel:

Кэширование Vercel работает через сеть Vercel Edge Network, которая «кэширует ваш контент на периферии, чтобы предоставлять данные вашим пользователям как можно быстрее».

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

«Возвращается заголовок Cache-Control, содержащий public, max-age=0, must-revalidate, чтобы клиенты (например, браузеры) не кэшировали файл локально», но это можно переопределить в конфигурации vercel.json.

Кэширование бессерверных функций:

Здесь значения всегда указаны в секундах, и можно использовать несколько директив для заголовка Cache-Control.

Ресурсы: