EnglishРусский Map

Управление перегрузкой в TCP

title
Управление перегрузкой в TCP
type
concept
summary
Как TCP ограничивает скорость отправки для защиты сети от коллапса, и почему первый RTT вмещает ~13 КБ
tags
networking, tcp, web-performance
created
2026-04-06
updated
2026-07-22
lang
ru
source_updated
2026-07-22
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

Механизм TCP для предотвращения сетевого коллапса за счёт ограничения скорости отправки данных. Без него потеря пакетов приводит к повторным отправкам, которые вызывают ещё большие потери, - петля обратной связи, положившая ранний интернет в 1986 году.

Как это работает

Отправитель поддерживает окно перегрузки (congestion window, cwnd) - число неподтверждённых пакетов, которым разрешено находиться в пути (in flight). Это косвенно ограничивает пропускную способность, задавая объём данных, передаваемый за один round trip.

Новыми соединениями управляет медленный старт (slow start). Окно начинается с 10 пакетов (согласно RFC 6928) и удваивается каждый RTT: каждый ACK увеличивает окно на единицу, а за один круговой оборот приходит пачка подтверждений на всё окно. Десять пакетов с типичным полезным объёмом ~1368 байт дают около 13 КБ в первом RTT. Разбор на конкретном примере см. в 13kb-tcp-slow-start.

Предотвращение перегрузки (congestion avoidance) включается при первых признаках потерь. Окно растёт линейно (+1 пакет за RTT), а не экспоненциально, зондируя пропускную способность без риска резко перегрузить сеть.

Медленный старт вместе с предотвращением перегрузки представляют собой регулятор с обратной связью: измеряем сигнал ошибки (потери), меняем управляющее воздействие (размер окна), повторяем и рассчитываем, что контур стабилизируется, а не уйдёт в раскачку. Книга Джанерта feedback-control-for-computer-systems раскладывает эту схему по деталям и даёт условия устойчивости - ровно то, что нужно, когда пишешь собственный цикл управления для автоскейлера или rate limiter'а.

Способ обнаружения потерь

Реакция зависит от того, как именно обнаружена потеря:

  • Дублирующиеся ACK - получатель всё ещё принимает пакеты, просто не тот, который ожидал. Окно уполовинивается, и продолжается предотвращение перегрузки. Это режим "быстрой повторной передачи" (fast retransmit).
  • Таймаут - в ответ не пришло ничего. Возможно, сеть всё ещё забита пакетами отправителя. Окно сбрасывается до 1, и медленный старт запускается заново до половины размера окна, предшествовавшего потере ("порог медленного старта", slow start threshold).

Разница отражает степень неопределённости: дублирующиеся ACK означают, что данные идут, а таймаут - что они, возможно, перестали проходить.

Почему это важно для веба

Поскольку медленный старт ограничивает первый RTT объёмом ~13 КБ, производительность сайта сильно зависит от того, что помещается в этот начальный всплеск. Критический CSS и JavaScript стоит встраивать прямо в страницу (inline) или делать достаточно компактными, чтобы они укладывались в первую отправку. Часто упоминаемый "бюджет в 14.2 КБ" приблизителен: реальный размер меняется в зависимости от MTU, VLAN, HTTP-заголовков, накладных расходов TLS и сжатия.

Внутреннее устройство таймеров TCP

Для управления жизненным циклом соединений TCP полагается на внутренние таймеры ядра - не только для контроля перегрузки, но и для истечения TIME_WAIT, таймаутов повторной отправки и keepalive-проб. В macOS эти таймеры завязаны на один счётчик uint32_t (tcp_now), который переполняется через 49.7 дней аптайма, замораживая системные часы TCP и ломая сборку мусора для TIME_WAIT. Полный разбор см. в macos-tcp-time-bomb.