Specify retry path rotation and close ACK ownership gaps
This commit is contained in:
1 parent
259dfa35d9
commit
4aae1f6151
2 files changed
+114
-12
No files matched your search
+102
-11
@@ -37,7 +37,12 @@ STARTUP/DRAIN, сериализация и обратный трафик не д
|
||||
|
||||
5. RTO общий, основан на RTT/jitter соединения. Очередь wait_ack просматривается
|
||||
как FIFO с единым timeout; индивидуальные дедлайны с такой остановкой обхода
|
||||
несовместимы. Повтор может снова уйти в зависший канал.
|
||||
несовместимы. Повтор может снова уйти в зависший канал. Приоритет следующего
|
||||
канала сейчас не реализован: select_link не получает last_link пакета,
|
||||
send_hist только записывается, а общий RR относится ко всему соединению.
|
||||
Воспроизведение на настоящих очередях/RTO при двух готовых UP-каналах дало
|
||||
seq1 A->A и seq2 B->B. Тест late_ack_and_migration этого не покрывает:
|
||||
он явно отключает A перед передачей через B.
|
||||
|
||||
6. Поток собирается по общему seq: при RTT 20/200мс разность времени доставки
|
||||
неизбежно создаёт переупорядочивание. Исправление ACK не устраняет ожидание
|
||||
@@ -47,6 +52,13 @@ STARTUP/DRAIN, сериализация и обратный трафик не д
|
||||
7. stcp_link_send() подтверждает постановку в tx_queue. Это не означает прогресс
|
||||
записи в TCP. Для stalled TCP одной проверки link_status/cwnd/pacer недостаточно.
|
||||
|
||||
8. В приёмнике ACK ставится в ack_q до выделения payload/ETCP_FRAGMENT и вставки
|
||||
в recv_q. При последующем OOM или отказе вставки уже подготовленный ACK может
|
||||
подтвердить несохранённые DATA. В новом контракте положительный ACK допустим
|
||||
только после сохранения фрагмента либо проверки, что он уже сохранён/доставлен.
|
||||
Инъекция отказа data_pool подтвердила: ACK_queued=1, DATA_stored=0,
|
||||
delivered_till=0. Это дефект надёжности, а не только неточность статистики BBR.
|
||||
|
||||
Экспериментальная проверка причин
|
||||
|
||||
Диагностический бинарник /tmp/etcp-rtt-experiment включает штатный multipath-стенд
|
||||
@@ -92,15 +104,32 @@ STARTUP/DRAIN, сериализация и обратный трафик не д
|
||||
|
||||
- Логический объект: общий seq, payload, признак доставки. Он отвечает за порядок
|
||||
потока, unacked_bytes приложения и очередь повторной доставки.
|
||||
Подтверждение фрагмента означает принятие его приёмником в надёжную очередь;
|
||||
сборка и выдача приложению идут своим порядком. Переход в очередь повтора
|
||||
идемпотентен: таймеры нескольких копий не создают несколько записей одного seq.
|
||||
Первый положительный ACK или till, покрывающий этот seq, удаляет ожидающий повтор.
|
||||
- Попытка: уникальный uint64 attempt_id, ссылка на канал, seq, размер, время
|
||||
отправки, delivery snapshots и состояние учёта окна. Последующая отправка
|
||||
создаёт новую попытку; предыдущие снимки остаются неизменными.
|
||||
Глобальные очереди содержат логические фрагменты: готовые к отправке и ожидающие
|
||||
доставки. Отдельные записи попыток принадлежат очередям линков; один ll_entry
|
||||
не включается в две очереди. Попытка хранит seq, а не висячую ссылку на уже
|
||||
доставленный логический объект.
|
||||
- attempt_id монотонен в пределах согласованной ETCP-сессии и не переиспользуется
|
||||
при удалении/создании линка. Перезапуск счётчика допустим только с новой эпохой,
|
||||
когда DATA/ACK старой сессии уже отклоняются. Переполнение закрывает сессию.
|
||||
- DATA содержит seq + attempt_id. ACK элемента содержит attempt_id и ограниченную
|
||||
задержку получателя. Задержка передаётся без короткого modulo-wrap; переполнение
|
||||
помечает измерение недействительным. Пересчитать DATA MSS, MTU и ACK batching.
|
||||
- DATA содержит seq + attempt_id. ACK элемента сохраняет оба идентификатора:
|
||||
seq:u32 + attempt_id:u64 + receiver_delay_us:u32. seq позволяет подтвердить
|
||||
логическую доставку даже после удаления метаданных старой попытки, без отдельной
|
||||
истории попыток. Для известного attempt_id проверять соответствие seq.
|
||||
Задержка насыщается, UINT32_MAX означает недействительный RTT sample.
|
||||
Пересчитать DATA MSS, MTU и ACK batching; не использовать modulo-wrap задержки.
|
||||
- ACK означает принятие DATA в надёжную очередь приёмника, не приход в сокет.
|
||||
Сначала проверить границы, сохранить DATA/вставить в recv_q либо найти дубликат,
|
||||
затем поставить ACK и лишь потом вызывать сборку/пользовательские callbacks.
|
||||
Это сохраняет порядок при reentrant close/reset. При OOM до сохранения DATA
|
||||
положительного ACK нет.
|
||||
При OOM самого ACK данные остаются сохранёнными; следующая копия получает ACK.
|
||||
- Подтверждение попытки возвращается через тот же ETCP_LINK, где она принята.
|
||||
Очередь ACK принадлежит линку; piggyback содержит только ACK этого линка.
|
||||
Дубликат логического DATA с новым attempt_id тоже подтверждается.
|
||||
@@ -111,15 +140,61 @@ STARTUP/DRAIN, сериализация и обратный трафик не д
|
||||
- Общий till остаётся подтверждением логической доставки и места приёмника.
|
||||
Он может прийти по любому живому пути, освобождает payload/очередь повторов,
|
||||
но не придумывает доставку попытки, RTT/BW или освобождение чужого окна.
|
||||
Продвижение till должно пробуждать отправку отдельного ACK с count=0 через
|
||||
готовый рабочий канал, даже без DATA и без ACK-элементов на нём. Объединять
|
||||
продвижения и ограничивать частоту, не создавать ответ на каждый ACK.
|
||||
Потеря последнего till не должна оставлять полное окно приёмника навсегда:
|
||||
ожидание места имеет таймер запроса актуального till через рабочий путь,
|
||||
получатель отвечает текущей границей. Таймер принадлежит соединению, активен
|
||||
только при ожидающих DATA и полном окне, отменяется при прогрессе/close/reset.
|
||||
Session-wrapped запрос/ответ не меняет модели BBR; частота ограничена.
|
||||
- Доставка приложения учитывается один раз. Физические попытки учитываются
|
||||
каждая в своей модели; их суммарная доставка может включать дубликаты DATA.
|
||||
- ACK или объявление потери освобождает окно попытки ровно один раз. Поздний ACK
|
||||
не дебетует его повторно. После доставки payload можно освободить, метаданные
|
||||
других попыток живут до ACK/потери/закрытия, без удержания лишнего payload.
|
||||
История ограничена по числу и сроку; неизвестный старый ID безопасно игнорируется.
|
||||
При потере запись попытки можно удалить: поздний ACK по seq ещё подтверждает
|
||||
логическую доставку, но неизвестный attempt_id не обновляет BBR или окно.
|
||||
Отдельная история/tombstone для уже потерянных попыток не нужна.
|
||||
- Удаление линка/сессии отменяет его таймеры, удаляет ACK и попытки, освобождает
|
||||
учёт ровно один раз. Не хранить указатель на уже освобождённый ETCP_LINK.
|
||||
|
||||
Правило повторной передачи, независимо от определения DOWN
|
||||
|
||||
Повтор использует историю именно своего логического фрагмента, не last_rr_link
|
||||
соединения и не позиции каналов в send_hist. При готовых A/B/C порядок попыток
|
||||
одного фрагмента — A->B->C->A; отправки других фрагментов и ACK его не меняют.
|
||||
Начать обход после last_link фрагмента, выбрать первый подходящий другой линк.
|
||||
Пропускать DOWN, неготовые, не вмещающие DATA и заблокированные pacer/транспортом.
|
||||
Если готовых альтернатив нет, разрешён готовый прежний линк. Если не готов никто,
|
||||
фрагмент ждёт штатного события ACK/pacer/transport-ready, без busy loop и нового RTO
|
||||
для ещё не отправленной копии. Временно занятый следующий линк не блокирует поиск
|
||||
остальных; отправлять без cwnd/pacing или ждать неограниченно именно его нельзя.
|
||||
|
||||
Для первоначальной отправки остаётся обычный выбор по загрузке. Retry — отдельный
|
||||
режим той же функции выбора, с едиными проверками готовности, без второго набора
|
||||
условий cwnd/pacing. Burst не навязывает DATA свой линк: при конфликте измерение
|
||||
идёт с FILLER, повтор отправляется по своему правилу. Старый линк не объявляется
|
||||
DOWN только потому, что копия отправлена другим путём.
|
||||
|
||||
last_link логического фрагмента — только заимствованный курсор выбора. При удалении
|
||||
линка очистить такие курсоры до free; при NULL начать с первого рабочего линка.
|
||||
Переиспользуемый uint8 local_link_id и порядковый номер списка не являются
|
||||
идентичностью попытки. send_count не должен определять retry через оборачиваемый
|
||||
uint8: хранить факт состоявшейся отправки отдельно от статистики.
|
||||
Курсор меняется после принятия новой попытки транспортом. Ошибка подготовки/OOM
|
||||
или отказ отправки не должны создавать фиктивный flight и ждать сетевого RTO.
|
||||
|
||||
Повтор и объявление потери — разные события. При ранней отправке второй копии
|
||||
первая ещё может быть в пути: её окно и метаданные остаются до собственного ACK,
|
||||
срока потери или закрытия. Сам по себе повтор не является loss sample для BBR.
|
||||
Дополнительные копии ограничены общим бюджетом памяти и окнами их каналов.
|
||||
Ротация сокращает число попыток через зависший путь, но не сокращает ожидание
|
||||
первого таймера. Нельзя обещать паузу <=100мс только сменой канала при RTO>100мс.
|
||||
Срок ранней повторной отправки и допустимую цену дубликатов проверять отдельно;
|
||||
сохранять физически достижимые требования конкретных профилей, не обещать один
|
||||
предел задержки для произвольных RTT, нагрузки и потерь.
|
||||
|
||||
Почему не общий самый быстрый обратный канал
|
||||
|
||||
Такой выбор не согласует интервалы и не устраняет неоднозначность повторов.
|
||||
@@ -141,18 +216,31 @@ STARTUP/DRAIN, сериализация и обратный трафик не д
|
||||
Добавить индекс attempt_id в очереди попыток каждого линка и отдельную ACK-очередь.
|
||||
Общий индекс попыток не нужен: ACK ищется на принявшем его линке.
|
||||
Разделить обработчики logical till и ACK попытки; одновременно обновить DATA,
|
||||
ACK, декодеры, MTU/MSS, lifecycle и .h. Не оставлять промежуточный формат,
|
||||
ACK, декодеры, MTU/MSS, lifecycle и .h. В этом же изменении нужны очередь/таймер
|
||||
попыток каждого линка и собственный RTT/RTO: иначе старый глобальный FIFO
|
||||
перестаёт соответствовать новому владению. FIFO допустима при одном текущем
|
||||
RTO для всех попыток линка; пересчитывать таймер при его смене.
|
||||
До первого DATA ACK использовать RTT того же KA-пути как начальную оценку
|
||||
либо консервативный начальный RTO; не начинать неизвестный путь с 5мс.
|
||||
Добавить ротацию retry сразу, пока старый канал ещё UP; не откладывать до DOWN.
|
||||
Не оставлять промежуточный формат,
|
||||
в котором новый ACK продолжает обращаться только к last_link.
|
||||
Проверки: первая копия A -> повтор B -> поздний ACK A; обратный порядок ACK;
|
||||
ACK дубликат; чужой/неизвестный ID; till с другого пути; link recreation;
|
||||
потеря ACK при уже доставленном payload; close/reset с активными попытками.
|
||||
После этого повторить всю матрицу скоростей. Балансировщик менять только
|
||||
потеря ACK при уже доставленном payload; close/reset с активными попытками;
|
||||
отказ принятия пакета транспортом без продвижения курсора и фиктивного flight;
|
||||
OOM сохранения DATA, вставки в recv_q и создания ACK. Проверить передачу till
|
||||
без DATA по другому пути и восстановление после потери последнего till.
|
||||
Для retry: A->B при обоих UP и меньшем inflight у A; A->B->C->A;
|
||||
посторонние DATA/ACK между попытками; пропуск заблокированных каналов;
|
||||
один доступный путь; все временно заняты; burst старого пути; удаление курсора.
|
||||
После этого повторить всю матрицу скоростей. Выбор пути первоначальных DATA менять только
|
||||
при сохраняющейся недогрузке: эксперименты уже показывают полную утилизацию
|
||||
без смены алгоритма выбора DATA, поэтому дополнительная эвристика пока лишняя.
|
||||
|
||||
3. Независимые сроки и восстановление каналов.
|
||||
RTT/RTO и таймер старейшей попытки принадлежат каналу. FIFO допустима только
|
||||
при одном текущем RTO для всех его попыток; пересчитывать таймер при его смене.
|
||||
3. Быстрое восстановление и здоровье каналов.
|
||||
Собственный RTT/RTO и ротация уже обязательны в этапе 2. Проверить срок первой
|
||||
повторной отправки, отдельно от объявления потери/снятия окна старой попытки.
|
||||
При потере ограничить новые DATA на проблемном пути, пробовать восстановление
|
||||
ограниченными probe, повторять недоставленные DATA через рабочие каналы.
|
||||
Не отправлять следующий bulk вслепую в тот же застрявший путь.
|
||||
@@ -190,6 +278,9 @@ test_nat_detection_faults, test_nat_detection, test_encrypted_attachment.
|
||||
/tmp/etcp-rtt-settled-karn.log, /tmp/etcp-rtt-settled-karn-repeat.log,
|
||||
/tmp/etcp-rtt-settled-fast-distant.log, /tmp/etcp-rtt-settled-slow-distant.log,
|
||||
/tmp/etcp-rtt-original-karn.log.
|
||||
Проверки отсутствующей ротации и ложного ACK при OOM: /tmp/etcp-retry-review.c,
|
||||
/tmp/etcp-retry-review.mk, /tmp/etcp-retry-review.log
|
||||
(exit=1: retry_rotation=2, false_ack=1, total=3; учёт/освобождение ресурсов проверены).
|
||||
Сборка диагностического бинарника:
|
||||
make -C tests -f Makefile -f /tmp/etcp-rtt-experiment.mk /tmp/etcp-rtt-experiment
|
||||
Основной повтор:
|
||||
|
||||
+12
-1
@@ -45,8 +45,19 @@
|
||||
Контроль прототипа по штатному rtt с прогревом 3с: 14.312/16Мбит/с, очередь 23.4/24.9мс, PASS.
|
||||
Это проверка причин, а не реализация новой архитектуры: нужны attempt_id, владение очередями и lifecycle.
|
||||
Начать с начального pacing, затем согласованно разделить логический seq и физические попытки/ACK,
|
||||
после этого исправлять сроки/здоровье линка и DROP/HOLD. Смену DATA-балансировщика пока не навязывать:
|
||||
после этого исправлять сроки/здоровье линка и DROP/HOLD. Выбор первоначального DATA-пути пока не менять:
|
||||
прототип уже утилизирует пути без неё. Штатные проверки разгона и отказов остаются обязательными.
|
||||
Дополнительный архитектурный разбор: ротации повтора относительно пути пакета сейчас нет.
|
||||
/tmp/etcp-retry-review.log: оба канала UP и готовы, seq1 A->A, seq2 B->B, retry_rotation=2.
|
||||
В контракт добавлены A->B->C->A с пропуском занятых и возвратом на прежний только без готовых альтернатив;
|
||||
burst не навязывает путь DATA. Ротация, очереди попыток и собственные RTO входят в единый этап перехода.
|
||||
ACK сохраняет seq вместе с attempt_id: поздний ACK освобождает логические данные и после удаления попытки,
|
||||
не меняя её уже снятое окно/BBR. Отдельная история потерянных попыток не требуется.
|
||||
Найдено подтверждение DATA до успешного сохранения в recv_q: включить исправление admission/ACK и OOM-тесты.
|
||||
Воспроизведение с отказом data_pool: ACK_queued=1, DATA_stored=0, delivered_till=0; false_ack=1.
|
||||
Также нужны передача till без DATA по другому пути и запрос потерянной границы при полном окне.
|
||||
Ранний повтор не равен loss: его старая копия остаётся в учёте до ACK/потери/close.
|
||||
Одна ротация не обеспечивает паузу <=100мс, если срок первой повторной отправки больше 100мс.
|
||||
|
||||
[+] **ETCP/BBR: бюджет очереди в установившемся режиме** — реализовано 23.10.2026 по выбору пользователя:
|
||||
В PROBE_BW окно ограничено max(4*MSS, BDP + BW*20мс), с насыщением арифметики и учётом ACK/PROBE_UP резервов
|
||||
|
||||
Reference in new issue
Block a user