- html5css.dev
- SEO
- Мобильное SEO
- Скорость сайта
- Настройка многоуровневого кеширования
Настройка многоуровневого кеширования
Кеш — самый дешёвый способ ускорения: лучший запрос тот, которого не было. Разбираем четыре уровня, правильные заголовки для каждого типа ресурса и главную сложность — инвалидацию.
Expires и советом
«поставить месяц на картинки». Ниже — актуальная схема с версионированием
файлов, immutable и тегированной инвалидацией.
Четыре уровня
| Уровень | Что хранит | Выигрыш | Чем управляется |
|---|---|---|---|
| 1. Браузер | Статику и ответы | Ноль запросов при повторном визите | Cache-Control, ETag |
| 2. CDN | Статику и HTML | Ответ из ближайшей точки | Заголовки + настройки CDN |
| 3. Сервер | Готовые страницы | Приложение не запускается | Кеш nginx, кеш CMS |
| 4. Приложение | Результаты запросов к базе | База не нагружается | Redis, Memcached, OPcache |
Правило: чем ближе к пользователю сработал кеш, тем дешевле ответ. Поэтому настраивают сверху вниз.
Заголовки по типам ресурсов
| Ресурс | Cache-Control | Почему |
|---|---|---|
| CSS, JS с версией в имени | public, max-age=31536000, immutable | Меняется имя — меняется URL |
| Изображения с версией | public, max-age=31536000, immutable | То же |
| Шрифты | public, max-age=31536000, immutable | Практически не меняются |
| HTML контентных страниц | public, max-age=300, s-maxage=3600 | Свежесть важнее экономии |
| HTML персонализированных | private, no-store | Нельзя отдавать чужие данные |
| API-ответы | private, max-age=0, must-revalidate | Валидация по ETag |
| sitemap.xml, robots.txt | public, max-age=3600 | Меняются редко, но должны обновляться |
# nginx: долгий кеш для версионированной статики
location ~* \.(css|js|woff2|avif|webp|jpg|png|svg)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
access_log off;
}
# HTML: короткий кеш у браузера, длиннее у CDN
location / {
add_header Cache-Control "public, max-age=300, s-maxage=3600";
}
Версионирование вместо сброса
Главный приём, делающий годовой кеш безопасным: имя файла содержит хеш содержимого. Изменили файл — изменился URL — браузер загрузит новый, а старый просто перестанет использоваться.
/css/main.a3f9c21b.css
/js/app.7d20e14c.js
/img/hero.5b81ff09.avif
Альтернатива попроще — метка времени изменения файла в параметре. Именно так
устроены ассеты этого раздела: в inc/ctx.php есть функция
seo_asset(), добавляющая ?v= по filemtime.
Кеш сбрасывается сам при любой правке CSS или JS.
Инвалидация: самое сложное место
Проблема не в том, чтобы закешировать, а в том, чтобы вовремя сбросить. Изменили цену товара — устарели карточка, страница категории, результаты фильтра, блок «похожие» на десятке других страниц и главная.
- Тегирование кеша. Каждой закешированной странице сопоставляются теги сущностей на ней:
product:1024,category:15. При изменении товара сбрасываются все страницы с его тегом. - Короткий TTL для изменчивого. Там, где тегирование не окупается, проще поставить пять минут.
- Сброс по событию. Публикация или изменение цены дёргает очистку конкретных ключей.
- Прогрев после сброса. Массовая инвалидация без прогрева даёт всплеск нагрузки.
- Никогда не кешировать надолго HTML без версии — иначе правка «не выезжает» неделями.
private, no-store.
Проверка
# заголовки кеширования конкретного ресурса
curl -sI https://site.ru/css/main.a3f9c21b.css | grep -iE 'cache-control|etag|age'
# сработал ли кеш на повторном запросе
curl -sI -H 'If-None-Match: "abc123"' https://site.ru/page/ | head -1
В DevTools → Network колонка Size показывает «disk cache» или «memory cache» для ресурсов, взятых из кеша браузера. Если при повторной загрузке всё качается заново — заголовки настроены неверно.
Итог
Настраивайте сверху вниз: годовой кеш для версионированной статики, короткий для HTML, полностраничный кеш на сервере для контентных страниц, кеш запросов в приложении. Основная работа приходится не на включение кеша, а на аккуратную инвалидацию. Дальше — использование CDN.
Частые вопросы
Какие заголовки ставить для статики?
Для файлов с версией в имени — Cache-Control: public, max-age=31536000, immutable. Год кеша безопасен, потому что при изменении файла меняется его имя, а значит и URL.
Как кешировать HTML?
Коротко или через валидацию. Для страниц, которые редко меняются, подходит max-age=0, must-revalidate с ETag: браузер спрашивает сервер, изменилось ли что-то, и обычно получает 304.
Что такое инвалидация кеша и почему это сложно?
Сброс устаревших данных. Сложность в том, что одна правка может затрагивать десятки закешированных страниц: изменили цену товара — устарели карточка, категория, поиск и главная. Решается тегированием кеша.
Нужен ли полностраничный кеш?
Для контентных страниц — да, это самый большой выигрыш: приложение не запускается вовсе. Для персонализированных страниц (корзина, личный кабинет) он не подходит.
Вся глава «Скорость сайта» — 7 уроков
- Производительность сайта и способы её измерения
- Минификация контента
- Сжатие: Brotli и GZIP
- Оптимизация изображений
- Протоколы HTTP/2 и HTTP/3
- Настройка многоуровневого кеширования
- Использование CDN