Кэширование интернет-магазина: настройка страничного, объектного и браузерного кэша
I. За что отвечает каждый из трёх уровней кэша
Кэш интернет-магазина делится на три уровня, каждый решает свою задачу — не путайте их. Страничный кэш сохраняет готовый HTML в статический файл: при следующем заходе на тот же URL файл отдаётся сразу, без запуска PHP и базы данных. Объектный кэш хранит результаты запросов к базе в памяти (например, Redis или Memcached): следующий такой же запрос берётся из памяти, без обращения к MySQL. Браузерный кэш через заголовки HTTP-ответа говорит браузеру посетителя: «этот файл хранится у тебя локально» — при следующем визите он читается прямо с диска.
Выгода от трёх уровней сильно различается. Страничный кэш даёт больше всего — он полностью пропускает выполнение PHP и запросы к базе, и LCP падает с более чем 4 секунд до менее чем 1 секунды. Объектный кэш даёт средний результат — он экономит только время запросов к базе; если страничный кэш уже сработал, объектный вообще не задействуется. Браузерный кэш работает для вернувшихся посетителей — при первом визите файлы всё равно скачиваются, со второго читаются локально, и скорость повторного захода заметно растёт.
| Уровень кэша | Что хранит | Где хранит | Выигрыш в производительности | Типичные инструменты |
|---|---|---|---|---|
| Кэш страниц | Полная HTML-страница | Диск или память сервера | Максимальный, LCP падает на 60–80% | WP Rocket、LiteSpeed Cache |
| Объектный кэш | Результаты запросов к базе, объекты PHP | Redis или Memcached | Средний, время запросов к БД падает на 50% | Redis、Memcached |
| Браузерный кэш | CSS/JS/изображения | Локально в браузере посетителя | Для вернувшихся посетителей, повторный визит быстрее | Заголовок ответа Cache-Control |
| Кэш CDN | Статика + часть HTML | Глобальные пограничные узлы | Задержка между регионами падает более чем на 50% | Cloudflare、Akamai |
Многие сразу начинают возиться с Redis и Memcached, хотя для B2B-сайта правильно настроенное кэширование страниц уже решает 80% проблем с производительностью. Объектное кэширование — это бонус, к нему стоит переходить, когда месячная посещаемость превышает 50 000 уникальных посетителей или запросы к базе данных замедляются. О том, как CDN связан с трёхуровневым кэшированием, читайте в Глобальное ускорение CDN и выбор узлов а о том, какие показатели производительности считаются нормой, — в Оптимизация Core Web Vitals.
II. Кэширование страниц: как хранить HTML без ошибок
Кэширование страниц — самый ценный уровень и самый простой для ошибок. Типичные симптомы неправильной настройки: после отправки заявки посетитель видит данные предыдущего посетителя; или после входа пользователь видит страницу в неавторизованном состоянии. Причина в том, что кэш страниц сохраняет HTML с динамическим содержимым как статический файл.
Правильный подход — разделить страницы на две категории по URL и статусу пользователя: публичные статические страницы (главная, страницы товаров, статьи блога) кэшируются; динамические страницы (страница после отправки формы заявки, админка wp-admin, страницы после входа, корзина) должны обходить кэш. Плагины кэширования WordPress (WP Rocket, LiteSpeed Cache) поддерживают правила «исключить URL» и «пропускать кэш по Cookie».
| Тип страницы | Кэшировать | Время кэширования | Правила исключения |
|---|---|---|---|
| Главная, список товаров | Кэш | от 1 до 4 часов | Исключить авторизованных |
| Страница блога | Кэш | от 12 часов до 1 дня | Обновлять вручную при изменении контента |
| Страница формы заявки | Не кэшировать | Не задано | Всегда запрашивать с сервера |
| Страница успешной отправки формы | Не кэшировать | Не задано | 带session cookie |
| Админка wp-admin | Не кэшировать | Не задано | Исключить по cookie администратора |
| Страница результатов поиска | Короткий кэш или без кэша | 5 минут | Не кэшировать разные поисковые запросы |
Пример: страница товара на сайте промышленного оборудования, URL — /products/cnc-machine-a/, содержимое меняется раз в несколько месяцев, её вполне можно кэшировать на 1 день. Но страница «Заявка отправлена» с URL /inquiry-thank-you/ должна показывать каждому посетителю подтверждение именно его отправки, поэтому её кэшировать нельзя. В WP Rocket добавьте /inquiry-thank-you/ и /wp-admin/* в список Never Cache URL(s).
Сброс кэша тоже важен для кэширования страниц. Изменили статью в блоге — как сразу обновить её на сайте? Два способа: вручную очистить весь кэш при публикации или обновить только эту страницу по URL. WP Rocket автоматически сбрасывает связанный кэш при обновлении записи, но для многих кастомных страниц это не срабатывает — нужно взять за привычку нажимать Purge после публикации. В crater на сайтах для выхода на зарубежные рынки сброс кэша привязан к процессу публикации, подробнее в Технологический стек crater и четыре собственных плагина.
III. Объектное кэширование: как переиспользовать результаты запросов к базе данных
Когда срабатывает кэш страниц, PHP и база данных не запускаются, и объектный кэш тоже не нужен. Но если кэш страниц промахнулся — например, вы только что опубликовали новую статью или открыли динамическую страницу, которую не стоит кэшировать, — PHP идёт в базу данных. В среднем страница WordPress делает от 12 до 20 запросов к базе, каждый запрос упирается в дисковый ввод-вывод, и накопленные медленные запросы легко растягивают загрузку страницы больше чем на секунду.
Объектный кэш хранит результаты этих запросов в Redis или Memcached, и при следующем таком же запросе они читаются прямо из памяти. Redis ставится на один сервер, WordPress подключается через плагин Redis Object Cache, код менять не нужно. При правильной настройке время запросов к базе падает больше чем на 50%, а отклик при промахе кэша страниц — с 1,5 секунды до менее чем 0,5 секунды.
| Показатель | Без объектного кэша | С объектным кэшем Redis | Прирост |
|---|---|---|---|
| Запросов к базе на страницу | 12–20 на страницу | 2–5 на страницу | Сокращение на 70–80% |
| Время одного запроса | 5–20 мс (дисковый ввод-вывод) | 0,1–1 мс (память) | В 10–50 раз быстрее |
| Отклик при промахе кэша страниц | 1–1,5 секунды | 0,3–0,5 секунды | Снижение больше чем на 50% |
| Загрузка CPU MySQL | Больше 80% в пик | 30–40% в пик | Снижение больше чем вдвое |
Объектный кэш нужен не всем. Для B2B-сайта с месячной аудиторией до 10 000 уникальных посетителей нагрузка на базу небольшая, кэш страниц уже держит 95% запросов, и выгода от Redis незаметна. Когда его стоит ставить? Два сигнала: первый — в логе медленных запросов MySQL больше 100 запросов в день длиннее секунды; второй — после сохранения статьи в админке изменения на сайте появляются только через несколько минут (объектный кэш не сбрасывается правильно). О медленных запросах и оптимизации индексов читайте в статье Медленные запросы и оптимизация индексов в базе данных интернет-магазина.
Четыре. Кэш браузера: как настроить заголовки кэширования статических ресурсов
Кэш браузера — самый простой в настройке из трёх уровней. Он не затрагивает серверные программы: достаточно добавить несколько строк заголовков в веб-сервере (Nginx или Apache). Принцип такой: отдавая CSS, JS или картинку, сервер добавляет в HTTP-заголовок Cache-Control: max-age=2592000 и говорит браузеру «храни этот файл у себя 30 дней» — в течение 30 дней повторные обращения к серверу не идут.
Но здесь есть классическое противоречие: чем дольше кэш браузера, тем быстрее открывается сайт, но если вы изменили CSS или JS, у пользователя остаётся старая версия и страница выглядит неправильно. Решение не в том, чтобы сократить срок кэширования, а в том, чтобы добавить к имени файла версию или хэш — например, style.css?v=2 или style.abc123.css. Содержимое файла изменилось — изменился URL, и браузер скачивает файл заново.
| Тип ресурса | Рекомендации по Cache-Control | max-age | Стратегия обновления |
|---|---|---|---|
| Изображения (jpg/png/webp) | public, max-age=31536000 | 1 год | Хэш в имени файла: меняете картинку — меняете имя |
| Файлы шрифтов | public, max-age=31536000 | 1 год | Шрифты не меняются — трогать не нужно |
| Таблицы стилей CSS | public, max-age=604800 | 7 дней | Версия в имени файла: ?ver=2 |
| JavaScript | public, max-age=604800 | 7 дней | Версия в имени файла: ?ver=2 |
| HTML-страницы | no-cache, must-revalidate | Не кэшировать | Проверка на источнике при каждом запросе |
| favicon.ico | public, max-age=604800 | 7 дней | Меняется редко |
Контринтуитивный вывод: многие боятся, что при долгом кэшировании пользователи не увидят изменений, и ставят max-age в 1 час для всех ресурсов. В итоге каждый посетитель при каждом заходе заново скачивает весь CSS и JS, и первый экран загружается медленнее. Правильно — смело ставить долгий срок (изображения — 1 год, CSS/JS — 7 дней), а обновления решать через хэш файла или номер версии. Функция wp_enqueue_script в WordPress сама добавляет номер версии, и при обновлении темы или плагина он меняется автоматически — вручную следить не нужно.
Об оптимизации изображений и управлении медиафайлами читайте в разделе Управление медиафайлами и сжатие изображений. В многоязычных сайтах кэширование статических ресурсов требует учёта взаимодействия hreflang и кэша CDN, см.Hreflang для мультиязычных сайтов.
Пять. Стратегии инвалидации кэша и типичные конфликты
После настройки кэша главная проблема — «как заставить кэш устареть, когда это нужно». Если кэш не сбрасывается вовремя, пользователи видят старое содержимое; если сбрасывается слишком легко, выгода от производительности пропадает. В независимых интернет-магазинах есть четыре типичные ситуации инвалидации кэша: публикация новой статьи, обновление информации о товаре, изменение CSS/JS, отправка формы запроса. Для каждой ситуации своя стратегия инвалидации.
| Ситуация | Область инвалидации | Способ инвалидации | На что обратить внимание |
|---|---|---|---|
| Публикация новой статьи в блоге | Главная + список статей + отдельная статья | WP Rocket обновляет автоматически | Страницы категорий и тегов тоже нужно обновлять |
| Обновление цены товара | Страница товара + страница списка | Вручную Purge нужного URL | Не делайте Purge всего — это бьёт по производительности |
| Изменение CSS/JS | Соответствующий статический файл | Смена номера версии вступает в силу автоматически | Не меняйте max-age, меняйте имя файла |
| Отправка формы запроса | Страница формы не кэшируется никогда | Правило исключения по URL | Страница успешной отправки тоже не кэшируется |
| Полный редизайн сайта | Весь кэш | Purge All одной кнопкой | Делайте в часы низкой нагрузки |
| Обновление плагина/темы | Весь кэш | Автоматический или ручной Purge | Перед обновлением сделайте резервную копию |
Типичных конфликтов два. Первый — установлены два плагина кэширования (например, одновременно WP Rocket и LiteSpeed Cache): оба правят .htaccess и буфер вывода, в результате страница белая или стили ломаются. Правило: на всём сайте только один плагин кэширования. Второй — конфликт кэша страниц со статусом входа: пользователь вошёл в админку, а на фронтенде всё ещё кэшированная страница для неавторизованных, и навигация отображается неправильно. Решение — плагин кэширования распознаёт cookie входа и автоматически пропускает кэш.
После запуска стратегии кэширования нужно постоянно следить за ней: раз в месяц проверять долю попаданий в кэш и LCP. Резкое падение доли попаданий обычно означает, что кто-то изменил структуру URL или добавил ссылки со случайными параметрами. Список для мониторинга и оповещений см. в Мониторинг сайта и оповещения, о повседневном обслуживании см. в Шесть задач на месяц в период обслуживания сайта. Учения по резервному копированию и восстановлению тоже нужно проводить после изменения настроек кэша, см.Бэкап и восстановление сайта.
FAQ: частые вопросы
Обязательно ли ставить плагин кэширования на независимый сайт WordPress?
Можно ли кэшировать страницу с формой заявки?
Когда нужно подключать объектный кэш Redis?
На какой срок ставить кэширование в браузере?
Что делать, если после изменения контента пользователи видят старую версию?
Конфликтуют ли кэш страниц и кэш CDN?
В заключение
С кэшированием новички чаще всего бросаются в две крайности: либо вообще ничего не настраивают, и каждая страница каждый раз дёргает PHP и базу данных — первый экран грузится больше 4 секунд; либо настраивают слишком агрессивно, кэшируют даже страницы с формами, и пользователь видит чужие отправленные данные. Правильный подход — разделить по уровням: статические страницы кэшируем смело, динамические — категорически нет, а статику отдаём с длинным кэшем и версионированием.
Три шага на практике. Первый: ставим плагин кэширования страниц (WP Rocket или LiteSpeed Cache — на выбор) и исключаем страницы с формами и wp-admin. Второй: настраиваем в Nginx заголовок Cache-Control — картинки на год, CSS/JS на 7 дней, HTML не кэшируем. Третий: когда месячная посещаемость перевалит за 50 000, подключаем объектный кэш Redis. После этих трёх шагов LCP обычно укладывается в секунду, и никаких аварий с перемешанным содержимым кэша не будет.
Запомните главное: кэш — это рычаг производительности вашего сайта. Кэш страниц экономит 80% времени, объектный кэш разгружает базу данных, кэш браузера ускоряет повторные визиты. У каждого уровня своя задача — и следите, чтобы страницы с формами не попадали в кэш.
