Record RTT feedback experiments and refine multipath recovery plan

This commit is contained in:
evgeny committed 2026-10-23 01:56:01 +02:00
1 parent 7e0a0905e5
commit 259dfa35d9
2 files changed
+229 -18

No files matched your search

+197
View File
@@ -0,0 +1,197 @@
ETCP: независимая обратная связь каналов и доставка при отказах
Проверка архитектуры и план следующего изменения, 23.10.2026
Статус
Бюджет очереди BBR уже реализован в fix/etcp-multipath-recovery: 20мс в PROBE_BW,
все резервы входят в предел max(4*MSS, BDP + BW*20мс). Это мягкая цель модели;
STARTUP/DRAIN, сериализация и обратный трафик не дают гарантии физической очереди <=20мс.
В штатном тесте equal получено 14.464/16Мбит/с, bandwidth — 9.060/10Мбит/с;
очередь медленного канала в bandwidth сократилась примерно с 47 до 21мс.
Изменения протокола и учёта попыток ниже ещё не реализованы.
Что подтверждено кодом и диагностикой
1. ACK выбирает канал независимо от DATA: select_link(conn, 0), inflight/RR.
Одна общая ack_q смешивает подтверждения DATA разных каналов. Поэтому интервал
delivery sample включает фактический обратный путь ACK, а rtt_us берётся
из отдельного timestamp-обмена last_link. Для RTT 20/200мс измерены возвраты
быстрых DATA через медленный канал за >=112мс при RTT модели около 24мс.
Это несовместимые исходные данные для BDP, pacing и бюджета очереди.
2. Общий ACK.till вызывает тот же etcp_ack_recv(), что и явный ACK элемента.
Даже если явные ACK возвращать своим путём, till подтверждает DATA других
каналов и обновляет их BBR в чужой момент времени. Перенаправить ACK недостаточно.
3. INFLIGHT_PACKET хранит только последнюю попытку: last_link, last_timestamp,
delivery snapshots. При повторе они заменяются, ACK содержит только общий seq.
Поздний ACK старой копии может быть приписан новой попытке и другому каналу.
Неоднозначны и RTT, и скорость, и выбор окна, которое освобождается.
4. В начальном pacing есть отдельный дефект. bbr_update_min_rtt() устанавливает
has_seen_rtt до bbr_set_pacing_rate(), поэтому предусмотренная инициализация
на первом RTT пропускается. Её аргумент также ошибочен: передаётся B/s вместо
размера окна в байтах. Затем перевод pacing в целые Kbit/s превращает малую
ненулевую скорость в 0, который shaper трактует как unlimited. Обновление
скорости само по себе не пересчитывает уже поставленный shaper-таймер.
5. RTO общий, основан на RTT/jitter соединения. Очередь wait_ack просматривается
как FIFO с единым timeout; индивидуальные дедлайны с такой остановкой обхода
несовместимы. Повтор может снова уйти в зависший канал.
6. Поток собирается по общему seq: при RTT 20/200мс разность времени доставки
неизбежно создаёт переупорядочивание. Исправление ACK не устраняет ожидание
пропущенного фрагмента. В диагностике при высокой скорости накоплено порядка
0.17–0.29MB. Память сборки и пауза приложения требуют отдельных проверок.
7. stcp_link_send() подтверждает постановку в tx_queue. Это не означает прогресс
записи в TCP. Для stalled TCP одной проверки link_status/cwnd/pacer недостаточно.
Экспериментальная проверка причин
Диагностический бинарник /tmp/etcp-rtt-experiment включает штатный multipath-стенд
и настоящее ядро. Подмена происходит через linker --wrap, исходники протокола
не менялись. Используются реальные шифрование, UDP, dummynet и проверка порядка,
содержимого, полного завершения доставки, таймеров и счётчика выделений.
Контроль RTT 20/200мс, 8+8Мбит/с, с начальным pacing от окна/RTT:
- после завершения STARTUP полезная скорость 8.055/16Мбит/с, быстрый канал 0.633;
- свой путь ACK, без обновления BBR через till, фактический RTT попытки:
8.831 и 8.945/16Мбит/с; длинный канал недогружен;
- дополнительно исключены неоднозначные повторы из оценки скорости:
14.127 и 14.559/16Мбит/с, проверки установившегося режима прошли.
С последним вариантом дополнительно проверены RTT20/200мс при разных BWlim:
- 2+8Мбит/с (fast-distant): полезная скорость 8.735/10Мбит/с;
- 8+2Мбит/с (slow-distant): полезная скорость 8.979/10Мбит/с.
Проверки каждого канала, суммарной скорости, очереди и полного drain прошли.
В агрегате максимум очереди составил соответственно 24.9/26.4мс и 22.6/27.6мс.
Для равной BW выполнено два успешных повтора, для разных BW — по одному;
этого достаточно для выбора направления, но не для заявления о полной устойчивости.
Контроль последнего варианта по штатному rtt с фиксированным прогревом 3с:
14.312/16Мбит/с, очереди в агрегате 23.4/24.9мс, failures=0.
Это один успешный прогон диагностического прототипа, а не всего рабочего ядра.
Выборочные логи показывают преждевременный выход длинного канала из STARTUP
с заниженной оценкой BW. До фильтрации в модель попадал sample от повторной
передачи: RTT отвергнут, но delivery interval и скорость использованы.
Это подтверждает необходимость идентификации попытки; фильтр по send_count
годится для диагностики, но теряет достоверные измерения повторов и не заменяет ID.
Успешный единичный запуск без полного разделения учёта давал 14.45Мбит/с,
но повторные проверки выявили нестабильность. Он не является критерием готовности.
Отдельный прогрев до выхода из STARTUP использован только для диагностики:
штатные требования к разгону, очереди и утилизации не ослаблялись.
Фильтрация till в последнем прототипе сохраняет кумулятивную границу rx_ack_till;
её удаление из протокола сломало бы ограничение окна приёмника.
Прототип не проверяет новый wire-формат, владение попытками или отказоустойчивость.
Предлагаемый контракт
Разделить логическую доставку фрагмента и физическую попытку передачи.
- Логический объект: общий seq, payload, признак доставки. Он отвечает за порядок
потока, unacked_bytes приложения и очередь повторной доставки.
- Попытка: уникальный uint64 attempt_id, ссылка на канал, seq, размер, время
отправки, delivery snapshots и состояние учёта окна. Последующая отправка
создаёт новую попытку; предыдущие снимки остаются неизменными.
- attempt_id монотонен в пределах согласованной ETCP-сессии и не переиспользуется
при удалении/создании линка. Перезапуск счётчика допустим только с новой эпохой,
когда DATA/ACK старой сессии уже отклоняются. Переполнение закрывает сессию.
- DATA содержит seq + attempt_id. ACK элемента содержит attempt_id и ограниченную
задержку получателя. Задержка передаётся без короткого modulo-wrap; переполнение
помечает измерение недействительным. Пересчитать DATA MSS, MTU и ACK batching.
- Подтверждение попытки возвращается через тот же ETCP_LINK, где она принята.
Очередь ACK принадлежит линку; piggyback содержит только ACK этого линка.
Дубликат логического DATA с новым attempt_id тоже подтверждается.
- BBR обновляется по реально подтверждённой попытке своего канала. RTT — elapsed
этой попытки минус допустимый receiver delay. KA RTT остаётся метрикой живости.
ACK другого канала не формирует sample. ACK/control по-прежнему обходят только
локальный DATA-pacer; общая физическая очередь коммуникации сохраняется.
- Общий till остаётся подтверждением логической доставки и места приёмника.
Он может прийти по любому живому пути, освобождает payload/очередь повторов,
но не придумывает доставку попытки, RTT/BW или освобождение чужого окна.
- Доставка приложения учитывается один раз. Физические попытки учитываются
каждая в своей модели; их суммарная доставка может включать дубликаты DATA.
- ACK или объявление потери освобождает окно попытки ровно один раз. Поздний ACK
не дебетует его повторно. После доставки payload можно освободить, метаданные
других попыток живут до ACK/потери/закрытия, без удержания лишнего payload.
История ограничена по числу и сроку; неизвестный старый ID безопасно игнорируется.
- Удаление линка/сессии отменяет его таймеры, удаляет ACK и попытки, освобождает
учёт ровно один раз. Не хранить указатель на уже освобождённый ETCP_LINK.
Почему не общий самый быстрый обратный канал
Такой выбор не согласует интервалы и не устраняет неоднозначность повторов.
Понадобится учитывать смену обратного маршрута в каждой модели, а отказ общей
обратной дороги затронет остальные прямые пути. Собственный ACK сохраняет одну
модель на канал и независимость отказов. Общая логическая граница при этом
может распространяться любым рабочим каналом.
Последовательность реализации и критерии завершения
1. Начальный pacing как отдельное исправление без смены wire-формата.
Инициализировать от настоящего начального окна и первого валидного RTT.
Сохранить точные B/s до shaper, отделить unlimited от округления. При смене
ставки пересчитать оставшийся pacing-долг и таймер, не создавая новый burst.
Проверки: короткий служебный DATA -> пауза -> bulk, RTT20/200мс, скорость ниже
1Kbit/s, увеличение/уменьшение ставки с активным таймером, полный STARTUP.
2. Цельный переход на логические фрагменты и идентифицируемые попытки.
Добавить индекс attempt_id в очереди попыток каждого линка и отдельную ACK-очередь.
Общий индекс попыток не нужен: ACK ищется на принявшем его линке.
Разделить обработчики logical till и ACK попытки; одновременно обновить DATA,
ACK, декодеры, MTU/MSS, lifecycle и .h. Не оставлять промежуточный формат,
в котором новый ACK продолжает обращаться только к last_link.
Проверки: первая копия A -> повтор B -> поздний ACK A; обратный порядок ACK;
ACK дубликат; чужой/неизвестный ID; till с другого пути; link recreation;
потеря ACK при уже доставленном payload; close/reset с активными попытками.
После этого повторить всю матрицу скоростей. Балансировщик менять только
при сохраняющейся недогрузке: эксперименты уже показывают полную утилизацию
без смены алгоритма выбора DATA, поэтому дополнительная эвристика пока лишняя.
3. Независимые сроки и восстановление каналов.
RTT/RTO и таймер старейшей попытки принадлежат каналу. FIFO допустима только
при одном текущем RTO для всех его попыток; пересчитывать таймер при его смене.
При потере ограничить новые DATA на проблемном пути, пробовать восстановление
ограниченными probe, повторять недоставленные DATA через рабочие каналы.
Не отправлять следующий bulk вслепую в тот же застрявший путь.
Проверки: DROP/HOLD отдельно по направлениям и вместе, несколько застрявших
каналов, возврат старых копий после HOLD, повторный отказ, смена RTT/BW на ходу.
4. Учёт нижележащей очереди STCP.
Ограниченный tx_queue и уведомление о реальном прогрессе/готовности должны
участвовать в выборе пути. Определить время начала попытки и учёт данных,
принятых STCP, но ещё не записанных в сокет; не смешивать их с wire delivery.
Проверки: полностью остановленная TCP-запись рядом с рабочим UDP/STCP,
последующий выпуск очереди, закрытие соединения и отсутствие роста памяти.
Общие проверки
Матрица: equal, bandwidth, rtt, fast-distant, slow-distant, three, bidirectional.
Отдельно измерять время STARTUP, steady goodput, очередь каждого направления,
переупорядочивание, повторы и паузу приложения. Отчёт содержит данные каждого
повтора и минимум, а не только лучший результат. Не выполнять сетевые замеры
параллельно. Сохранить исходные пороги штатного test_etcp_multipath.
Добавить асимметричные прямой/обратный пути, ACK compression, поздние копии,
потери ACK и исчерпание лимитов памяти. Проверять счётчики по очередям, однократный
учёт подтверждения попытки и одну логическую доставку; утечки/UAF — ASAN/UBSan.
Логи: session/seq/attempt_id, DATA link, ACK link, send/receive/ack times,
receiver delay, причина retire, inflight до/после и вход/выход BBR.
Проверено для текущего бюджета: BBR18/18, windows16 сценариев, шесть транспортных
ASAN/UBSan тестов с detect_leaks=1 PASS. Общий check.sh: 180/183; FAIL
test_nat_detection_faults, test_nat_detection, test_encrypted_attachment.
Эти падения внесены отдельной задачей; связь с BBR не установлена.
Логи опытов: /tmp/etcp-rtt-ab-baseline.log,
/tmp/etcp-rtt-settled-control.log, /tmp/etcp-rtt-settled-candidate-diagnostic.log,
/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.
Сборка диагностического бинарника:
make -C tests -f Makefile -f /tmp/etcp-rtt-experiment.mk /tmp/etcp-rtt-experiment
Основной повтор:
RTT_SETTLED=1 RTT_SEED=1 RTT_SAME_ACK=1 RTT_NO_CUM=1 RTT_ACTUAL=1 RTT_KARN_RATE=1 \
/tmp/etcp-rtt-experiment rtt
+32 -18
View File
@@ -21,7 +21,7 @@
при разных RTT/BWlim не выполняются требования утилизации, в том числе из-за повторов и переполнения очередей.
Базовые исправления BBR/pacing внесены 23.10.2026 в fix/etcp-multipath-recovery (см. завершённую подзадачу ниже).
Выбор пути повторов, общий RTO и блокировка сборки ещё не исправлены.
Финальный прогон девяти отказов: drop-reverse/short-hold PASS, остальные семь FAIL по целевым требованиям;
Прогон девяти отказов до бюджета очереди: drop-reverse/short-hold PASS, остальные семь FAIL по целевым требованиям;
повтор на обычных часах slow-drop: пауза 450мс, latency 1267мс. Trace показывает повторную отправку в зависший путь.
Связанные регрессии 5/5 PASS. ASAN/UBSan + detect_leaks=1: calibration и short-hold PASS;
slow-drop сохраняет функциональный FAIL, ошибок санитайзеров/утечек во всех трёх запусках нет.
@@ -31,22 +31,35 @@
После исправлений добавить смену профилей на ходу, повторяющиеся отказы и смешанный UDP/STCP со stalled TCP write.
Полная матрица дольше 90s общего runner и запускается отдельной целью; нарушения завершают её с ошибкой.
Окно PROBE_RTT и DATA MSS согласованы 23.10.2026 (см. завершённую подзадачу ниже).
Одиночный канал RTT=200мс/BWlim=8Мбит/с теперь проходит: полезная скорость 6.99Мбит/с, очередь <=133.1мс.
Далее согласовать обратную связь: ACK выбирает путь по inflight/RR, скорость оценивается по фактическому времени
возврата ACK, а RTT модели берётся из отдельного timestamp-обмена исходного линка. Это разные интервалы.
При повторах ACK не идентифицирует попытку: запись хранит только last_link, старый ACK может быть приписан новому пути.
Нужен явный контракт учёта попыток до изменения выбора пути/повторов; простой запрет прошлого линка его не заменяет.
После этого исправлять здоровье линка, независимые сроки повторов и доставку при DROP/HOLD по существующим тестам.
Профили после исправления окна: equal PASS (14.75 из 16 Мбит/с), bandwidth по скорости PASS (9.11 из 10),
но очередь 47.9мс >40мс. RTT 20/200мс: 10.08 из 16 Мбит/с, быстрый путь недогружен; rtt FAIL.
Пороги очереди и утилизации не ослаблены. Логи: /tmp/etcp-probe-{equal,bandwidth,rtt}.log/.csv.
Диагностика bandwidth с состояниями модели: /tmp/etcp-probe-bandwidth-diagnostic.log.
Дополнительная проверка 23.10: /tmp/etcp-queue-budget.log/.csv; лог включает bw Q16, DATA MSS, ACK-резерв и пик очереди.
Пик штатного PROBE_UP: bw=16465/65536 байт/мкс, min_rtt=24000мкс, MSS=1097;
2*BDP=12060, ACK-резерв=1893, 2*MSS=2194, cwnd=16147 байт. Сложение и единицы на этом пике корректны.
Профиль bandwidth даёт полезные 9.045 из 10Мбит/с, очередь 47.1мс >40мс; порог теста не изменён.
Для следующей правки требуется выбрать политику: добавить бюджет задержки к BBR либо сохранить штатные резервы
и обосновать допустимый предел очереди с учётом сериализации. Вопрос передан пользователю; алгоритм пока не изменён.
Пользователь выбрал бюджет задержки; реализация и проверки завершены (см. подзадачу ниже).
После бюджета equal PASS (14.464 из 16 Мбит/с), bandwidth PASS (9.060 из 10), очередь медленного пути
25мс отдельно / 20.7мс в агрегате. RTT 20/200мс остаётся FAIL: 7.1–7.7 из 16 Мбит/с, быстрый путь недогружен.
Пороги очереди и утилизации не ослаблены. Логи: /tmp/etcp-queue-limited-{equal,bandwidth,rtt}.log/.csv.
Диагностика подтвердила несовместимость интервалов ACK и отдельного RTT last_link, обновление чужого BBR
через общий till и неоднозначность ACK повторов. Найден отдельный дефект начального pacing от окна/RTT.
Подробные причины, проверенный контракт попыток, этапы и критерии: [doc/etcp_multipath_plan.txt](etcp_multipath_plan.txt).
Диагностический прототип без правок протокола: после разгона контроль 8.055/16Мбит/с; свой путь ACK,
отдельный till и RTT попытки без фильтрации неоднозначной скорости дают лишь 8.831–8.945/16.
После фильтрации неоднозначных повторов — 14.127 и 14.559/16Мбит/с, steady-проверки PASS.
Разные BWlim 2+8 и 8+2Мбит/с при RTT20/200мс: 8.735 и 8.979/10Мбит/с, steady PASS.
Контроль прототипа по штатному rtt с прогревом 3с: 14.312/16Мбит/с, очередь 23.4/24.9мс, PASS.
Это проверка причин, а не реализация новой архитектуры: нужны attempt_id, владение очередями и lifecycle.
Начать с начального pacing, затем согласованно разделить логический seq и физические попытки/ACK,
после этого исправлять сроки/здоровье линка и DROP/HOLD. Смену DATA-балансировщика пока не навязывать:
прототип уже утилизирует пути без неё. Штатные проверки разгона и отказов остаются обязательными.
[+] **ETCP/BBR: бюджет очереди в установившемся режиме** — реализовано 23.10.2026 по выбору пользователя:
В PROBE_BW окно ограничено max(4*MSS, BDP + BW*20мс), с насыщением арифметики и учётом ACK/PROBE_UP резервов
внутри общего предела. Ограничение применяется также на fast path и до callback. 0 отключает политику.
STARTUP/DRAIN не ограничены этим бюджетом; это мягкая цель модели, а не гарантия физической очереди <=20мс.
До политики bandwidth давал очередь 47.1–47.9мс >40мс при корректных единицах и сложении резервов;
после политики профиль проходит по скорости и очереди, equal также PASS. Разные RTT и отказы не закрыты.
BBR 18/18, windows 16 сценариев PASS; BBR/windows/session/transport/STCP traffic/NCD ASAN/UBSan
с detect_leaks=1: 6/6 PASS. Полный check.sh: 180/183, FAIL NAT detection/fault и encrypted_attachment;
связь падений с BBR не установлена, отдельная открытая задача сохраняется.
Логи: /tmp/etcp-queue-budget-fastpath.log, /tmp/etcp-queue-budget-windows.log,
/tmp/etcp-queue-limited-asan-results.log, /tmp/etcp-queue-limited-asan-test_*.log,
/tmp/etcp-queue-limited-full-check.log. Политика описана в etcp_bbr.h, etcp_bbr_doc.md и doc/etcp_protocol.txt.
[+] **ETCP/BBR: единое окно DATA и корректное осушение PROBE_RTT** — исправлено 23.10.2026:
BBR использует MSS=normalizer->frag_size, а не wire-MTU/размер STCP-кадра. Начальное окно UDP/STCP равно 4*MSS;
@@ -88,10 +101,11 @@
После исправления окна BBR общий прогон снова 181/183: encrypted_attachment PASS, но FAIL оба NAT-теста.
test_nat_detection_faults упал в run_case mode=1 (UNKNOWN/contact_history); test_nat_detection не дождался профиля
за 18с на socket=udp. Его отдельный повтор тоже упал, уже на socket=second, с той же причиной contact_history/UNKNOWN.
После бюджета очереди полный check.sh: 180/183, повторились оба NAT-падения и encrypted_attachment.
Связь с изменениями BBR не установлена. Разобрать фикстуры/таймеры по логам, не ослаблять ожидания.
Логи: tests/logs/test_nat_detection_faults.log, tests/logs/test_encrypted_attachment.log,
/tmp/etcp-recovery-nat-retry.log, /tmp/etcp-recovery-attachment-retry.log,
/tmp/etcp-probe-full-check.log, /tmp/etcp-probe-nat-retry.log.
/tmp/etcp-probe-full-check.log, /tmp/etcp-probe-nat-retry.log, /tmp/etcp-queue-limited-full-check.log.
[+] **ETCP: единый установщик прямого транспорта через NCD** — исправлено 22.10.2026:
Удалён неиспользуемый рабочим кодом etcp_connect с EARLY/LATE, отдельными линками и таймерами;