Кратко

  • PRR после каждого ACK вычисляет точное число разрешённых к отправке байтов и плавно ведёт фактический объём данных в сети к ssthresh, выбранному отдельным алгоритмом управления перегрузкой.
  • ACK подтверждает узкий факт продвижения доставки, а не здоровье всего пути; эксплуатационное доказательство должно раздельно хранить выбор цели, ветвь PRR, реальную отправку, pacing и измеренный результат.

Правильная точка назначения не оправдывает путь

Пусть в сети находилось двадцать сегментов, когда потеря заставила алгоритм управления перегрузкой выбрать десять целью восстановления. Старый механизм может сразу уменьшить окно, ждать снижения оценки объёма в сети, а затем отправить несколько сегментов вместе. В примере RFC 9937 это названо половиной окна молчания. Резкий скачок оценки pipe способен породить противоположную крайность — внезапное большое разрешение и всплеск.

PRR занимается не только конечной десяткой. Он распределяет добровольное сокращение окна по возвращающимся подтверждениям. После каждого ACK отправитель заново определяет, сколько можно выпустить. Одинаковое количество данных приобретает другую форму во времени.

В статье 2011 года Nandita Dukkipati, Matt Mathis, Yuchung Cheng и Monia Ghobadi исследовали короткие потоки, остановки приложения, пакетные потери, потерю и перестановку ACK, а также stretch ACK. Прежние механизмы могли чрезмерно сокращать окно или создавать крупные всплески. В изученной выборке PRR вместе с работой по ранней повторной передаче снизил задержку TCP-соединений, столкнувшихся с потерями, на 3–10% в зависимости от размера ответа. Это результат конкретного измерения, не универсальный прогноз.

В 2013 году вышел экспериментальный RFC 6937 за авторством Mathis, Dukkipati и Cheng. В декабре 2025 года его заменил RFC 9937 на стандартизационном треке, подготовленный Mathis, Neal Cardwell, Cheng и Dukkipati. Эта цепочка связывает Dukkipati с исходным измерительным вопросом, экспериментом и пересмотренной спецификацией. Она не подтверждает единоличное изобретение или контроль над каждой реализацией.

Цель, наблюдение и разрешение принадлежат разным модулям

Сначала алгоритм управления перегрузкой выбирает ssthresh — желаемый объём данных в сети к концу эпизода. Это делает Reno, CUBIC или другой совместимый контроллер. PRR не определяет самостоятельно тяжесть перегрузки и не создаёт цель.

Затем логика восстановления читает ACK. DeliveredData — лучшая оценка отправителя того, сколько байтов текущее подтверждение считает доставленными со времени предыдущего. Слова «лучшая оценка» задают предел: это не полное описание прямого и обратного пути, причины потери или состояния приложения.

После этого PRR вычисляет SndCnt, точное число байтов, разрешённых в ответ. Отдельная функция решает, будут ли это повторно передаваемые или новые данные. PRR управляет объёмом и моментом, но не выбирает содержимое.

Так выглядит минимальная спецификация без расплывчатости. Общий расчёт детерминирован и проверяется локально. Решения, которым нужно другое состояние, остаются у соответствующих компонентов. Прибывший ACK не получает власть над всей системой.

Квитанция о доставке задаёт такт выпуска

В начале отправитель сохраняет RecoverFS, оценку исходного объёма в полёте, который может быть доставлен в эпизоде. prr_delivered накапливает подтверждённый прогресс, а prr_out — отправленное во время восстановления.

Пока inflight выше ssthresh, пропорциональный расчёт определяет, сколько уже следовало выпустить с учётом доставленной доли и уменьшенной цели. Из результата вычитается prr_out, и получается очередной SndCnt.

ACK здесь не медицинское заключение о маршруте, а квитанция, открывающая ограниченный кредит. Малый прогресс разрешает малую отправку. Если промежуточные ACK потеряны, последующий может отразить больше накопленной доставки; расчёт догоняет её, не превращая скачок оценки в безлимитный всплеск.

Доверие намеренно узкое. ACK способен запустить одну соразмерную операцию. Он не выбирает ssthresh, не объясняет потерю и не удостоверяет восстановление пути.

Ниже цели осторожность переключается по фактам

Тяжёлая потеря может опустить inflight ниже ssthresh. Абсолютная консервативность затягивает восстановление, а безусловное заполнение свободного места создаёт новую потерю. RFC 9937 использует две границы сокращения.

По умолчанию Conservative Reduction Bound тесно привязывает отправку к доставленным данным. Если SafeACK истинно, Slow Start Reduction Bound может добавить не более одного максимального сегмента отправителя. ACK должен продвинуть накопительное подтверждение и не сообщить о новой потере.

Версия 2025 года сделала выбор адаптивным после выявления сложного случая с token-bucket policer. При исчерпании токенов устройство может внезапно начать массовое отбрасывание, не показывая конечной системе скорость пополнения. Цель, основанная на прежней производительности пути, оказывается слишком высокой. Поэтому алгоритм начинает с консервативной ветви и разрешает дополнительный шаг лишь при заданном признаке прогресса.

Название SafeACK нельзя расширять. Оно не означает безопасный путь; только выполнение двух условий для ограниченной прибавки в этой ветви.

Завершение всё ещё нуждается в pacing

Каждая передача увеличивает prr_out. В конце PRR устанавливает cwnd равным ssthresh. Но RFC 9937 отмечает, что этот шаг в некоторых сценариях может разрешить пачку последовательных сегментов, и рекомендует pacing для смягчения всплеска.

Спецификация не объявляет исчезновение всех временных рисков и не выдаёт предполагаемые эффекты мягкого темпа за полностью измеренные. Стандартизационный статус подтверждает публичное рассмотрение текста, а не корректность конкретного бинарного файла или пользу конкретной службы.

RFC 9937 также фиксирует, что с первой широко развёрнутой реализации 2011 года PRR служит механизмом быстрого восстановления Linux TCP для стандартных и поддерживаемых модулей перегрузки. Это важная история работающего кода. Она не говорит, какую ветвь выбрало конкретное ядро, был ли включён pacing и улучшилось ли время ответа пользователя.

Что должна содержать эксплуатационная квитанция

Проверяемое утверждение начинается с версии транспорта или ядра, модуля перегрузки, события обнаружения потери, исходных cwnd, inflight и RecoverFS, а также компонента и конфигурации, выбравших ssthresh.

Для каждого значимого ACK сохраняют накопительный прогресс, новую потерю, DeliveredData, значение и причину SafeACK, пропорциональную ветвь, CRB или SSRB, рассчитанный SndCnt, фактически отправленные байты и новый prr_out. Выбор между повторной и новой передачей отмечается отдельно.

При завершении нужны финальное окно и объём в сети, состояние pacing, всплеск, тайм-аут и повторные потери, а также распределения задержки и goodput против сопоставимой контрольной группы. Испытания охватывают перестановку, остановку приложения, SACK и режим без SACK там, где он поддерживается, и token-bucket policing. Отрицательные результаты обязательны: ACK могут продвигаться, пока путь или приложение остаются плохими.

Такая квитанция сохраняет порядок утверждений. ACK наблюдал доставку. Контроллер выбрал цель. PRR рассчитал бюджет. Другой модуль выбрал байты. Работающий код отправил. Эффект доказывает измерение, а не номер RFC.

Источники