Що таке CDN і навіщо воно потрібне?
CDN (Content Delivery Network) - це глобальна мережа проксі-серверів, яка кешує статичні ресурси і роздає їх з точок, найближчих до користувача.
Теорія
TL;DR
- CDN - як мережа піцерій: місцева точка видає піцу з готового тіста (кеш), а не чекає поставки від центрального складу з іншого кінця країни
- Скорочує затримку з 200-500ms до 20-100ms, направляючи запити до найближчого Point of Presence (PoP)
- Знімає 70-95% статичного трафіку з основного сервера
- Варто додавати при глобальній аудиторії або коли статичні файли (зображення, JS, CSS) складають більшу частину трафіку
Швидкий приклад
<!-- Без CDN: кожен запит іде на твій єдиний сервер -->
<link rel="stylesheet" href="/styles.css">
<!-- Користувач у США при сервері в ЄС: ~400ms затримки -->
<!-- З CDN: найближчий edge-сервер роздає закешовану копію -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<!-- Затримка: ~50ms, файл закешований глобально -->Відкрий вкладку Network в DevTools. Запит через CDN покаже малий TTFB (Time to First Byte). Запит до origin - великий. Це і є та різниця, яку CDN усуває.
Головна різниця
Без CDN кожен запит до ресурсу потрапляє на твій єдиний origin-сервер, незалежно від того, де знаходиться користувач. Людина в Токіо, яка завантажує файл із сервера у Франкфурті, чекає 300-500ms до появи першого байта. CDN перехоплює цей запит на токійському edge-сервері й роздає закешовану копію за 20-50ms. Origin підключається лише при першому запиті до файлу або після закінчення TTL.
Коли використовувати CDN
- Глобальна аудиторія з користувачами в різних країнах: CDN скорочує географічну затримку на 50-80%
- Сайт із важкими статичними ресурсами (зображення, JS-бандли, шрифти складають більшість трафіку): CDN
- Пікові навантаження навколо запусків продукту або розпродажів: CDN поглинає трафік без падіння сервера
- Локальний прототип або внутрішній інструмент для кількох людей: достатньо звичайного хостингу
- Суто динамічний API без кешованих відповідей: CDN тут не допоможе
Як CDN працює зсередини
Браузер резолвить CDN-хостнейм через anycast DNS до найближчого PoP. Edge-сервер перевіряє кеш (за TTL, наприклад Cache-Control: max-age=3600 для JS-файлів). Є в кеші - роздає одразу з диска або пам'яті. Немає - запитує origin, зберігає копію, потім роздає.
Ця pull-модель стоїть за замовчуванням у CloudFront і Cloudflare. Такі провайдери, як Akamai, запускають Varnish-подібні проксі з LRU-витісненням на цих вузлах. Ключовий момент: заголовки Cache-Control у відповіді твого origin-сервера визначають, як довго CDN тримає файл.
Типові помилки
Немає заголовків Cache-Control. Якщо origin не надсилає заголовки кешування, CDN вважає кожен файл некешованим і пересилає всі запити на origin. Нуль користі.
// Неправильно: без заголовків CDN не може нічого кешувати
app.use('/static', express.static('public'));
// Правильно: кажемо CDN тримати файли рік
app.use('/static', express.static('public', {
maxAge: '1y',
immutable: true
}));Забули про інвалідацію кешу після деплою. Ти задеплоїв новий app.js, але назва файлу та сама. CDN роздає стару версію до закінчення TTL, іноді кілька днів. Рішення: хеш у назві файлу (app.abc123.js). Vite і Webpack роблять це автоматично.
Кешування динамічного або персоналізованого контенту. Cache-Control: public, max-age=3600 на маршруті /api/user/profile означає, що CDN закешує дані одного користувача і роздасть їх усім іншим. Для персональних даних - тільки Cache-Control: private, no-cache.
Де використовується на практиці
- React/Vite: production-збірка виводить
dist/assets/index-[hash].js, завантажується на CDN з immutable-заголовками кешу - Next.js: Edge Network від Vercel автоматично кешує все з
_next/static - Express: Cloudflare перед папкою
public/, плюс заголовки кешу на статичних відповідях - Netflix: власна CDN під назвою Open Connect доставляє 99% відеотрафіку через обладнання, вбудоване прямо в мережі провайдерів
Follow-up питання
Q: Як DNS-резолвінг працює в CDN?
A: CDN-провайдери використовують anycast-маршрутизацію. Одна IP-адреса оголошується з сотень локацій по всьому світу, і DNS веде до найближчої. cdn.cloudflare.com може резолвитись у Франкфурті для берлінського користувача і в Далласі для користувача з Х'юстона.
Q: Яка різниця між push і pull CDN?
A: Pull CDN (за замовчуванням у CloudFront і Cloudflare) сам забирає контент з origin при першому промаху кешу і зберігає копію. Push CDN вимагає попередньо завантажити контент до того, як прийдуть запити. Push підходить для великих файлів, як-от відеоманіфести, коли ти вже знаєш, що попит буде.
Q: Як керувати інвалідацією кешу в масштабі?
A: Стандартний підхід - інвалідація за шляхом (/images/*) через API CDN. Повне скидання кешу - крайній захід, бо спричиняє хвилю запитів до origin. Краще проєктувати систему так, щоб інвалідація була не потрібна: хеш у назвах файлів означає, що URL змінюється з кожним деплоєм, а старі записи в CDN стають недосяжними самі по собі.
Q: Коли CDN погіршує продуктивність?
A: Перший запит після промаху кешу (cold start) додає затримку, бо edge мусить звернутись до origin. Надмірне кешування динамічного контенту призводить до застарілих даних. Петлі редиректів трапляються, коли CDN і origin по черзі намагаються перенаправити один і той самий URL один до одного.
Приклади
Підключення Bootstrap через CDN
Найпростіший кейс: завантаження бібліотеки з публічного CDN замість самостійного хостингу.
<!DOCTYPE html>
<html>
<head>
<!-- Роздається з найближчого jsDelivr PoP, закешовано глобально -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
/>
</head>
<body>
<button class="btn btn-primary">Натисни</button>
</body>
</html>Файл вже закешований на edge-серверах jsDelivr по всьому світу. Користувач у Токіо отримує його з токійського PoP. Користувач у Бразилії - з місцевого. Твій сервер у цьому не бере участі взагалі.
Інвалідація кешу в Express і CloudFront
Тут більшість джунів стикаються з реальним багом. Ти оновлюєш файл на S3, але користувачі годинами бачать стару версію.
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const { CloudFrontClient, CreateInvalidationCommand } = require('@aws-sdk/client-cloudfront');
const s3 = new S3Client({ region: 'us-east-1' });
const cf = new CloudFrontClient({ region: 'us-east-1' });
app.post('/update-image', async (req, res) => {
// Завантажуємо новий файл на S3
await s3.send(new PutObjectCommand({
Bucket: 'myapp-assets',
Key: 'img.jpg',
Body: req.body
}));
// Інвалідуємо кеш CDN, щоб користувачі отримали нову версію
await cf.send(new CreateInvalidationCommand({
DistributionId: 'E123ABC',
InvalidationBatch: {
Paths: { Quantity: 1, Items: ['/img.jpg'] },
CallerReference: Date.now().toString()
}
}));
res.json({ ok: true });
});Без виклику інвалідації користувачі бачать старий img.jpg до 24 годин (дефолтний TTL CloudFront). З ним кеш очищається за менш ніж 5 хвилин. Цей баг я бачив у продакшені мінімум тричі в командах, що вперше будували щось на S3 і CloudFront.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.