From f10078e48280ebcc648ef51bd52ded1af4eebc89 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sun, 11 Oct 2026 13:31:23 +0200 Subject: [PATCH] Document timestamp metrics and negotiated stream overload cuts --- doc/stream.txt | 63 ++++++++++++++++++++++++++++++++++++++++---------- doc/tasks.md | 10 +++++++- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/doc/stream.txt b/doc/stream.txt index 046ae0fe..0b16f21b 100644 --- a/doc/stream.txt +++ b/doc/stream.txt @@ -370,8 +370,10 @@ Rate выдачи — её средний вклад в поступающую Число выдач выбирается по их rates: закрываем достаточно выдач для требуемого сокращения; при сильном росте это сразу несколько, не фиксированная одна и не случайное постоянное число. -OVERLOAD содержит request_id, расчётное число выдач и требуемое сокращение rate. -Получатель выбирает handles с учётом FEC и альтернативных поставщиков. +OVERLOAD содержит request_id, расчётное число выдач, требуемое сокращение rate и список handles с фиксированными rates. +Получатель выбирает handles с учётом FEC и альтернативных поставщиков и отправляет OVERLOAD_SELECT. +Отправитель исполняет выбор, только пока актуален исходный request_id, и сообщает CLOSED. +Получатель не отсоединяет выбранные handles до CLOSED: поздний SELECT после принудительного закрытия не режет дополнительные выдачи. При разных rates одного количества закрытий недостаточно: суммарный снятый rate должен покрыть требование. Rate закрываемых выдач фиксируется по оценке на момент запроса, чтобы условие исполнения не менялось на каждом тике. Срок реакции — 2 секунды с первого запроса; повторы не сбрасывают срок и не начинают новое требование. @@ -544,9 +546,35 @@ Stop/destroy выполняются по правилам ядра, вне callb Общий ./check.sh: 144 passed, 0 failed, 0 skipped; proxy/full (9/9), burst и load — PASS. Лог: /tmp/stream-network-check.log (88 с). -[ ] Планировщик отправки и разгрузка: - одна очередь на пира, backpressure, ограничение памяти/возраста, A/D/X/Q, - подтверждение 500 мс, сокращение по g/rates и двухсекундный срок исполнения OVERLOAD. +[+] Метрики и разгрузка — 11.10.2026: + stream_load.c/h — баланс A/D/X/Q по packets/bytes для выдачи, пира и модуля; + интервалы >=200мс фактической длительности, история 10с, рост A-D за 1с до искусственных X. + Изменение состава выдач исключает смешанный интервал из роста и сбрасывает его подтверждение. + Кольцо сообщает только фактические вставки/вытеснения; повторный блок не создаёт A. + Списки субпотоков по времени вставки дают точный возраст ещё ожидающих блоков, в том числе вне порядка batch_seq. + Логическая DATA-очередь представлена курсорами и счетчиками: содержимое и история остаются в одном 32-МБ кольце. + Частные/общие метрики lag/rates/late/stops подключены к подписанным DATA; после END ожидание прекращается. + INFO содержит nonce пробы и 64-битный снимок метрик; RTT — uint32 мс с признаком неизвестного. + Условие перегрузки: ожидающая нагрузка старше 200мс и рост либо нулевой D; + непрерывное подтверждение — 500мс по монотонным часам, независимо от количества тиков. + Требуемое сокращение — g + 1% + 1 байт/с, с ограничением суммой доступных rates; при нулевом D — также оценка backlog/2с. + Rates фиксируются при создании OVERLOAD. Расчётное число — подсказка, исполнение проверяется по суммарному rate. + Получатель предпочитает закрытия, сохраняющие k с учётом других поставщиков, затем parity при равных условиях. + OVERLOAD_SELECT предлагает handles; source закрывает только актуальное требование, поздний/повторный выбор безопасен. + Срок 2с начинается с первого запроса и не меняется при повторе. Невыполненный остаток source закрывает сам. + Новые SUBSCRIBE не компенсируют разгрузку: запрет действует до исполнения и 500мс снятого давления; + stream_peer_get_load.accepting сообщает этот статус отдельно от request_active. + Глобальный бюджет включается только для backlog нескольких пиров вместе с CPU/опозданием callbacks; + CPU отдельно не отключает выдачи, уже запрошенное сокращение повторно не учитывается. + Control FIFO ограничена 128 кодограммами по 1094 байта, возрастом 4с и отменой неподтверждённых запросов. + Просроченные ожидающие DATA при активном OVERLOAD учитываются X и пропускаются явным GAP, кольцо не стирается. + Диагностика сообщает A/D/X/Q, age, input/output/g, длительность интервала, cpu/late callbacks, + frozen/released rates, request/deadline и нижние очереди/inflight; D остаётся принятием ETCP, а не доставкой. + test_stream_core: баланс, X отдельно от D, граница 500мс, глитч, смена состава, 10-секундное окно и широкие wire-метрики. + test_stream_service: реальная заблокированная очередь ETCP, короткий глитч без закрытий, частичная parity-разгрузка, + продолжающийся FEC decode, несколько закрытий, подавленный SELECT/fallback/поздний выбор и общий бюджет двух пиров. + Высокий CPU без backlog не создаёт нового OVERLOAD. Оба теста прошли под ASAN/LeakSanitizer без ошибок и утечек. + Логи: /tmp/stream-pressure-asan-core.log и /tmp/stream-pressure-asan-service.log. [ ] Оптимизация сети и интеграционные проверки: пути/защита от циклов, стартовые 32 пробы, дальнейший темп 1/с и полный цикл не чаще 30 с, @@ -557,31 +585,42 @@ stream_receive_get_info сообщает handle/прогресс/причину, Локальная подписка по-прежнему владеет кольцом; receive handle её не заменяет и закрывается отдельно. Прямой dispatcher в старой части теста сохранён для изолированной проверки FEC и закрытия из callback; новая часть проверяет реальные сетевые bindings и передачу через relay. -Следующий этап — метрики поставщиков/общей нагрузки, OVERLOAD с подтверждением 500 мс и оптимизатор проб/переноса. +Следующий этап — автоматические пробы 32/1с/30с, выбор поставщиков, перенос с перекрытием и failover. 17. Зафиксированный сетевой формат и пределы первого сетевого этапа Все stream-числа на wire — big-endian, без packed-структур и зависимости от host byte order. +Версия stream wire — 2; обратная совместимость не поддерживается. Заголовок raw (52 байта): cmd:1, version:1, command:1, subblock:1, group_id:8, source_node_id:8, source_epoch:8, sender_epoch:8, receiver_epoch:8, handle:8. INFO_REQ/RESP согласуют sender/receiver epochs; неизвестная receiver_epoch=0 допустима только при начальном INFO_REQ/reverse. Подписанный routed payload содержит тот же заголовок; его group_id сверяется с реальной группой router, sender берётся из end-to-end router metadata. DATA через routed service отвергается. -INFO_RESP/ACCEPT: actual_seq:8, first_available:8, last_available:8, n:1, r:1, block_size:2, -path_count:1, node_ids:8*path_count. В INFO actual_seq — последний доступный, в ACCEPT — фактический старт. -SUBSCRIBE: requested_seq:8; REJECT: reason:1 и для отказа SUBSCRIBE first_available:8,last_available:8. +INFO_REQ: probe_nonce:8, не резервирует номер SUBSCRIBE. +INFO_RESP/ACCEPT: probe_nonce:8 (0 в ACCEPT), actual_seq:8, first_available:8, last_available:8, n:1, r:1, block_size:2, +metric_flags:1, lag_ms:8, source_rate:8, receive_rate:8, blocks:8, late_blocks:8, stops:8, +path_count:1, node_ids:8*path_count — фиксированная часть 86 байт. В INFO actual_seq — последний доступный, в ACCEPT — старт. +metric_flags: bit0 — измерение известно, bit1 — source_rate известен, bit2 — receive_rate известен, bit3 — stopped. +SUBSCRIBE: requested_seq:8; REJECT: reason:1, для SUBSCRIBE дополнительно first_available:8,last_available:8, +для INFO дополнительно probe_nonce:8. Старый nonce не подтверждает новую пробу. RENEW: один header handle без payload (каждая кодограмма продлевает один элемент списка). UNSUBSCRIBE/CLOSED: reason:1. DATA: path_count:1,node_ids:8*path_count,неизменяемый подписанный блок. GAP: old_cursor:8,next_cursor:8, уведомление включает диапазон [old_cursor,next_cursor). END: "stream_end":10,group_id:8,source_node_id:8,source_epoch:8,last_seq:8,Ed25519:64 — всего 106 байт. UINT64_MAX в END означает пустой источник; запрос с конца пустого кольца явно отвергается (нет первого блока). +OVERLOAD: request_id:8, required_rate:8 (байт/с), estimated_count:1, candidate_count:1, +{handle:8,frozen_rate:8}*candidate_count; не более 64 элементов. +OVERLOAD_SELECT: request_id:8, selected_count:1, handles:8*selected_count; не более 64 элементов. +Оба сообщения идут по raw ETCP с проверенными эпохами пира и действуют только на существующие выдачи. +Список проверяется полностью до действия; повторный/поздний id не создаёт новое требование и не продлевает срок. Предел пути — 32 узла. Сохраняются только реальные узлы пути; исходный {source} не требует отдельной аллокации. Память пути отделена от 32-МБ бюджета данных и ограничена числом блоков кольца: до (8 + 8*32) байт на блок плюс поля индекса и overhead allocator; источнику эта память путей не нужна. 64 stream-пира, 256 активных выдач всего и 64 на пира. Control FIFO — до 128 кодограмм, -каждая не больше 338 байт wire; DATA в ней не хранится. На пира один waiter общего send_input_q, +каждая не больше 1094 байт wire плюс 8 байт локального времени постановки; DATA в ней не хранится. На пира один waiter send_input_q, отправка по освобождению до пустого порога; курсоры downstream обслуживаются round-robin. -Эти пределы задают ограниченную память базовой выдачи. A/D/X/Q, возраст нагрузки и 500-мс OVERLOAD -подключаются следующим этапом; автоматический выбор/перекрытие поставщиков пока не запускаются. +Для временного индекса каждый фактический блок дополнительно имеет seq/received_ms и два uint32 указателя списка субпотока. +Логический Q не выделяет память под копии/задания на весь backlog и ограничен доступными блоками колец и числом выдач. +Эти пределы задают ограниченную память выдачи и разгрузки; автоматический выбор/перекрытие поставщиков пока не запускаются. diff --git a/doc/tasks.md b/doc/tasks.md index e48b9b9d..e04cdbb9 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -25,7 +25,15 @@ После восстановления обычной сборки ./check.sh: 144 passed, 0 failed, 0 skipped; proxy/full (9/9), burst и load — PASS. Лог: /tmp/stream-network-check.log (88 с). Wire и численные пределы зафиксированы в doc/stream.txt, раздел 17. - Следующий этап — метрики и перегрузка (500мс/rates/OVERLOAD), затем автоматические пробы/перенос/failover. + 11.10.2026 подключены timestamp-метрики/rates/stops, nonce/метрики INFO и RTT uint32 мс, + A/D/X/Q выдач/пиров/модуля, интервалы 200мс и история 10с, подтверждение перегрузки 500мс. + OVERLOAD с frozen rates, FEC/альтернативами при выборе, SELECT/CLOSED, неизменным сроком 2с и fallback; + глобальный бюджет нескольких пиров требует backlog и локальной загрузки, CPU отдельно не режет. + 4-секундный предел возраста control/ожидающих заданий, GAP/X при истечении и наблюдаемый статус accepting. + Частичная/сильная/глобальная разгрузка, короткий глитч и поздний SELECT прошли под ASAN/LeakSanitizer без ошибок/утечек. + Логи: /tmp/stream-pressure-asan-core.log и /tmp/stream-pressure-asan-service.log. + Wire версии 2 и пределы обновлены в doc/stream.txt, раздел 17. + Следующий этап — автоматические пробы 32/1с/30с, перенос с перекрытием и failover. [+] **test_reality_tls: коллизии порта слушателя** — 10.10.2026: В общем прогоне 140 passed, 1 failed: stcp_server_create не смог занять порт 34922, bind errno=98 (EADDRINUSE).