Проблема: каждая фотография товара — это запрос
Fashion-e-commerce живёт фотографией. Только главная страница этого магазина ссылается более чем на 130 изображений — слайдеры тяжелее 300 КБ, фотографии товаров примерно 50–350 КБ, — а страницы категорий и товаров повторяют ту же картину. Без CDN каждый посетитель тянет каждый из этих файлов с origin-сервера: одни и те же фотографии, тысячи раз в день, конкурируя за те же PHP-воркеры и полосу, которые должны обслуживать корзины и оформление заказов.
Цель была не экзотической: полностью убрать повторный трафик изображений с origin, держать HTML достаточно свежим для магазина — и всё это не трогая тему WordPress.
Правило для изображений: кешировать год, отдавать за миллисекунды
Сердце всей схемы — одно правило доставки, совпадающее с расширениями изображений (jpg, jpeg, png, gif, webp, svg, ico). Оно кеширует успешные ответы на edge на целый год, добавляет CORS-заголовок, чтобы изображения можно было встраивать где нужно, и сжимает то, что от этого выигрывает, через Brotli и gzip.
Год звучит агрессивно — пока не вспомнишь, как на самом деле меняются фотографии товаров: никак. Загруженная для товара фотография сохраняет свой URL, пока живёт товар; редизайн загружает новые файлы с новыми именами. Длинные TTL означают, что edge почти никогда не переспрашивает origin — в нашей выборке каждая картинка главной уже была HIT. А для редкого случая, когда изображение нужно заменить по тому же адресу, точечный пурж очищает ровно эту запись.
Правило для HTML: один день — и трюк для трафика кампаний
С HTML обходятся иначе: главная страница кешируется на один день — достаточно долго, чтобы edge поглощал почти весь анонимный трафик, и достаточно коротко, чтобы изменения витрины появлялись в тот же день; всё срочное решает пурж.
Деталь, которую стоит забрать себе, — нормализация query-параметров. Трафик из социальных кампаний приходит с трекинговыми параметрами: каждый клик из Facebook несёт уникальный fbclid. При наивном кешировании каждый клик был бы «другим» URL, каждый посетитель кампании — cache MISS, и origin принимал бы полную нагрузку рекламного всплеска в самый неподходящий момент. Правило исключает fbclid из ключа кеша, так что десять тысяч кликов кампании — это одна запись в кеше. Параметр по-прежнему доходит до аналитики; он просто перестаёт дробить кеш.
Что мы измерили
Числа с живого сайта, измеренные через публичный интернет (то есть они включают реальное сетевое расстояние, а не лабораторные условия). Закешированное изображение отвечает с медианным временем до первого байта около 0,15 секунды. Если заставить edge забрать тот же файл с origin, медиана оказывается около 0,54 секунды — примерно в 3,5 раза медленнее. HTML главной, отданный как cache HIT со сжатием Brotli, начинает приходить примерно за 0,27 секунды.
Умножьте этот разрыв на 130+ изображений на просмотр страницы — и эффект на воспринимаемую скорость перестаёт быть тонким: браузер начинает отрисовывать фотографии товаров, пока схема без кеша всё ещё ждала бы первые. И каждый HIT — это запрос, которого origin вообще не видит: во время всплеска кампании работа origin съёживается до обслуживания корзин.
Остальной стек: Redis и WAF без дополнительных усилий
Рядом с кешем работают ещё две части, обе — включённые, а не построенные. На уровне хостинга WordPress подпирает объектный кеш Redis, превращая повторяющиеся обращения к базе — опции, меню, метаданные товаров — в чтение из памяти для тех запросов, которые всё же доходят до PHP. На входе WAF-пресет аккаунта проверяет входящий трафик на том же edge, который отдаёт кеш, так что типовые атаки отфильтровываются до того, как встанут в очередь к origin.
Честная сноска: этот клиент не использует нашу оптимизацию изображений WebP/AVIF — числа выше дают чистые кеширование и сжатие. На столе остаётся измеримый запас (современные форматы обычно существенно снижают вес изображений), и это делает результат более переносимым, а не менее: вот что даёт edge-кеширование само по себе.
Что скопировать для своего магазина
Паттерн переносится на любой сайт с обилием изображений в виде четырёх правил. Кешируйте изображения по расширению с длинным TTL и пуржите при изменении — вместо коротких TTL «на всякий случай»: за «всякий случай» отвечает пурж. Кешируйте HTML на часы или день, а не на ноль, и доверьте свежесть пуржу при деплое. Нормализуйте трекинговые параметры (fbclid, а где позволяет аналитика — и utm_*) из ключа кеша до следующей кампании, а не после того, как она расплавит origin. И проверяйте измерениями, а не ощущениями: один curl с антикэш-параметром против одного без него точно скажет, чего стоит edge на ваших собственных страницах.
Частые вопросы
Безопасен ли годовой TTL изображений для e-commerce?
Да, потому что URL фотографий товаров стабильны: новые товары приносят новые имена файлов. Рискованный случай — замена изображения по тому же URL — закрывается точечным пуржем, который срабатывает за секунды.
Почему главная кешируется всего на день, если изображения получают год?
HTML меняется вместе с витриной — кампании, цены, рекомендуемые товары. День означает, что edge всё равно поглощает почти весь читающий трафик, а изменения в тот же день появляются сами собой; срочные — на расстоянии одного пуржа.
Что на самом деле даёт исключение fbclid из ключа кеша?
Без него каждый рекламный клик — уникальный URL и, значит, cache MISS: весь ваш платный трафик, самый дорогой из всех, приземляется на origin. С ним все клики делят одну закешированную запись. Параметр по-прежнему доходит до ваших аналитических скриптов без изменений.
Стало бы ещё быстрее с WebP/AVIF?
Да, это дополнительно снизило бы объём передачи (часто на 30–70% на фотографиях) — именно поэтому мы отмечаем, что у этого клиента она выключена: цифра в 3,5 раза — это одно только кеширование. Включение оптимизации изображений складывается поверх всего описанного здесь, а не вместо него.
Нужно ли для всего этого менять тему WordPress?
Нет. Всё в этом кейсе — правила кеша, нормализация query, сжатие, WAF, Redis — настраивается на уровне доставки и хостинга. Приложение не менялось.