За 30 секунд
Когда вы открываете сайт, браузер находит адрес сервера (DNS), открывает к нему соединение (TCP или QUIC), делает его защищённым (TLS), запрашивает страницу (HTTP), а затем превращает ответ в пиксели. Каждый шаг занимает миллисекунды, и на каждом из них сайт может оказаться быстрым или медленным, надёжным или сломанным. Понимание этой цепочки — фундамент для всех остальных тем о вебе.
Почему я это использую
- Я пользуюсь этой ментальной моделью каждый день: когда сайт тормозит или лежит, я прохожу цепочку шаг за шагом, а не гадаю.
- Почти каждый продакшен-баг, с которым я сталкиваюсь, сидит в одном из звеньев этой цепочки: DNS-запись, сертификат, заголовок прокси, кэш или блокирующий рендеринг скрипт.
- Это помогает мне простыми словами объяснить клиентам, почему за CDN, HTTPS или кэширование стоит платить.
- Скорость фронтенда и скорость бэкенда имеют смысл только вместе; этот путь их связывает.
Как это работает
01Общая картина: аналогия с рестораном
Представьте, что открыть сайт — это как сделать заказ в ресторане, где вы никогда не были. Сначала вы узнаёте адрес (DNS). Потом идёте туда и получаете столик (TCP-соединение). Договариваетесь с официантом о «секретном языке», чтобы никто не подслушал (TLS). Делаете заказ по меню (HTTP-запрос). Кухня готовит (сервер выполняет код и обращается к базе данных). Официант приносит блюдо (HTTP-ответ), а вы раскладываете его на столе и начинаете есть (браузер разбирает и отрисовывает страницу). CDN — это филиал ресторана рядом с вашим домом, где популярные блюда уже готовы. Держите эту картинку в голове: каждый шаг ниже — её часть.
- URL: https://example.com/products?page=2 = схема + хост + путь + query-параметры.
- Клиент — браузер или приложение; сервер — машина, которая отвечает.
- Для большинства страниц задержка (время кругового пути, RTT) важнее пропускной способности.
02Шаги 1–3: DNS, TCP и TLS
Браузеру нужен IP-адрес, а не имя. Он проверяет свой кэш, кэш операционной системы, а затем спрашивает рекурсивный резолвер (вашего провайдера, 1.1.1.1 или 8.8.8.8). Резолвер обходит корневые серверы, затем серверы зоны .com, затем авторитативные nameserver'ы домена и кэширует ответ на время его TTL. Получив IP, браузер открывает TCP-соединение на порт 443 через трёхстороннее рукопожатие (SYN, SYN-ACK, ACK). Затем запускается TLS 1.3: браузер и сервер договариваются о ключах, а сервер подтверждает свою личность сертификатом. TLS 1.3 требует одного дополнительного кругового пути; HTTP/3 объединяет транспорт и TLS в одно QUIC-рукопожатие поверх UDP. На мобильном канале с задержкой 100 мс эти круговые пути — это уже 200–300 мс до прихода первого байта HTML, поэтому повторное использование соединений и близкие серверы так важны.
# See each phase of a real request with timings
curl -o /dev/null -s -w "dns: %{time_namelookup}s
tcp: %{time_connect}s
tls: %{time_appconnect}s
first byte: %{time_starttransfer}s
total: %{time_total}s
" https://example.com/
03Шаги 4–6: запрос, сервер, ответ
По защищённому соединению браузер отправляет HTTP-запрос: метод (GET), путь и заголовки — Host, Accept-Language, cookie и подсказки для кэширования. На стороне сервера его принимает веб-сервер вроде nginx. Он может сразу отдать статический файл или передать запрос приложению (Laravel через PHP-FPM, процесс Node.js), которое выполняет бизнес-логику, читает базу данных или кэш и собирает HTML или JSON. Ответ возвращается со статус-кодом (200, 301, 404, 500), заголовками (Content-Type, Cache-Control, Set-Cookie) и телом, обычно сжатым gzip или Brotli. Time to First Byte (TTFB) измеряет весь этот круг: сеть плюс работа сервера. Медленный TTFB обычно означает медленные запросы к базе, отсутствие кэша или сервер, расположенный далеко от пользователя.
GET /products?page=2 HTTP/1.1
Host: example.com
Accept: text/html
Accept-Encoding: br, gzip
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Encoding: br
Cache-Control: public, max-age=60
04Шаг 7: браузер собирает страницу
Браузер читает HTML по мере поступления и строит DOM — дерево элементов. Встретив CSS, он скачивает и разбирает его в CSSOM; CSS блокирует рендеринг, потому что браузер не будет рисовать нестилизованный контент. Классические теги script тоже блокируют разбор, если у них нет defer или async. DOM и CSSOM объединяются в дерево рендеринга, после чего браузер рассчитывает layout (размеры и позиции), рисует пиксели и компонует слои на GPU. Изображения, шрифты и дополнительные скрипты грузятся параллельно. JavaScript может позже изменить DOM, что снова запускает layout. Результат измеряют Core Web Vitals: LCP (как быстро появляется основной контент), INP (как быстро страница реагирует на ввод) и CLS (насколько элементы «прыгают»).
- Подключайте CSS пораньше, скрипты — с defer, а изображениям задавайте width и height.
- Делайте preload для главного изображения и основного шрифта; всё, что ниже первого экрана, грузите лениво.
- Меньше JavaScript почти всегда означает более быструю и отзывчивую страницу.
05Где здесь CDN
CDN (Content Delivery Network) — Cloudflare, Fastly или CloudFront — держит серверы в сотнях городов. Когда ваш DNS указывает на CDN, TLS-рукопожатие посетителя завершается на ближайшем edge-сервере, часто в 10–30 мс вместо 150 мс. Edge сам отдаёт закэшированные файлы (изображения, CSS, JS, иногда целые HTML-страницы) и пересылает на ваш origin-сервер только промахи кэша — по «тёплому», переиспользуемому соединению. Многие CDN также добавляют защиту от DDoS, web application firewall и HTTP/3. Цена — ещё один слой, в котором нужно разбираться: правила кэширования, настройки SSL между edge и origin и то, что ваш сервер теперь видит IP CDN, если не восстановить реальный IP посетителя из заголовка.
06Отладка цепочки на практике
Когда что-то не так, проверяйте каждое звено по порядку, а не гадайте. Резолвится ли имя в правильный IP? Открывается ли TCP-соединение на порт 443? Действителен ли сертификат для этого хоста? Какой статус-код и какие заголовки возвращаются? Медленный ли сервер (высокий TTFB) или браузер (долгое выполнение скриптов или рендеринг в DevTools)? Вкладка Network в браузере показывает время DNS, соединения, TLS, ожидания и загрузки для каждого файла. Вкладка Performance и Lighthouse показывают разбор, layout и отрисовку. На сервере access- и error-логи подскажут, дошёл ли запрос вообще.
dig +short example.com A # 1. DNS
nc -vz example.com 443 # 2. TCP port open?
openssl s_client -connect example.com:443 -servername example.com </dev/null | head -n 20 # 3. TLS
curl -sI https://example.com/ # 4. status + headers
sudo tail -f /var/log/nginx/access.log # 5. did it reach the server?
Когда применять
- Диагностика, почему сайт лежит, тормозит или показывает ошибку сертификата.
- Планирование нового деплоя: выбор DNS, CDN, TLS и сервера вытекает из этой цепочки.
- Объяснение работы над производительностью (CDN, кэширование, оптимизация изображений) нетехническим людям.
- Подготовка к собеседованиям: «что происходит, когда вы вводите URL» — классический вопрос.
Когда не стоит
- Чтобы сделать сайт, не нужно заучивать каждый TCP-флаг; углубляйтесь настолько, насколько требует возникшая проблема.
- Не оптимизируйте сетевые круговые пути, пока не исправлены очевидные проблемы сервера, например медленные запросы к базе.
Альтернативы
- Нативные приложения
Обходятся без рендеринга HTML, но всё равно используют DNS, TLS и HTTP для общения с API.
- WebSockets / SSE
Держат одно открытое соединение для обновлений в реальном времени вместо запроса–ответа на каждое изменение.
- Статический хостинг на CDN
Убирает сервер приложения из цепочки для страниц, которые редко меняются.
Лучшие практики
- Отдавайте всё по HTTPS с включёнными HTTP/2 или HTTP/3.
- Ставьте CDN перед публичными сайтами и кэшируйте статику надолго, с версионированием имён файлов.
- Держите TTFB низким: кэшируйте горячие данные, добавляйте индексы для запросов к базе, размещайте серверы ближе к пользователям.
- Отправляйте меньше JavaScript; откладывайте некритичные скрипты и избегайте ресурсов, блокирующих рендеринг.
- Сжимайте текстовые ответы Brotli или gzip и отдавайте изображения в современных форматах (WebP, AVIF).
- Измеряйте по данным реальных пользователей (Core Web Vitals), а не только на быстром ноутбуке в офисном Wi-Fi.
Частые ошибки
- Винить «сервер», не проверив сначала DNS, сертификаты или браузер.
- Подключать большие блокирующие скрипты в head, задерживая первую отрисовку.
- Забывать, что CDN или прокси скрывают реальный IP посетителя от логов и rate limit'ов.
- Отдавать на мобильные телефоны изображения в полном разрешении камеры.
Глубже
07Почему важны первые 14 KB: TCP slow start
Новое TCP- или QUIC-соединение не знает, насколько быстрый канал, поэтому начинает осторожно. Отправитель может держать «в полёте» всего около десяти пакетов (начальное окно перегрузки, примерно 14 KB), после чего должен ждать подтверждений, а затем удваивает этот объём на каждом round trip, пока ничего не теряется. Поэтому HTML-документ на 100 KB на свежем соединении требует нескольких round trip, а не одного, даже на быстром канале. Вот почему inline-критичный CSS и небольшой верх HTML ускоряют первую отрисовку и почему переиспользуемые, уже «прогретые» соединения ощущаются намного быстрее. Потеря пакетов заставляет отправителя снова уменьшить окно, поэтому мобильные сети с потерями вредят сильнее, чем подсказывают цифры пропускной способности. Современные алгоритмы управления перегрузкой, например BBR, лучше реагируют на потери, чем старые, но физика round trip никуда не девается.
- Небольшой HTML, отрендеренный на сервере, с критичным CSS отрисовывается раньше.
- Переиспользование соединений (keep-alive, мультиплексирование HTTP/2) позволяет следующим запросам пропустить slow start.
- Каждый дополнительный origin — это новый DNS-запрос, handshake и «холодное» окно.
08Как браузер решает, что загружать первым
Браузеры загружают ресурсы не в порядке их появления на странице. Пока основной парсер заблокирован скриптом, preload scanner читает сырой HTML наперёд и начинает загружать найденные изображения, стили и скрипты. Каждый запрос получает приоритет: CSS и блокирующие скрипты — высокий, изображения во viewport повышаются после layout, async-скрипты и изображения ниже первого экрана — низкий. Этим можно управлять. rel=preload загружает то, что сканер не видит, например шрифт, на который ссылается только CSS. fetchpriority=high помечает LCP-изображение как важное. 103 Early Hints позволяет серверу или CDN отправить preload-ссылки ещё до готовности HTML, используя время, пока сервер «думает». Ловушка — злоупотребление: если всё высокоприоритетное, значит, ничего, а preload неиспользуемых файлов тратит пропускную способность на критическом пути.
<!-- In the <head>: help the browser find critical files early -->
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>
<img src="/img/hero.avif" width="1200" height="630" fetchpriority="high" alt="Product hero">
<img src="/img/footer.webp" width="400" height="300" loading="lazy" alt="Team photo">
<script src="/js/app.3f9a1c.js" defer></script>
09Слои кэша между пользователем и базой данных
На запрос можно ответить на многих уровнях, и каждый дешевле следующего. В браузере: back/forward cache держит целые страницы в памяти для мгновенного перехода назад; memory и HTTP disk cache хранят файлы согласно Cache-Control; service worker может отвечать из собственного кэша, даже офлайн. Дальше — edge CDN, иногда с региональным уровнем перед origin. На origin reverse proxy вроде nginx может кэшировать целые ответы (microcaching на несколько секунд гасит всплески трафика). Внутри приложения Redis или in-memory кэш хранят вычисленные данные, а у базы есть свой buffer pool. Инженерный вопрос всегда один: где этот ответ можно безопасно переиспользовать, для кого и как долго? Персонализированные данные могут жить только в кэшах с ключом, привязанным к конкретному пользователю.
10Доверие по всей цепочке: что можно подделать
Каждый шаг чему-то доверяет. Обычные DNS-ответы можно подделать во враждебной сети, поэтому существует DNSSEC, а зашифрованный DNS (DNS over HTTPS или TLS) скрывает запросы от локальной сети. Но настоящая защита — это TLS: даже если DNS отправит вас на чужой IP, атакующий не сможет предъявить валидный сертификат для example.com, и браузер остановится. HSTS убирает первый незащищённый запрос по http://, который атакующий мог бы перехватить. Внутри браузера same-origin policy не даёт одному сайту читать данные другого, cookie с SameSite ограничивают межсайтовые запросы, а Content-Security-Policy ограничивает, какие скрипты могут выполняться. На стороне сервера всё в запросе (заголовки, cookie, X-Forwarded-For) — это пользовательский ввод, пока за него не поручился доверенный прокси.
Реальные ситуации
В офисе быстро, у пользователей за рубежом медленно
Проблема
Для команды рядом с дата-центром сайт открывается мгновенно, но пользователи с другого континента жалуются на загрузку в три-четыре секунды. Метрики сервера в норме.
Как решить
Измеряйте оттуда, где находятся пользователи: запустите curl с таймингами с удалённого VPS или мультирегиональным тестом и сравните DNS, connect, TLS и TTFB. Если connect и TLS занимают около 150 ms каждый, проблема в расстоянии, а не в коде. Поставьте CDN, чтобы handshake завершались на ближайшем edge, кэшируйте статику с долгими сроками и версионированными именами, а если страницы публичные — ненадолго кэшируйте HTML на edge. Включите HTTP/2 и HTTP/3, уберите лишние сторонние origin и сократите цепочки редиректов. Затем проверьте Core Web Vitals реальных пользователей по странам, чтобы подтвердить улучшение.
TTFB хороший, но LCP больше четырёх секунд
Проблема
HTML приходит за 200 ms, но на мобильных главное изображение появляется поздно. Lighthouse указывает, что LCP-элемент — большое hero-изображение.
Как решить
Задержка в браузере, так что смотрите waterfall. Типичные причины: hero-изображение задано как CSS background или вставляется JavaScript, и preload scanner его не находит; оно по ошибке lazy-load; это JPEG на 3 MB. Исправление: обычный тег img с width и height, fetchpriority=high и без loading=lazy, AVIF или WebP нужного размера через srcset и preconnect к image CDN. Блокирующие рендеринг скрипты переведите на defer. Перепроверьте на мобильном профиле с троттлингом и через несколько дней посмотрите полевые данные.
После миграции часть пользователей всё ещё видит старый сервер
Проблема
A-запись переключили на новый сервер час назад. Большая часть трафика переехала, но несколько клиентов всё ещё видят старый сайт и старые данные.
Как решить
Это закэшированный DNS, а не сломанный деплой. Проверьте, какой TTL был у старой записи: резолверы могут держать её до истечения, а некоторые клиенты кэшируют дольше. Подтвердите авторитетный ответ через dig к nameserver и сравните с публичными резолверами. Не выключайте старый сервер: либо переведите его в read-only с баннером, либо проксируйте его трафик на новый сервер, чтобы записи не разъехались по двум базам. В следующий раз снизьте TTL до 300 секунд за день до переезда. Когда access-логи старого сервера затихнут, выводите его из эксплуатации.
Шпаргалка
- Замерить каждую фазу запроса
curl -o /dev/null -s -w "%{time_namelookup} %{time_connect} %{time_appconnect} %{time_starttransfer} %{time_total}\n" https://example.com/- Разрешить имя через публичный резолвер
dig +short example.com A @1.1.1.1- Проверить, открыт ли TCP-порт
nc -vz example.com 443- Посмотреть сертификат и версию TLS
openssl s_client -connect example.com:443 -servername example.com -brief </dev/null- Только заголовки
curl -sI https://example.com/- Обратиться к конкретному серверу в обход DNS
curl -sI https://example.com/ --resolve example.com:443:203.0.113.10- Трассировка сетевого пути и потерь пакетов
mtr -rwc 50 example.com- Лабораторный аудит производительности
npx lighthouse https://example.com --view- Сделать LCP-изображение приоритетным
<img src="/hero.avif" fetchpriority="high" width="1200" height="630" alt="">
В моих реальных проектах
- Я держу в продакшене сайты на Laravel и Next.js на серверах Ubuntu с nginx перед ними и прохожу эту цепочку при разборе инцидентов.
- На сайтах, которыми я управляю, перед серверами стоит Cloudflare для DNS и базовой защиты от DDoS, везде HTTPS и автоматически продлеваемые сертификаты.
- Я читаю серверные логи, чтобы отследить продакшен-проблему до конкретного запроса, — так были найдены баг в middleware локализации и баг конвертации изображений в WebP.
Вопросы и ответы
Q1Что происходит, когда вы вводите URL и нажимаете Enter?
Браузер разбирает URL и проверяет кэши. Если IP нет, он резолвит имя через рекурсивный резолвер, который обходит корневые, TLD- и авторитативные nameserver'ы. Браузер открывает TCP-соединение на порт 443 и проводит TLS-рукопожатие, проверяя сертификат. Затем отправляет HTTP-запрос с заголовками и cookie. Сервер — часто nginx перед приложением — выполняет код, может обратиться к базе данных и возвращает статус, заголовки и тело. Браузер разбирает HTML в DOM, CSS в CSSOM, выполняет скрипты, рассчитывает layout, рисует и компонует слои. CDN может ответить прямо с edge, вообще не обращаясь к origin.
Q2Что такое TTFB и как его улучшить?
Time to First Byte — это время от отправки запроса до получения первого байта ответа. Оно включает DNS, установку соединения и TLS, сетевую задержку и время обработки на сервере. Чтобы его улучшить, я сначала смотрю на серверное время: медленные запросы, отсутствующие индексы, N+1, отсутствие кэша приложения. Затем — на расстояние: CDN или edge-кэш приближают контент к пользователю и переиспользуют тёплые соединения с origin. HTTP/2 или HTTP/3 и keep-alive сокращают затраты на рукопожатия. Для страниц, которые редко меняются, кэширование полного HTML на edge может снизить TTFB с сотен миллисекунд до нескольких десятков.
Q3Что такое критический путь рендеринга?
Это последовательность, которую браузер должен пройти, прежде чем что-то нарисовать: скачать и разобрать HTML в DOM, скачать и разобрать CSS в CSSOM, выполнить блокирующие скрипты, объединить всё в дерево рендеринга, рассчитать layout и отрисовать. Всё, что его блокирует, откладывает первую содержательную отрисовку. CSS блокирует рендеринг, классические скрипты блокируют разбор. Чтобы его сократить, я инлайню или приоритизирую критический CSS, добавляю скриптам defer, делаю preload главного изображения и основного шрифта и избегаю больших клиентских бандлов. Цель — чтобы самый крупный видимый элемент появился быстро; именно это и измеряет LCP.
Q4Почему CDN ускоряет сайт и какие у него риски?
Основная задержка в вебе — это круговые пути, а не пропускная способность. CDN завершает TCP и TLS на edge-сервере рядом с посетителем, поэтому рукопожатия занимают несколько миллисекунд вместо долгого межконтинентального пути. Закэшированные ресурсы отдаются с edge, а промахи идут на origin по тёплым переиспользуемым соединениям. Риски связаны с конфигурацией: случайное кэширование приватных или персонализированных страниц, неправильный режим SSL между edge и origin, потеря реального IP клиента в логах и rate limiting, устаревший контент после деплоя. Чёткие правила кэширования, версионированные имена файлов и шаг очистки кэша в деплое решают большую часть этих проблем.
Q5Чем TCP отличается от UDP и почему веб теперь использует оба?
TCP даёт надёжный упорядоченный поток байтов: он повторно отправляет потерянные пакеты и доставляет данные по порядку ценой рукопожатия и head-of-line blocking при потере пакета. UDP просто отправляет датаграммы без гарантий порядка и доставки, поэтому он легче. HTTP/1.1 и HTTP/2 работают поверх TCP. HTTP/3 работает поверх QUIC, который построен на UDP, но добавляет собственную надёжность, шифрование и независимые потоки в пользовательском пространстве. Благодаря этому один потерянный пакет задерживает только свой поток, а транспортное и TLS-рукопожатия объединяются, что очень помогает в мобильных сетях.
Вопросы уровня senior
S1Как бы вы спроектировали систему для глобальной аудитории с одним origin-сервером?
Я бы оставил один origin, который просто обслуживать, и вынес как можно больше на edge. Статика получает имена с хэшем и кэширование на год в CDN. Публичный HTML кэшируется на edge от секунд до минут со stale-while-revalidate и сбрасывается при публикации. Персонализированные части загружаются небольшими API-запросами, или страница разделяется так, чтобы shell был кэшируемым. Tiered cache ещё сильнее снижает число обращений к origin. Записи всё равно идут на origin, поэтому я делаю API-ответы небольшими и идемпотентными для безопасных повторов. Цена — сложность инвалидации кэша и eventual consistency контента. Мультирегиональные origin окупаются только тогда, когда требования к задержке записи или доступности оправдывают гораздо более сложную репликацию данных.
S2Куда вы посмотрите первым делом, если p95 latency выросла вдвое, а p50 не изменилась?
Стабильная медиана при ухудшившемся «хвосте» обычно означает, что часть запросов попадает на медленный путь, а не что замедлилось всё. Я разбиваю по измерениям: маршрут, регион, устройство, статус кэша и upstream. Частые причины: промахи кэша после деплоя или purge, конкретный запрос, потерявший индекс, конкуренция за блокировки, garbage collection или исчерпанный пул воркеров, из-за чего запросы встают в очередь, медленный сторонний вызов без таймаута или потери пакетов в одной сети. На сервере я сравниваю upstream response time с общим временем запроса в логах nginx, чтобы отделить ожидание в очереди от работы. Трейсинг с request ID показывает, где именно лишнее время. Исправление зависит от причины, но типичны таймауты, правильный размер пулов и кэширование медленного пути.
S3SSR, статическая генерация или SPA с рендерингом на клиенте: как они меняют цепочку?
Статическая генерация создаёт HTML во время сборки, поэтому CDN может отвечать на всё, а TTFB минимален; цена — пересборки или ревалидация при изменении контента. Server-side rendering строит HTML на каждый запрос, давая свежий персонализированный контент и хороший LCP, но TTFB зависит от скорости сервера и данных, поэтому важны кэширование и стриминг. SPA с клиентским рендерингом отдаёт маленький HTML-shell и большой JavaScript-бандл; первая отрисовка реального контента ждёт загрузки, парсинга, выполнения и API-запросов, что на медленных устройствах бьёт по LCP и SEO, зато дальнейшая навигация быстрая. Современные фреймворки смешивают подходы по маршрутам: статика для маркетинговых страниц, SSR или стриминг для динамических и клиентские компоненты только там, где нужна интерактивность.
Глоссарий
- RTT
- Round-trip time: сколько времени пакет идёт до сервера и обратно. Большая часть задержек в вебе измеряется в RTT.
- TTFB
- Time to First Byte: время от отправки запроса до получения первого байта ответа.
- DOM
- Document Object Model: дерево элементов, которое браузер строит из HTML и которое JavaScript может читать и менять.
- CSSOM
- Разобранная браузером модель всех CSS-правил; вместе с DOM определяет, как всё выглядит.
- LCP
- Largest Contentful Paint: момент, когда самый большой видимый элемент, часто hero-изображение или заголовок, дорисован. Хорошо — меньше 2.5 s.
- INP
- Interaction to Next Paint: насколько быстро страница визуально реагирует на клики, тапы и нажатия клавиш. Хорошо — меньше 200 ms.
- CLS
- Cumulative Layout Shift: насколько видимый контент неожиданно «прыгает» при загрузке. Хорошо — меньше 0.1.
- Origin
- Ваш собственный сервер за CDN; в безопасности браузера — также scheme + host + port URL.
- Edge
- Сервер CDN рядом с посетителем, который завершает соединения и отдаёт закэшированный контент.
- Preload scanner
- Вспомогательный парсер браузера, который читает HTML наперёд, чтобы раньше начать загрузку ресурсов.
Что изучить дальше
Есть идея продукта?Давайте создадим его.
Расскажите о своей идее, продукте или команде. Обычно отвечаю в течение одного рабочего дня.