Как TCP обеспечивает надёжную доставку и не перегружает сеть?
- Что такое окно TCP?
- Как работает slow start?
- Чем flow control отличается от congestion control?
Каждый байт пронумерован, получатель подтверждает принятое (ACK), неподтверждённое отправляется повторно — по таймауту или по трём повторным ACK.
- Flow control: окно получателя — сколько он готов принять
- Congestion control: окно перегрузки — сколько сеть, по оценке отправителя, выдержит
- Slow start удваивает окно каждый RTT до первой потери, дальше рост линейный
А ещё Пропускная способность одного соединения ≈ окно / RTT
Подробно
Подтверждения и повторы. Отправитель нумерует байты, получатель шлёт ACK с номером следующего ожидаемого байта (кумулятивное подтверждение; SACK позволяет сообщить и о кусках после дыры). Если ACK не пришёл за время RTO (оценивается по измеренному RTT), сегмент отправляется снова. Быстрее — fast retransmit: три одинаковых ACK значат, что сегмент потерялся, а следующие дошли.
Окно. Ждать ACK на каждый сегмент было бы медленно, поэтому отправитель держит «в полёте» до окна байт без подтверждения. Окно — минимум из двух:
- окно получателя (rwnd) — свободное место в его буфере; приходит в каждом ACK. Это flow control: медленный читатель уменьшает окно до нуля, и отправитель останавливается. Пример backpressure прямо в протоколе;
- окно перегрузки (cwnd) — оценка отправителя, сколько выдержит сеть. Это congestion control.
Как растёт cwnd (классический Reno/CUBIC):
- slow start — начинаем с ~10 сегментов и удваиваем окно каждый RTT, пока не случится потеря или не дойдём до порога;
- избегание перегрузки — дальше рост медленный (линейный у Reno, кубическая функция у CUBIC — по умолчанию в Linux);
- потеря считается сигналом перегрузки: окно уменьшается (вдвое при тройном ACK, до минимума при таймауте).
BBR (Google) не ждёт потерь, а измеряет пропускную способность и минимальный RTT канала и держит в полёте их произведение. Лучше работает на каналах с потерями не от перегрузки (мобильные, дальние линии).
Следствия для практики:
- скорость одного соединения ограничена ≈ окно / RTT — на дальних линиях с большим RTT нужно большое окно (масштабирование окна в заголовке);
- новое соединение стартует медленно — ещё одна причина держать соединения открытыми (keep-alive, пулы);
- потеря пакета тормозит весь поток — блокировка начала очереди, от которой уходит QUIC;
- алгоритм Нейгла копит мелкие записи; для интерактивных протоколов его отключают
TCP_NODELAY.
Пример
RTT = 50 мс, окно = 64 КБ: 64 КБ / 0,05 с ≈ 1,3 МБ/с ≈ 10 Мбит/с — даже на гигабитном канале
окно = 4 МБ: 4 МБ / 0,05 с = 80 МБ/с ≈ 640 Мбит/сЧто хотят услышать
- Нумерация, ACK, повтор по таймауту и по тройному ACK.
- Окно и разница flow control и congestion control.
- Slow start и реакция на потерю.
- Связь окна, RTT и скорости; BBR — плюс.
Частые ошибки
- Путать окно получателя и окно перегрузки.
- Считать, что slow start — «медленный» рост; он экспоненциальный.
Проверьте себя
Несколько верных вариантов. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✓Нумерация байтов, подтверждения и повторная передача
- ✓Окно получателя (flow control)
- ✓Окно перегрузки и slow start (congestion control)
- ✗Отправка каждого пакета дважды на всякий случай
Разбор темы
- TCP изнутри — рукопожатие, надёжность и перегрузка
Как устанавливается и закрывается соединение, откуда TIME_WAIT, как TCP гарантирует доставку и не перегружает сеть, что добавляет TLS.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.