Девятая статья серии «Архитектура и производительность». Мы уже научились раскладывать нагрузку по серверам (балансировка нагрузки), ускорять ответы из кэша (кеширование) и видеть, где именно всё тормозит, по логам и трассировке (логирование и трассировка). В прошлой серии мы довели клиент до автономности: приложение умело работать без сети благодаря сервис-воркерам и офлайн-режиму.
Теперь посмотрим на то, что стоит между вашим сервером и браузером пользователя. Когда проект выходит за пределы одного города, одного языка и одного провайдера, выясняется простая вещь: скорость ответа зависит не только от того, как быстро работает ваш код, но и от того, как далеко летит пакет. Один и тот же файл, отданный с сервера в Москве пользователю во Владивостоке, в Бразилии или в Южной Африке, придёт с разницей в секунды. CDN и edge-вычисления — это способ сократить этот полёт.
Разберём по-простому: что такое CDN и точки присутствия, как устроены слои кэширования и origin shield, что означают по-русски заголовки Cache-Control, такое edge-логика и Varnish, как работает geo-routing, чем CDN прикрывается от DDoS и как встроить это всё в сервис-воркер, который вы уже написали. Плюс готовые фрагменты на nginx, HTML и JavaScript.
Часть I. Что такое CDN и как устроены его слои
1. Скорость — это расстояние, а не только мощь
Начнём с физики. Скорость света в оптоволокне — примерно двести тысяч километров в секунду. Между Москвой и Владивостоком около девяти тысяч километров кабеля, и туда-обратно пакет идёт хотя бы 90 миллисекунд чистой задержки, а с учётом маршрутизации на роутерах — 120–150. Между Москвой и Сан-Паулу — 180–230 миллисекунд. Это на один запрос. А страница делает их десятки.
Ваш сервер один, он физически стоит в одном месте. Как бы вы его ни масштабировали (см. балансировку нагрузки), пользователи на другом континенте всё равно платят за расстояние. CDN решает это не «ускорением сервера», а приближением контента.
CDN (Content Delivery Network, сеть доставки контента) — это сеть серверов, расставленных по разным странам и городам, которые держат копии ваших файлов и отдают их оттуда, где пользователь находится рядом. Пользователь из Берлина качает картинку не из вашего дата-центра в Москве, а из сервера в Франкфурте в десяти миллисекундах от себя.
PoP (Point of Presence, точка присутствия) — это один такой узел в конкретном городе. Обычно это не одна машина, а небольшая группа серверов в одном дата-центре: балансировщик разливает входящие по ним, чтобы один узел тянул толпу. Когда говорят «у CDN двести PoP», имеют в виду двести городов, где стоят такие группы.
Простая ментальная картинка: ваш origin-сервер — это оптовый склад. PoP — это магазины у дома в каждом городе. Пользователь идёт в ближайший магазин, а не едет на склад.
2. Откуда берётся копия файла в PoP
Важно сразу понять: CDN не копирует всё заранее. Он работает по принципу «ленивой доставки».
Первый пользователь в Берлине просит файл app.css. Берлинский PoP смотрит в свой кэш — пусто. Тогда он сам идёт на ваш origin-сервер, качает файл, отдаёт его пользователю и заодно кладёт в свой кэш. Все следующие пользователи Берлина получают файл уже из PoP, до origin не доходя.
Отсюда два важных вывода:
- Первый запрос всегда медленнее — он идёт на origin. Это называется «холодный PoP», «miss» (промах) в терминах кэша.
- CDN — это кэш, а не база данных. Он хранит ответ ровно столько, сколько вы ему скажете заголовками. Скажете
max-age=0— он будет каждый раз лететь к origin, и толку от него почти не будет.
Здесь CDN смыкается с тем, что вы уже читали в кешировании: те же понятия hit (попадание) и miss (промах) работают и на сетевом уровне.
3. Слои кэширования: почему их несколько
Если у CDN двести PoP, а на origin нахлынет толпа, все двести узлов промахнутся одновременно и дружно застучат на ваш сервер. Это ровно та же «лавина одинаковых запросов» (cache stampede), которую мы разбирали в статье про кэширование. Чтобы этого не случилось, вводят слои.
Классическая раскладка — три слоя:
| Слой | Где живёт | Что хранит | Кого бережёт |
|---|---|---|---|
| Edge PoP (ближний) | город пользователя | горячие файлы этого региона | пользователя (скорость) |
| Региональный PoP (дальний) | крупный хаб (Франкфурт, Сингапур) | общие для региона файлы | edge-слой |
| Origin shield | один хаб перед origin | агрегированный кэш | ваш сервер |
Edge-слой обслуживает людей. Региональный слой нужен, чтобы десятки edge-узлов одного региона не лезли на origin за одним и тем же файлом: они спрашивают у регионального. А origin shield — последняя преграда перед вашим настоящим сервером: он собирает все промахи всей сети в один вход и сам идёт к origin максимум один раз на файл.
4. Когда CDN нужен, а когда это лишняя сущность
CDN полезен почти всегда, где есть статика и география. Но чтобы не усложнять впустую, решайте по делу:
- Есть пользователи из разных регионов или стран → CDN даёт заметный выигрыш, особенно на картинках, шрифтах, CSS/JS.
- Проект на одном VPS, аудитория из одного города → выигрыш меньше; CDN полезен хотя бы ради защиты и TLS-разгрузки, но не обязателен.
- Контент почти не кэшируется (личная лента, персональные данные под каждый запрос) → CDN на такое почти не влияет; здесь помогают кэш приложения и оптимизация БД, а не сеть доставки.
CDN — это транспорт и кэш на транспортном уровне. Он не отменяет работу вашего кода: он лишь решает, сколько раз к origin вообще доедут запросы.
Часть II. Заголовки Cache-Control: срок годности ответа простыми словами
5. Cache-Control — это инструкция для кэша
Когда ваш сервер отдаёт файл, он отправляет вместе с ним HTTP-заголовок Cache-Control. Это не украшение: именно по нему и edge-PoP, и браузер решают, можно ли использовать сохранённый ответ и сколько он ещё годен.
Самые важные директивы (правила) переведём на человеческий русский:
| Директива | Формально | По-русски |
|---|---|---|
max-age=31536000 | ответ свеж 31 536 000 секунд | «считай этот ответ свежим целый год, не ходи ко мне» |
s-maxage=86400 | срок только для разделяемых кэшей (CDN) | «для CDN — сутки; для браузера — смотри max-age» |
no-store | не сохранять нигде | «вообще не сохраняй этот ответ, он слишком секретный» |
no-cache | можно хранить, но всегда проверяй | «держи копию, но перед выдачей спроси у меня, не изменилась ли она» |
public / private | можно ли кэшировать посредникам | public — всем, private — только браузеру пользователя |
must-revalidate | по истечении срока — обязательная проверка | «просрочено — не отдавай по-тихому, иди проверяй» |
6. immutable: «файл с хэшем в имени никогда не изменится»
Директива immutable — это обещание: содержимое этого URL не поменяется никогда, даже когда срок годности выйдет. Браузер с immutable не будет слать conditional-запрос (проверку «а точно не изменилось?») даже после перезагрузки страницы.
Это работает по одной простой причине: файл называют по содержимому. Например app.7f3a9c.css. Изменили стили — сборщик пересчитал хэш и отдал app.b12d4f.css. Старый URL app.7f3a9c.css больше никем не используется, но и не менялся — значит, его можно кэшировать на год с immutable.
# Для статики с хэшем в имени — максимум агрессивности:
Cache-Control: public, max-age=31536000, immutable
# Для HTML-страницы, которую надо отдавать свежей, но дёшево:
Cache-Control: no-cache
7. stale-while-revalidate: «отдай старьё, обнови в фоне»
Самая удобная директива для контента, где скорость важнее идеальной свежести: новостные ленты, цены, описания товаров.
stale-while-revalidate=60 означает: после того как срок max-age истёк, можно ещё до 60 секунд отдавать пользователю протухший (stale) ответ немедленно, а параллельно тихо сходить к origin, забрать свежий и заменить его в кэше. Первый в этом окне пользователь получит старый контент за нулевую задержку до origin; те, кто придёт следом, уже свежий.
Это сетевой аналог стратегии stale-while-revalidate, которую мы реализовывали в сервис-воркере прошлой серии (об этом в Части VII). Разница в том, что там это делает браузер, а здесь — CDN.
8. Мета-теги HTML: наследие и честная оговорка
Исторически кэш можно было намекать из HTML через <meta http-equiv="Cache-Control">. Важно понимать по-русски: для CDN этот способ не работает. Сеть доставки читает заголовки HTTP-ответа, а не содержимое тега body. Мета-тег видит только сам браузер (да и тот с оговорками), и то не везде. Ставить no-cache в мета-теге, ожидая, что «CDN не будет кэшировать», — типичная ошибка.
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<!-- Мета-подсказка: действует только на браузер, но НЕ заменяет
HTTP-заголовок. CDN и прокси её не читают — для них нужен
настоящий заголовок Cache-Control на сервере (см. Часть V). -->
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Pragma" content="no-cache">
<title>Страница</title>
<!-- Статика с хэшем в имени кэшируется долго, сам HTML — нет -->
<link rel="stylesheet" href="/assets/app.7f3a9c.css">
</head>
<body>
<p>Актуальный контент всегда отдаётся по-новому, а картинка — из кэша.</p>
<img src="/assets/hero.3b9c11.webp" width="1200" height="600" alt="Обложка">
</body>
</html>Правильный порядок: срок годности ответа живёт в HTTP-заголовке, который ставит сервер или nginx; мета-теги — это максимум подсказка браузеру, и полагаться на них нельзя.
Часть III. Origin shield: защита исходного сервера
9. Что такое origin и почему его надо беречь
Origin (исходный сервер) — это ваш настоящий сервер, тот, который генерирует контент: PHP, база данных, файловое хранилище. Всё, что отдаёт CDN, — это копия с origin. Origin дорог в обслуживании: он выполняет код, ходит в базу, тратит CPU на рендер.
Если CDN настроен плохо, origin превращается в единственное узкое горлышко. Худший сценарий: вышел срок годности у популярного файла, и в одну секунду двести PoP промахнулись — двести запросов ударили по origin. Это и есть cache stampede на сетевом уровне, только в десять раз крупнее.
10. Как origin shield собирает промахи в одну точку
Origin shield (щит источника) — дополнительный слой кэша: один выбранный PoP, перед которым стоит вся остальная сеть. Вместо того чтобы каждый из двухсот узлов шёл к origin, edge-узлы идут к shield. Shield один раз сходил на origin, получил файл и раздал всем.
Без origin shield:
user -> [200 edge PoP] --200 промахов--> [origin] origin тонет
С origin shield:
user -> [edge PoP] -> [origin shield] --1 промах--> [origin] origin спокоен
Практически это выглядит так: вы указываете CDN-провайдеру, в каком регионе держать shield-хаб. Провайдер сам маршрутизирует все сетевые промахи через него. Для вашего сервера вся сеть CDN превращается в «одного клиента из одного IP».
11. Правила хорошего origin shield
- Белый список shield-IP на файрволе origin. Если к вашему серверу можно достучаться напрямую, shield не спасёт от атаки. Закрывайте origin так, чтобы его трогал только shield (и, при необходимости, мониторинг).
- Управляйте TTL осознанно. Shield хранит ответ по
s-maxage/max-age. Короткий срок = shield чаще ходит на origin. Длинный = реже, но контент может быть устаревшим. - Не кэшируйте на shield то, что нельзя в принципе — персональные ответы с
no-storeвообще не должны попадать ни в один слой.
Origin shield — это то же самое, что read-through и группировка ключей в обычном кэше, только в географическом масштабе.
Часть IV. Edge-вычисления: логика близко к пользователю
12. Что значит «выполнять логику близко к пользователю»
Классический CDN только копирует готовые ответы. Но современные сети позволяют исполнять код прямо на PoP — то есть в том самом городе, где сидит пользователь. Это и называют edge-вычислениями (edge — «край», периферия сети; логика живёт на краю, а не в центре).
Зачем делать на краю то, что можно сделать на origin? Потому что здесь выигрывают три вещи:
- Задержка. Миллисекунды рядом с пользователем вместо ста на межконтинентальный путь.
- Разгрузка origin. Если решение можно принять на PoP, origin вообще не просыпается.
- Локальная адаптация. По стране можно менять язык, валюту, цену на доставку, не трогая код приложения.
near-user execution (выполнение близко к пользователю) — это и есть весь смысл edge: не ждать ответа издалека, а сделать нужное действие там, где находится человек.
13. Varnish: HTTP-кэш и логика на границе
Varnish — это быстрый HTTP-кэш и веб-ускоритель на границе: он стоит перед вашим приложением, разбирает запросы, кэширует ответы и выполняет логику на языке VCL (конфигурационный язык Varnish). Часто Varnish ставят и как локальный shield-слой прямо в вашем дата-центре: nginx -> Varnish -> PHP-FPM.
Логика на Varnish умеет, например: убрать куку из кэшируемого ответа, склеить страницу из кусков, перенаправить мобильного пользователя, добавить нужный заголовок — и при этом не будить приложение.
# Заглянуть в состояние Varnish: попадания/промахи и сколько памяти занято
varnishstat -1
# Что Varnish вернул по конкретному объекту (ключ кэша)
varnishadm "ban.list"
# Принудительно выкинуть всё, что относится к домену (инвалидация)
varnishadm "ban req.url ~ /articles/"
14. Edge-функции: небольшой код на краю
У крупных CDN-провайдеров есть edge-функции — мини-программы (обычно на JavaScript в изолированном рантайме или на собственном языке конфигурации), которые исполняются на PoP по событиям «запрос пришёл», «ответ с origin получен», «ответ уходит пользователю».
Типичные задачи edge-функции:
- переписать
Cache-Controlперед выдачей (например, добавитьstale-while-revalidateтам, где origin его не ставит); - по геолокации вернуть пользователя на локальный поддомен;
- подменить не найденный ресурс (
404) на кэшированную страницу-заглушку; - сжать картинку на лету или добавить водяной знак;
- проверить токен и вернуть
401до того, как запрос дойдёт до origin.
Важное ограничение: edge-функции не должны долго думать и ходить в базу — они живут на краю и работают с тем, что уже в кэше или в самом запросе. Это функция «транспортного» уровня, а не замена бизнес-логики приложения.
Часть V. Geo-routing: как трафик попадает к ближайшему серверу
15. Три способа направить пользователя
Geo-routing (географическая маршрутизация) — это набор приёмов, которые решают, какой PoP отдаст контент конкретному человеку. «Ближайший» — это не обязательно ближайший по карте, а ближайший по сетевой доступности и загрузке. Основные способы:
- Anycast. Один и тот же IP-адрес объявлен с нескольких PoP сразу. Сеть сама ведёт пакет к ближайшему «объявлению» адреса — это работает на уровне маршрутизации и почти не требует настройки. Плюс: прозрачно и устойчиво к DDoS (трафик рассеивается по узлам). Минус: труднее отлаживать, «почему именно этот узел».
- DNS-роутинг (GeoDNS). Авторитетный DNS CDN смотрит, откуда пришёл запрос, и отдаёт адрес ближайшего PoP. Плюс: гибко. Минус: результат зависит от кэша DNS и от того, какой резолвер использует пользователь (публичный DNS может увести в чужой город).
- HTTP-редирект. Один входной узел, получив запрос, смотрит на
X-Forwarded-Forили данные геолокации и перенаправляет на нужный PoP. Плюс: полный контроль логики. Минус: лишние миллисекунды на редирект.
16. nginx и доверенные заголовки от CDN
Когда CDN стоит перед вашим nginx, клиентский IP в логах nginx — это IP узла CDN, а не пользователя. Чтобы геолокация, лимиты запросов и логи работали правильно, nginx должен уметь извлекать настоящий адрес из заголовков и доверять им. Ниже — прокси-конфигурация, совместимая с CDN: она передаёт нужные заголовки наверх и корректно разбирает протокол и клиентский адрес.
server {
listen 443 ssl http2;
server_name example.com;
# Диапазоны IP, которые принадлежат вашему CDN-провайдеру.
# Доверять заголовкам можно только от них, иначе любой
# посетитель подставит себе любой X-Forwarded-For.
set_real_ip_from 203.0.113.0/24; # условные подсети PoP
set_real_ip_from 198.51.100.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on; # идти по цепочке адресов
location / {
proxy_pass http://php_backend;
# Заголовки, которые CDN и балансировщик передают выше
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Протокол origin и задержка — полезно для трассировки
proxy_set_header X-Request-ID $request_id;
}
# Статика с хэшем в имени: год и immutable
location /assets/ {
add_header Cache-Control "public, max-age=31536000, immutable";
# Разрешаем CDN хранить копию
add_header X-CDN-Cacheable "yes";
}
# HTML отдаём с условным кэшированием через CDN
location ~ \.php$ {
# срок для CDN чуть мягче, чем для браузера
add_header Cache-Control "s-maxage=300, stale-while-revalidate=60";
}
}Ключевая мысль: nginx передаёт наверх X-Forwarded-For (цепочку адресов), X-Forwarded-Proto (изначальный протокол http/https) и X-Request-ID (сквозной идентификатор запроса для трассировки — см. логирование и трассировку). Без корректных доверенных подсетей эта схема опасна: поддельный X-Forwarded-For обходит лимиты и врёт в логах.
17. Как проверить, что geo-routing работает
- Посмотрите заголовок
X-CacheилиCF-Cache-Status(имя зависит от провайдера):HIT,MISS,BYPASS. - Сравните
X-Response-POPCodeили аналог — он покажет, какой узел отдал ответ. - Сделайте запрос из нескольких регионов (через внешний тест или VPN) и проверьте, меняется ли узел и падает ли задержка.
- Посмотрите время отклика origin на shield-хабе — там оно должно быть стабильным, даже если на edge идёт толпа.
Geo-routing — это продолжение той же темы, что и балансировка: там вы раскладываете запросы по серверам одного дата-центра, а здесь — по дата-центрам мира.
Часть VI. Безопасность: базовая защита от DDoS и интеграция WAF
18. Почему CDN сам по себе немного защищает
DDoS (Distributed Denial of Service, распределённая атака отказа в обслуживании) — это попытка завалить сервер таким количеством запросов, что он перестаёт отвечать нормальным пользователям. Атакующий использует тысячи заражённых машин, откуда и «распределённость».
CDN прикрывает от DDoS по двум причинам:
- Масштаб. Поток атаки сначала упирается в сеть CDN, у которой сотни PoP и огромная полоса пропускания. Вам на origin надо «пробить» не всю атаку, а только то, что прошло сквозь shield и не удовлетворилось из кэша.
- Отделяемость. Origin физически скрыт за CDN: его реальный IP может вообще не светиться в DNS. Прямой удар по origin для атакующего — задача посложнее, чем удар по публичному домену.
Но это базовая, пассивная защита. Она хороша против простого флуда статикой (потому что статика отдаётся из кэша и origin не нагружается). Против «умной» атаки на динамические страницы, которая обходит кэш и бьёт по вашему коду и базе, её недостаточно.
19. WAF: файрвол веб-приложений на входе
WAF (Web Application Firewall, файрвол веб-приложений) — это фильтр, который смотрит не на IP и порты, а на содержимое HTTP-запроса и блокирует типовые приёмы атак: SQL-инъекции, межсайтовый скриптинг (XSS), обход авторизации, автоподбор паролей, вредоносные payload в форме. В отличие от сетевого файрвола, который решает «кому вообще можно стучаться», WAF решает «разрешён ли этот конкретный запрос и это конкретное содержимое».
Когда WAF стоит на edge, у него два преимущества:
- Атака отсекается до origin. Плохой запрос не будит ни приложение, ни базу.
- Единая политика на все PoP. Правила WAF раскатываются по сети разом, а не копипастятся на каждый сервер.
# Типовая проверка: что вернул WAF по блокам (пример с логом edge-фильтра)
# Смотрим, какие правила сработали за последний час и с какими IP.
grep -i 'blocked\|waf' /var/log/edge/firewall.log | tail -n 20
# Счётчик запросов, отбитых файрволом (для мониторинга)
awk '/blocked/ {count++} END {print "заблокировано:", count}' /var/log/edge/firewall.log
Интеграция WAF в edge — это логичное продолжение статьи про WAF и ModSecurity: там мы рассматривали его как часть вашего nginx, а здесь выносите правила на уровень сети, ближе к источнику трафика.
20. TLS и загрузка криптографии
Отдельная приятная сторона CDN: разгрузка TLS. Шифрование/расшифрование HTTPS — дорогая по CPU операция. Когда терминация TLS (точка, где пакет «распаковывается») происходит на edge PoP, ваш origin принимает уже обычный расшифрованный трафик и тратит процессорное время на приложение, а не на криптографию. Сертификат при этом живёт на edge, а origin можно держать на «внутреннем» канале.
Это важно и для безопасности: вы держите приватный ключ не на каждом сервере, а в управляемом edge-слое, и обновляете его в одном месте.
Часть VII. Синхронизация с сервис-воркерами: мост к офлайн-кэшу
21. Браузер и CDN — два кэша одного пути
Вы уже построили офлайн-кэш в сервис-воркерах прошлой серии. Теперь посмотрим, как он стыкуется с CDN. У вас фактически два уровня кэша, и оба работают по одним принципам:
- CDN (edge PoP) — кэш между origin и всем миром.
- Service Worker (Cache API) — кэш между CDN и конкретным человеком в его браузере.
Хорошая новость: они договороспособны через одни и те же заголовки Cache-Control. Статика с max-age=31536000, immutable одинаково дорого живёт и на PoP, и в Cache API воркера. А stale-while-revalidate — это ровно та же стратегия, которую вы реализовывали руками в воркере: теперь её частично берёт на себя CDN, а воркер подхватывает то, что сеть не отдала.
22. Сопоставление кэша с учётом версий и CDN
Практическая задача: сервис-воркер должен уметь находить закэшированный ответ даже когда URL немного отличается (например, CDN добавил параметр, или версия сборки в имени файла). Ниже — логика сопоставления кэша в воркере с учётом хэша-версии в имени (как в Части II) и понятного фолбэка на сеть/CDN.
// sw.js — сопоставление кэша с учётом версии сборки и CDN
// Работает в связке с офлайн-кэшем прошлой серии.
// Собираем имя кэша из версии приложения (её инжектит сборщик).
const CACHE = `app-${APP_VERSION}`;
const STATIC = ['/index.html', '/assets/app.7f3a9c.css', '/assets/hero.3b9c11.webp'];
self.addEventListener('install', (event) => {
// Прогреваем ближний кэш статикой; origin/CDN при этом почти не нагружается,
// потому что заголовки immutable гарантируют долгий срок на edge.
event.waitUntil(
caches.open(CACHE).then((cache) => cache.addAll(STATIC))
);
self.skipWaiting();
});
// Убираем старые версии при активации — иначе кэш разрастается.
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) => Promise.all(
keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))
))
);
self.clients.claim();
});
// Сопоставляем запрос с кэшем, игнорируя лишние CDN-параметры,
// и используем stale-while-revalidate для публичного контента.
function normalize(req) {
const url = new URL(req.url);
// Удаляем технические параметры, которые подставляет CDN (?v=, ?sig=...)
url.searchParams.delete('v');
url.searchParams.delete('sig');
return url.href;
}
self.addEventListener('fetch', (event) => {
const req = event.request;
if (req.method !== 'GET') return; // мутации отправляем напрямую
// Статика — cache-first: отдаём из воркера, сеть не трогаем.
if (req.url.includes('/assets/')) {
event.respondWith(
caches.match(req).then((hit) => hit || fetch(req).then((fresh) => {
const copy = fresh.clone();
caches.open(CACHE).then((c) => c.put(req, copy));
return fresh;
}))
);
return;
}
// Публичные данные — stale-while-revalidate: сразу то, что есть,
// и параллельно тихо обновляем через CDN/origin.
event.respondWith(
caches.match(normalize(req)).then((stale) => {
const network = fetch(req).then((fresh) => {
caches.open(CACHE).then((c) => c.put(normalize(req), fresh.clone()));
return fresh;
}).catch(() => stale); // сеть упала — держим старьё
return stale || network;
})
);
});
Здесь важно: normalize чистит CDN-параметры, чтобы воркер не плодил дубликаты одного и того же файла. Статика идёт по cache-first (дорого живёт и на PoP, и в воркере), а данные — по stale-while-revalidate, как мы описали в Часте II. Точное поведение стратегий и фолбэка разобрано в статье про сервис-воркеры.
23. Что синхронизировать, а что нет
- Версию сборки держите в одном месте: если имя файла поменялось (хэш в имени), и edge-кэш, и воркер автоматически возьмут новый URL — инвалидация по имени.
- Инвалидацию контента делайте на edge (purge/бан по URL или тегу), но помните: воркер у тех, кто уже открыл сайт, обновится только при следующем визите или по
skipWaiting. Для срочных изменений контента не рассчитывайте на офлайн-кэш. - Персональные ответы (профиль, корзина, оплата) не кэшируйте ни на edge (
no-store/private), ни в воркере. Их путь — origin, и точка. - Фолбэк офлайна оставьте на воркере: CDN человеку в метро без сети не поможет, а воркер с закэшированной страницей — поможет.
CDN и сервис-воркер — не конкуренты, а два конца одной трубы: сеть доставки ускоряет всех, воркер страхует конкретного человека.
Чек-лист: CDN без самообмана
- Заголовки решают всё. Проверьте
Cache-Controlна статике:public, max-age=31536000, immutable. На HTML — короткий срок илиno-cacheсstale-while-revalidate. Мета-теги в HTML CDN не читают. - Origin shield настроен, а origin закрыт белым списком по IP shield — прямой удар мимо CDN не проходит.
- nginx доверяет
X-Forwarded-Forтолько подсетям CDN (set_real_ip_from), иначе лимиты и логи врут. - geo-routing проверен из нескольких регионов: смотрим
X-Cache/CF-Cache-Statusи код PoP, убеждаемся, что HIT растёт, а задержка падает. - WAF на edge активен, правила блокируют типовые приёмы атак до origin; логи блокировок отправлены в мониторинг (см. логирование и трассировку).
- TLS терминируется на edge, приватный ключ не лежит на каждом сервере.
- Edge-функции короткие и без базы: они читают кэш и запрос, а не выполняют бизнес-логику приложения.
- Воркер синхронизирован по версии сборки: хэш в имени файла автоматически инвалидирует и edge, и Cache API; персональный контент не кэшируется нигде.
- Инвалидация (purge) описана: что и как чистить на CDN при релизе, чтобы пользователи не сидели на вчерашнем JS.
- Балансировка на origin остаётся нужной: CDN снимает сетевую задержку и статический флуд, а живые запросы всё равно принимают ваши серверы (см. балансировку нагрузки).
Итог. Сеть доставки как часть архитектуры
CDN превращает вопрос «как ускорить сервер» в вопрос «как приблизить ответ к человеку». Мы разобрали, как устроены точки присутствия и слои кэширования, что на самом деле значат по-русски директивы Cache-Control, зачем нужен origin shield, чтобы не топило ваш настоящий сервер, как edge-функции и Varnish выполняют логику близко к пользователю, как geo-routing выбирает ближайший узел и чем CDN прикрывает от DDoS и ставит WAF и TLS на входе. И главное — как это всё стыкуется с офлайн-кэшем сервис-воркера, который вы уже построили.
Материал написан простым языком без излишней терминологии. Все примеры основаны на технологиях из предыдущей серии «Веб-разработка без фреймворков» (HTML, CSS, JavaScript, Service Worker) и серии «Архитектура и производительность». Практические советы учитывают специфику проектов на PHP/WordPress и самостоятельного хостинга на VPS. Названия продуктов и заголовков CDN-провайдеров намеренно приведены обобщённо: конкретные имена полей (
X-Cache,CF-Cache-Statusи аналоги) различаются у вендоров, сверяйтесь с документацией своего провайдера.
👤 Зарегистрируйтесь, чтобы добавить материал в закладки.
