Разбираем HTTP-кэширование

Использование CDN долгое время было прерогативой сайтов из топ-100 Alexa. Маленьким компаниям это было или не нужно, или же они не могли себе этого позволить. Но ситуация изменилась в последние годы — появилось множество CDN с доступными вариантами оплаты, ориентированных на небольшие сайты. В этой статье мы вместе с Ульрихом Каутцом, специалистом компании Fortabit, постараемся помочь вам в освоении этого довольно простого инструмента, рассказав о различных аспектах кэширования данных с помощью CDN.

Чтобы использовать Content Delivery Network (CDN, сети доставки контента) в качестве HTTP-кэша, мы должны четко понимать, что такое HTTP-заголовок. Какие заголовки правильны? Как они работают? Как их использовать?

Зачем вообще нужны CDN?

CDN нужны для того, чтобы быстрее доставлять содержимое веб-сайта в места географически удаленные от вашего сервера. Например, ваши сервера расположены в Ирландии, а так получилось, что многие клиенты – в Австралии. Большое расстояние создает задержки и ухудшает качество соединения, и это разочаровывает ваших клиентов. Перемещение статического контента на сервера CDN в Австралию значительно улучшает качество соединения и восприятие клиентами вашего сайта.

Польза от CDN не сводится только лишь к приведенному выше примеру. CDN – это, в принципе, просто кэш на прокси-сервере. Точнее, пограничный кэш. И даже если вас несильно волнует географический аспект, кэширующий прокси CDN может значительно улучшить восприятие клиентами вашего сайта, ускорив и повысив качество доставки контента пользователям вне зависимости от их расположения глобально.

Зачем использовать прокси-кэш?

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

Предположим, у вас есть блог, на главной странице которого размещен список ранее опубликованных записей. Чтобы сформировать эту страницу, PHP-скрипт посылает запрос к базе данных и на основе полученного ответа генерирует HTML-код страницы. И так для каждого запроса, для каждого посещения. Одно исполнение скрипта и пара запросов к БД. А для тысячи визитов — тысяча запусков скрипта и пара тысяч запросов к БД. А ведь каждая операция требует ресурсов памяти и процессора – как PHP, так и запросы к базе.

Требования к ресурсам растут линейно с ростом посетителей. Звучит пугающе? Ну да, ну да… Линейно-то линейно, но до определенного предела. Ни память, ни ресурсы процессора не бесконечны. Диск тоже может обслужить только некоторое конечное количество запросов в секунду. Рано или поздно где-то образуется узкое место, и тогда становится неважно, как много еще в запасе других ресурсов – нехватка памяти тормозит работу, или процессор не справляется, хотя памяти достаточно, неважно. Сайт начинает тормозить и даже зависает, переставая отвечать на запросы. Конечно, можно масштабировать оборудование «горизонтально», добавив памяти или ядер процессору, но это усложняет ситуацию, требует денег, а в то же время есть гораздо более простое и дешевое решение.

Кэширующий прокси между сервером и пользователями позволяет преодолеть ограничения по ресурсам. Если брать вышеприведенный пример, то только первый запрос требует вызова PHP-скрипта и обращения к базе данных. Все последующие запросы могут быть обслужены при помощи кэша. А обращение к кэшу – это просто обращение к памяти, которое обслуживается довольно быстро. И все, теперь только один вызов PHP-скрипта, пара обращений к БД для тех самых тысяч запросов.

CDN != CDN

Есть различные «типы» CDN. Администратору сетей, наверное, больше всего интересно, как именно данные хранятся внутри CDN и как потом распределяются. Но данная статья ориентирована не на администраторов, а на разработчиков, потому ограничимся тем, что бывают CDN «классические», а бывают «peer-to-peer» CDN. Второй подход реализован в современных сетях.

С точки зрения разработчиков более интересно понять, как отдаются данные в CDN, как оно там потом крутится. В этом смысле есть push CDN, а есть pull CDN (от слов: «push» — «толкать» и «pull» — «тянуть»). Как понятно из названий, push CDN ждет, когда вы будете пересылать в нее данные, а pull – сама будет их скачивать от вас.

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

Как работает pull CDN?

Предположим, что у вас есть сайт, расположенный, скажем, по адресу https://www.foobar.tld. В этом случае домен www.foobar.tld должен быть прикреплен к серверу CDN, а не к серверу, на котором расположен сайт. Другой домен, не публичный, скажем, direct.foobar.tld, должен указывать на сервер с сайтом. Мы будем называть его еще «исходник» (origin).

Теперь CDN принимает запросы от пользователей и либо выдает им хранящуюся в кэше информацию, либо, если ее там нет, запрашивает ее у исходного сервера и выдает ее пользователю, попутно помещая ее в кэш.

Схематично этот процесс выглядит так:

  • Приходит запрос на страницу http://www.foobar.tld/some/page
  • Запрашиваемая страница ищется в кэше по ключу some/page
  • Если в кэше она есть – выдается сохраненная там копия
  • Если в кэше нет – посылается запрос на «исходник» http://direct.foobar.tld/some/page, оттуда получается страница some/page, выдается по запросу и одновременно сохраняется в кэше

Статический и динамический контент

Приведенная выше конфигурация работает только для полностью статического контента. Статический контент, это когда данные, получаемые по запросу определенного URL, одинаковы для всех пользователей. Например, это могут быть файлы скриптов css, подгружаемые страницей с отдельного адреса. Скажем, http://www.foobar.tld/public/css/main.css, где main.css – статичный файл одинаковый для всех страниц сайта. Очень удобный для кэширования файл.

Но существует и динамический контент. Есть множество причин, по которым контент генерируется во время исполнения запроса. Например, в случае многоязычности – здесь контент генерируется в зависимости от языка браузера. Или когда контент связан с параметрами сессии: с именем зарегистрировавшегося на сайте пользователя, например. Это не кэшируется. Также сложно кэшировать быстроменяющийся контент – например, главную страницу новостного сайта.

Теперь будьте внимательны. Сейчас будет интересное, но довольно сложное для понимания место.

Заголовки кэша

Большинство, если не все pull CDN дают нам возможность решить проблему динамического контента, вводя «постраничный» контроль кэша. Для этого используются HTTP-заголовки кэша.

Первое, что надо знать о заголовках кэша, это то, что тут есть два формата заголовков – старый и новый, в смысле соответствия спецификациям HTTP/1.0 и HTTP/1.1. Здесь есть множество различных опций, и путаница со «старыми» и «новыми» заголовками часто является той причиной, по которой люди вообще боятся связываться с темой заголовков кэша.

Чтобы упростить, мы для начала рассмотрим тэги ETag и Cache-Control. Они важны оба. Некоторые CDN до сих пор используют старые заголовки (Expires, Pragma и Age), но в качестве запасного варианта: если не используются новые тэги, тогда система использует старые.

Заголовок ETag

Это очень простой тэг. Он задает версию документа. В любом виде. «101». Или «2017-22-04». Единственное правило – значение должно быть в кавычках –

ETag: "d3b07384d113edec49eaa6238ad5ff00"

Ревалидация – проверка актуальности

Теперь о практическом применении тэга ETag – проверка актуальности содержимого кэша. Давайте на время забудем о том, что у нас конфигурация прокси-исходник, и будем говорить о просто конфигурации клиент-сервер.

Далее представим себе, что клиент посылает запрос к http://www.foobar.tld/hello.txt. Сервер в ответ выдает контент со следующим заголовком:

# REQUEST
GET /hello.txt HTTP/1.1
Host: www.foobar.tld 

# RESPONSE
HTTP/1.1 200 OK
Date: Sun, 05 Feb 2017 12:34:56 UTC
Server: Apache
Last-Modified: Sun, 05 Feb 2017 10:34:56 UTC
ETag: "8a75d48aaf3e72648a4e3747b713d730"
Content-Length: 8
Content-Type: text/plain; charset=UTF-8 

(тут тело страницы)

Здесь есть два интересных для нас тэга – ETag с MD5 хэшем контента и Last-Modified с датой последней модификации hello.txt.

Теперь давайте посмотрим, как работает проверка актуальности. Когда посетитель после некоторого перерыва снова запрашивает какой-то URL, его браузер использует в запросе один из If-* заголовков. Например, If-None-Match, через который проверяется значение ETag. В ответ на заголовок с приведенным ниже содержанием браузер должен получить или сообщение, что ничего не изменилось, или полномасштабный ответ от сервера.

Заголовки запроса:

GET /hello.txt HTTP/1.1
If-None-Match: "8a75d48aaf3e72648a4e3747b713d730"
Host: www.foobar.tld

Ответ сервера, если ETag не изменился:

HTTP/1.1 304 Not Modified
Date: Sun, 05 Feb 2017 12:34:57 UTC
Server: Apache
Last-Modified: Sun, 05 Feb 2017 10:34:56 UTC
ETag: "8a75d48aaf3e72648a4e3747b713d730"
Content-Length: 8
Content-Type: text/plain; charset=UTF-8

Как вы видите, сервер отвечает «304 Not Modified», а не «200 OK», без основного тела контента, побуждая браузер посетителя использовать кэшированный контент. В случае большого объема данных это дает существенную экономию.

Как разработчик, вы можете подумать: «Это не очень хорошо. Я теперь должен еще и озаботиться обработкой в моем приложении всех этих if-запросов».

Не беспокойтесь. Тут и возникает CDN. Вернемся к первоначальной конфигурации клиент<->прокси<->исходный сервер. Все эти 304 запросы здесь обрабатывает прокси, опираясь на собственный кэш. Об этом подробнее в следующем разделе, а пока давайте поговорим еще и о тэге Last-Modified.

В ряде случаев, особенно если контент статичен, текстовый файл или статичный файл html, полезным бывает использование запроса If-Not-Modified-Since: Sun, 05 Feb 2017 10:34:56 UTC, ответом на который тоже может быть 304. Это работает вообще быстро, поскольку здесь используется время, содержащееся в метке времени у файла на диске. А вот для динамического контента временная метка бесполезна.

В общем, ETag в ряде важных и распространенных случаев гораздо удобнее.

Тэг CacheControl

Заголовок Cache-Control несколько сложнее. Он сложнее по двум причинам. Во-первых, потому, что может использоваться как в запросе, так и в ответе. В нашей статье мы будем уделять основное внимание применению его в ответах, поскольку разработчики несут ответственность именно за эту часть обмена. Во-вторых, потенциально этот тэг контролирует два типа кэша: «локальный (или приватный) кэш» и «общий кэш».

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

Публичный, или общий кэш – это то, чему посвящена данная статья: кэш между браузером и сервером. CDN. В этом случае вы как разработчик имеете полный контроль над кэшем и должны использовать это на все сто.

Ок, давайте взглянем на кое-какие примеры кода:

  1. Cache-Control: public max-age=3600
  2. Cache-Control: private immutable
  3. Cache-Control: no-cache
  4. Cache-Control: public max-age=3600 s-maxage=7200
  5. Cache-Control: public max-age=3600 proxy-revalidate

Во-первых, обратите внимание, что Cache-Control оперирует тремя видами директив: кэшируемость, срок жизни кэша и проверка актуальности версий.

Первая — кэшируемость — указывает на то, где именно должна храниться копия данных

  • private. Означает, что данные должны храниться в локальном кэше. В вашем ноутбуке
  • public. Означает, что данные должны храниться в общем кэше – в CDN. Но они также могут быть сохранены и локально
  • no-cache. Интересная директива – она на самом деле означает, что данные должны кэшироваться, но кэши всех уровней должны проверять актуальность данных каждый раз перед использованием
  • no-store. Означает, что данные не должны кэшироваться. Никогда. Нигде.

Следующая категория директив – управление сроком хранения данных.

  • max-age=<seconds>. Указывает срок жизни кэша. Сколько секунд кэш должен хранить копию данных. Касается как локального, так и общего кэша.
  • s-maxage=<seconds>. Переопределяет значение max-age для общего кэша. Не влияет на локальный кэш.

И последние – управление проверкой актуальности данных.

  • Immutable. Указывает, что документ не будет изменен. Никогда. И должен храниться вплоть до момента тепловой смерти Вселенной.
  • must-revalidate. Указывает на то, что браузер должен для данного запроса провести проверку актуальности кэша, даже если он только что был обновлен.
  • proxy-revalidate. Означает, что для данного запроса прокси должна провести проверку актуальности своего кэша, сверившись с исходным сервером.

И теперь, вот как вышеприведенные директивы читаются в переводе «на русский»:

  1. Кэшировать эти данные как на компьютере пользователя, так и в CDN сроком на 1 час
  2. Кэшировать только локально — на компьютере пользователя, не кэшировать в CDN. Сохранив один раз, больше не обновлять.
  3. Можете кэшировать, а можете не кэшировать. Только каждый раз проверяйте, актуальные ли данные вы храните в кэше.
  4. Кэшировать на час на компьютере пользователя, но на два часа в CDN
  5. Кэшировать на компьютере пользователя и в CDN на час, но на CDN каждый раз, когда приходит запрос, даже в течение этого часа, надо свериться с сервером, актуальны ли данные.

Пример

Приведем пример, как внедрить заголовки ETag и Cache-Control с помощью файла .htaccess. Это для Apache, но если у вас другой сервер, разобраться несложно.

# Set ETag and cache for one day for all images:
<FilesMatch "\.(gif|flv|jpg|jpeg|png|gif|swf)$">
    FileETag -INode MTime Size
    Header set Cache-Control "max-age=86400 public"
</FilesMatch>

# Set ETag and cache for two hours, but assure revalidation, for all CSS, JS assets
<FilesMatch "\.(js|css)$">
    FileETag -INode MTime Size
    Header set Cache-Control "max-age=7200 public must-revalidate"
    Header unset Last-Modified
</FilesMatch>

Например, ответ на запрос файла http://www.foobar.tld/baz.jpg должен содержать в себе заголовок ETag с указанием времени последнего изменения файла, его размера, и Cache-Control заголовок с указанием срока хранения этого файла в кэше – 1 сутки.

# REQUEST
GET /baz.jpg HTTP/1.1
Host: www.foobar.tld

# RESPONSE
HTTP/1.1 200 OK
Date: Tue, 07 Feb 2017 15:01:20 GMT
Last-Modified: Tue, 07 Feb 2017 15:01:15 GMT
ETag: "4-547f20501b9e9"
Content-Length: 123
Cache-Control: max-age=86400 public
Content-Type: image/jpeg

Ответ на запрос http://www.foobar.tld/dist/css/styles.css должен содержать в себе также заголовок ETag с указанием времени последнего изменения файла и его размера, Cache-Control заголовок с указанием срока хранения этого файла в кэше – 2 часа. Кроме того, из заголовков должен быть исключен Last-Modified, и это означает, что версия будет сверяться только по полю ETag.

# REQUEST
GET /styles.css HTTP/1.1
Host: www.foobar.tld

# RESPONSE
HTTP/1.1 200 OK
Date: Tue, 07 Feb 2017 15:00:00 GMT
Server: Apache
ETag: "20-547f1fbe02409"
Content-Length: 32
Cache-Control: max-age=7200 public must-revalidate
Content-Type: text/css

Cookie

Теперь, когда мы разобрались с тем, как в кэшировании используются заголовки, давайте посмотрим на то, какую роль в этом процессе играют cookie. Cookie — это заголовки HTTP-ответа. А именно: заголовок Set-Сookie. Основная цель отправки cookie пользователю – идентификация пользователя. Соответственно, каждому уникальному посетителю нужна уникальная cookie.

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

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

Но кроме этих, «плохих» сессионных cookie, есть cookie получше. Это тип cookie, которые задаются в момент исполнения, через Javascript. К примеру, так делает Google Analytics, подключаемый через Javascript. GA задает cookie, но это не влияет на генерацию контента и не входит в Set-Cookie заголовок. Даже если GA меняет страницу, например, дописывая что-то вроде «за вами следят с помощью Google Analytics», он делает это не в том коде, который кэшируется, а на лету, во время просмотра страницы в браузере.

Работа с cookie в условиях кэширования

Первое, что тут надо сделать – выяснить, как именно ваше веб-приложение (CMS, или что вы используете) работает с cookie. Используются ли они редко (только для регистрации и входа пользователя)? Встраиваются ли в каждый ответ сервера? Есть у вас вообще возможность контролировать то, когда они устанавливаются?

То есть, когда вы генерируете ответ, содержащий Set-Cookie заголовок, вы должны запретить его кэширование. То же самое касается ответов, содержащих уникальную пользовательскую информацию – содержимое корзины, например и т. п. Как это выглядит конкретно, зависит от того, что делает прокси/CDN. Например:

  • Устанавливает ли она некоторое свое дефолтное время кэширования автоматически через заголовок Cache-Control, если оно не установлено сервером?
  • Удаляет ли она Cache-Control заголовки, если в ответе присутствует Set-Cookie?

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

# 1) Включить кэширование, если COOKIE НЕ ИСПОЛЬЗУЮТСЯ.

Header set Cache-Control «public max-age=3600» «expr=-z resp(‘Set-Cookie’)

# 2) Выключить кэширование, если КУКИ ИСПОЛЬЗУЮТСЯ

Header always remove Cache-Control «expr=-n resp(‘Set-Cookie’)

# 2a) Альтернатива двум предыдущим вариантам: установить время кэширования 0, если COOKIE ИСПОЛЬЗУЮТСЯ

Header set Cache-Control «no-cache max-age=0 must-revalidate» «expr=-n resp(‘Set-Cookie’)

  • Правило 1 устанавливает заголовок Cache-Control с дефолтным временем, если не обнаружен заголовок Set-Cookie
  • Правило 2 вырезает заголовок Cache-Control, если обнаружен заголовок Set-Cookie
  • Правило 3 делает то же, что и 2, но немного по-другому – оно не вырезает ничего, просто устанавливает время кэширования 0 и заставляет каждый раз брать с сервера актуальную версию данных.

Подавление cookie на основе анализа path

Некоторые CMS используют брутфорс-стратегию, насыщая заголовки записями Set-Cookie где надо и где не надо. Это, конечно, может быть и обоснованным решением, например, если ваше приложение – некая засекреченная система с очень короткой длительностью сессии – например, 5 минут. Тогда да, надо в каждом запросе проверять уникальность сессии сверкой кук. Но если у вас на сайте нет ничего персонализированного, и все для всех выглядит одинаково – вам не нужны cookie вообще.

Так что будете вы использовать нижеприведенный пример или нет, зависит от вашего приложения и ваших целей. Пусть для большей ясности, мы говорим о новостном сайте. И все новости у вас публикуются как некие новостные объекты по адресу такого вот типа: http://www.foobar.tld/news/item/<ID>. Теперь мы хотим сделать так, чтобы все ответы на запросы к /news/item/<ID> не содержали Set-Cookie заголовков, поскольку вы убедились, что эти cookie избыточны.

# обычный PHP редирект .. обратите внимание на `?path=$1` в RewriteRule
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?path=$1 [NC,L,QSA]
RewriteRule ^$ index.php [NC,L,QSA] 

# проверяем наличие предыдущего `path=` в запросе
<If "%{QUERY_STRING} =~ m#path=news/item/[^&]+#">  
  Header always unset Set-Cookie
</If>

Для тех, кому интересно: редирект с использованием path=$1 и последующая обработка QUERY_STRING – необходимы при условии использования Apache в связи с внутренними особенностями его функционирования. If вычисляется проще, чем RewriteRule, из-за того, что REQUEST_URI и прочие данные из изначального запроса уже изменены тем же самым Rewrite.

Кэшируемость как следствие правильной разработки

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

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

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

Такую стратегию трудно реализовать на уже существующем приложении – надо лезть глубоко в недра CMS, переписывать отображаемый слой и т. п. Если идти по этому пути, то такие возможности надо закладывать в самом начале – при разработке макета страниц.

Устаревший кэш: очистка и обход

При помощи директив max-age и s-maxage вы получаете контроль над тем, сколько будут жить в кэше те или иные специфические элементы. Но этого не всегда достаточно. Эти директивы устанавливают начало отсчета на момент генерации страницы. А в этот момент вы можете и не знать еще точно, когда именно устареет этот элемент. Например, главная страница новостного сайта. Пусть на ней размещено 10 главных новостей. И вы установили для нее max-age=900 будучи уверенным, что она обновляется каждые 15 минут. Но внезапно, по тем или иным причинам, вышла внеочередная новость, раньше чем истекло 15 минут. И вам нужно удалить соответствующий кэшированный ответ уже сейчас.

Это довольно распространенная проблема, и для нее есть решение. Давайте разберемся сначала с терминологией.

  • «Обход кэша» (cache busting) означает – обойти элемент кэша используя измененный ключ. Видоизменив адрес страницы в запросе, например, взяв пример, который использовался выше http://www.foobar.tld/some/page — здесь ключ, по которому в кэше ищется элемент — some/page. Запросим страницу, немного изменив URL, и, соответственно, ключ — some/page?v2, и тогда мы обойдем кэш и получим не кэшированное содержимое, а что-то новое.
  • «Очистка кэша» (cache purging) — означает удаление элемента из кэша, и тогда он должен быть обновлен немедленно.

Обход кэша при помощи задания версий

Эта стратегия довольно часто применяется для различных ресурсов (css, js и т. п.). Идея в том, чтобы подгружать ваши ресурсы, модифицируя их URL-номером версии. Это может быть реальная версия, или хэш содержимого или временная отметка и т. п.

  • Числовая версия: style-v1.css, style.css?v=1
  • Хэш в качестве версии: style.css?d3b07384d113edec49eaa6238ad5ff00
  • Временная метка в качестве версии: styles.css?t=1486398121

Но тут проблема может быть в том, что HTML-страница, которая содержит запрос к вашему ресурсу в виде <link rel=»stylesheet» href=»..»> может быть сама кэширована со старой версией адреса ресурса. И вы получите все равно старую версию.

Очистка кэша

Как удалить один или несколько объектов из кэша CDN, зависит от особенностей конкретной реализации. Многие CDN построены на основе популярного открытого кода Varnish, и для них общая стратегия – использовать кодовое слово PURGE в запросе.

PURGE /news/item/i-am-obsolete HTTP/1.1
Host: www.foobar.tld

Такие запросы на очистку требуют хотя бы минимальной аутентификации, или же внесения источника запроса в некий «белый список» адресов, с которых может быть принят такой запрос.

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

Суррогатные ключи (тэги кэша)

Название «суррогатный ключ» используется CDN провайдером Fastly. Другие провайдеры могут называть это по-другому. Популярным является вариант «тэг кэша». Varnish называет это Hashtwo/Xkey, но это название ужасно.

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

Для примера, вот что ответит ваш исходный сервер на использование суррогатного ключа:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 123
Surrogate-Key: top-10 company-acme category-foodstuff

В этом примере ответ «помечен» тремя суррогатными ключами: top-10, company-acme and category-foodstuff. Например, это может быть один из топ-10 товаров вашего электронного магазина, он произведен компанией ACME  и принадлежит категории foodstuff.

Помечая ответы суррогатными ключами, вы легко сможете потом удалить из кэша все, что помечено top-10 или company-acme или как-то еще. Легко, правда?

В заключение отметим, что для того, чтобы вы получили теоретическое представление о вопросе, этого материала достаточно. Чтобы разобраться конкретнее, надо смотреть, как устроено кэширование у конкретных CDN, которые вы собираетесь использовать.

Николай Мациевский
Технический директор облачного сервиса Айри.рф, продукта компании WEBO Group, позволяющего ускорить и защитить любой сайт от наиболее распространенных угроз. Профессионально занимается скоростью, надежностью и доступностью веб-сайтов уже много лет. Является автором книг «Разгони свой сайт» и «Реактивные веб-сайты». Основатель первой в России компании, профессионально занимающейся повышением качества и быстродействия сайтов различной сложности — WEBO Group. Работает в составе рабочих групп РАЭК, W3C и объединения разработчиков «Веб-стандарты».

Прокомментировать

2 Комментарий на "Кэширование в браузерах и CDN"

Notify of
Sort by:   newest | oldest | most voted
Федор
Гость

Для серверов nginx настройка кэширования выполняется по-другому через файл настроек nginx.conf.

#Включаем кэширование браузера пользователей вашего сайта
location ~* ^.+.(jpg|jpeg|gif|png|svg|js|css|mp3|ogg|mpe?g|avi|zip|gz|bz2?|rar|swf)$ {#какие файлы надо кэшировать
root /var/www/fedor/data/www/sup.seo28.ru;#здесь у вас свои данные должны быть
expires 99d;#Количество дней, сколько будет хранится кэш
}
Подробное описание на сайте sup.seo28.ru http://sup.seo28.ru/kjeshirovanie_stranic_sajta.html#nginx

Дмитрий
Гость

Ну вот, а я думал здесь будет палево никому-не-известных секретных супер-дешёвых cdn-сервисов 🙁

wpDiscuz