Retry Jitter in Docs

This commit is contained in:
Alexey
2026-10-31 14:38:25 +03:00
parent 3df59cfa28
commit 4635ecadd3
10 changed files with 330 additions and 58 deletions
+39 -12
View File
@@ -94,7 +94,7 @@ flowchart LR
W5 --> W6["Получен TL_pong<br/>Отображаемый замер завершён"]
X["Только если нужно ещё одно соединение<br/>TCP + TLS, возможный WebSocket Upgrade<br/>При переиспользовании нет handshake на каждый ping"] -.-> W3
X -.-> W5
R["Только при ошибках или перегрузке<br/>Повторы и backoff<br/>Retry-After: 1 может добавить около секунды"] -.-> W3
R["Только при ошибках или перегрузке<br/>Повторы и backoff<br/>База Telemt 250 мс<br/>Плюс опциональный jitter"] -.-> W3
R -.-> W5
end
classDef preparation fill:#eeeeee,stroke:#666666,color:#111111
@@ -113,6 +113,30 @@ flowchart LR
Таким образом, в видимую разницу могут войти оставшееся открытие WEB-потока, дополнительные соединения, обработка транспорта, планирование и подтверждённые повторы. Это не фиксированная надбавка TLS и не арифметическая сумма блоков. Начальный настоящий TLS намеренно показан до таймера Android: он влияет на полное время проверки, но обычно не на отображаемый замер. Отдельный транспорт проверки также означает, что активное соединение приложения не гарантирует прогретую проверку в списке прокси.
### Настраиваемый jitter HTTP-повторов
`[web.retry_jitter]` добавляет независимо выбранную задержку к каждому существующему HTTP-повтору бриджа: сетевым ошибкам и ответам 408/429/502/503/504. Менять приложения Telegram не требуется. Без секции или при `enabled = false` сохраняются подсказка Telemt на 250 мс и прежний backoff/jitter.
```toml
[web.retry_jitter]
enabled = true
min_ms = 0
max_ms = 250
distribution = "uniform"
# Only for distribution = "triangular":
# peak_ms = 125
```
Диапазон задаёт **добавку**, а не полную паузу: подсказка Telemt 250 мс с этим примером даёт 250–500 мс. Без положительной серверной подсказки база остаётся 250, 500, 1000, затем 2000 мс. Включённый jitter заменяет прежний jitter до 25%. Корректный стандартный `Retry-After` во включённом режиме не сокращается прежним пределом в 30 секунд. Если пауза не помещается в оставшийся бюджет операции, бюджет истекает без раннего повтора.
Значения по умолчанию: `enabled = false`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`, `peak_ms` отсутствует. Требуется `0 <= min_ms <= max_ms <= 30000`. `uniform` выбирает целые миллисекунды равномерно; `triangular` использует треугольную плотность с округлением до миллисекунд. Необязательный пик по умолчанию находится посередине и должен входить в диапазон. Явный пик для `uniform`, неизвестные ключи/распределения и неверные границы отклоняются даже при выключенной опции. Одинаковые границы дают постоянную добавку.
Политика фиксируется в каждой странице бриджа. Reload через конфиг/API влияет на новые страницы; активные сохраняют настройки при recovery. Recovery JSON и HTTP-заголовки совместимости не меняются. Используется `crypto.getRandomValues`, при недоступности — `Math.random` для совместимости. Успешный трафик не задерживается. Лимиты попыток, общий бюджет, отмена и повтор неизменных payload/sequence сохраняются; более длинные паузы могут уменьшить число попыток, помещающихся в startup/recovery-бюджет.
Это размывает фиксированные интервалы повторов, но не гарантирует защиту от DPI. Планирование браузера, сетевые очереди и другие временные характеристики протокола остаются наблюдаемыми. Существующие примеры временной шкалы описывают выключенную опцию. Для включённого режима добавляйте выбранную задержку к каждой паузе повтора, а не к первому соединению или каждому кадру данных.
Политика меняет только уже предусмотренные паузы перед повтором. Более строгие ограничения отдельных вызовов сохраняются: обычный poll `/down` и вызов `/up` после commit выполняют одну попытку; их replay при восстановлении допускает две. Опция не создаёт новых циклов повторов. Она не продлевает `web.timeouts.bridge_retry_secs` и сроки запуска или восстановления.
## Ориентировочная временная шкала
**Поясняющая модель, а не бенчмарк и не норматив задержки.** Числа подобраны, чтобы показать сложение этапов. Они не восстанавливают наблюдавшиеся 1000–1500 мс. Условия примера: DNS уже закеширован, RTT от клиента до фронтенда — 40 мс, TCP-соединение новое, при необходимости выполняется полный TLS 1.3 handshake, ключ авторизации DC уже есть, потерь и сброса нативной временной метки запроса нет. Базовый вариант — Classic/DD. Для EE собственная подготовка FakeTLS добавляется до нативного таймера.
@@ -126,10 +150,10 @@ flowchart LR
gantt
dateFormat x
axisFormat %S.%L
tickInterval 200millisecond
tickInterval 100millisecond
todayMarker off
title Отображаемый ping - условная модель
accTitle: Отображаемый ping - условная модель
title Отображаемый ping - jitter выключен
accTitle: Отображаемый ping - jitter выключен
accDescr: Секунды от метки запроса, подписи этапов в миллисекундах
section Classic/DD - 100 мс
R 100 мс :n_r, 0, 100ms
@@ -137,28 +161,31 @@ gantt
U 40 мс :w_u, 0, 40ms
R 100 мс :w_r, after w_u, 100ms
D 60 мс :w_d, after w_r, 60ms
section WEB с повтором - 1240 мс
section WEB с повтором - 490 мс
F 40 мс :crit, f_u, 0, 40ms
Ожидание 1000 мс :crit, retry_wait, after f_u, 1000ms
Ожидание 250 мс :crit, retry_wait, after f_u, 250ms
U 40 мс :retry_u, after retry_wait, 40ms
R 100 мс :retry_r, after retry_u, 100ms
D 60 мс :retry_d, after retry_r, 60ms
```
Длительности этапов: `R` = 100 мс базовой работы MTProxy relay/сети/DC для запроса и ответа. `U` = 40 мс дополнительной работы WEB на отправке/OPEN/клиенте. `D` = 60 мс дополнительной работы WEB на приёме и доставке. `F` = 40 мс одной неудачной попытки upload. `Ожидание` = 1000 мс ожидания по `Retry-After: 1`. `U` и `D` — условные дополнительные затраты сверх `R`, а не повторный учёт полного сетевого RTT. Ожидание ACK/commit учитывается лишь в той мере, в какой оно действительно задержало доставку.
Длительности этапов: `R` = 100 мс базовой работы MTProxy relay/сети/DC для запроса и ответа. `U` = 40 мс дополнительной работы WEB на отправке/OPEN/клиенте. `D` = 60 мс дополнительной работы WEB на приёме и доставке. `F` = 40 мс одной неудачной попытки upload. `Ожидание` = 250 мс ожидания по `X-Telemt-Retry-After-Ms: 250`. `U` и `D` — условные дополнительные затраты сверх `R`, а не повторный учёт полного сетевого RTT. Ожидание ACK/commit учитывается лишь в той мере, в какой оно действительно задержало доставку.
| Сценарий | До таймера ping | Отображаемый ping | Полное время проверки в модели |
| --- | --- | --- | --- |
| Classic/DD | 40 мс | 100 мс | 140 мс |
| WEB без ошибок | 750 мс | 40 + 100 + 60 = 200 мс | 950 мс |
| WEB с одной неудачной загрузкой и одним ожиданием повтора | 750 мс | 40 + 1000 + 40 + 100 + 60 = 1240 мс | 1990 мс |
| WEB с одной неудачной загрузкой и одним ожиданием повтора | 750 мс | 40 + 250 + 40 + 100 + 60 = 490 мс | 1240 мс |
| WEB, тот же повтор с uniform jitter 0–250 мс | 750 мс | 490–740 мс | 1240–1490 мс |
Ещё одно TCP + TLS 1.3 соединение, открытое **внутри** замера, могло бы добавить здесь около 80 мс при полностью последовательном выполнении: замер 200 мс превратился бы в 280 мс. При переиспользовании соединения затраты на этот дополнительный handshake равны нулю. Замена начального полного TLS 1.3 handshake на TLS 1.2 при этих условиях добавляет примерно 40 мс к подготовке, а не к показанному ping. В примерах не учтены обработка TLS, возобновление сессии и потери пакетов.
Строка с 1240 мс показывает один возможный механизм секундного результата — повтор, подтверждённый HTTP-трассировкой. Она не доказывает, что исходное наблюдение вызвано повторами. Если такого повтора нет, нужно найти другие фактические задержки: очереди, буферизацию фронтенда, открытие соединений или работу upstream. Не подставляйте таймауты вместо пауз и не переносите перекрывающиеся этапы в эту последовательную модель без проверки.
Строка с 490 мс и диаграмма показывают один повтор при выключенном jitter. Дополнительная строка таблицы применяет к тому же повтору `enabled = true`, `min_ms = 0`, `max_ms = 250`, `distribution = "uniform"`; её диапазон получен из модели, а не измерений. Прежний JavaScript-мост без миллисекундного расширения или посредник, удаляющий эту подсказку при выключенном jitter, сохраняет стандартную секундную паузу: отображаемый ping в той же модели составит 1240 мс. Ни один сценарий не устанавливает причину исходного наблюдения. Если повторы не подтверждены трассировкой, ищите другие задержки: очереди, буферизацию фронтенда, открытие соединений или upstream. Не подставляйте таймауты вместо пауз и не переносите перекрывающиеся этапы в эту последовательную модель без проверки.
## HTTP, WebSocket и другие источники задержки
Ответы Telemt при перегрузке содержат `Retry-After: 1` и `X-Telemt-Retry-After-Ms: 250`. Только статус `503` с этой точной парой заголовков задаёт сгенерированному мосту **базовую паузу 250 мс**. При `web.retry_jitter.enabled = false` пауза равна 250 мс; при включении добавляется настроенная случайная задержка. Для остальных ответов действуют стандартная обработка `Retry-After` или резервный backoff, описанные ниже. Ранее загруженные страницы JavaScript-моста без поддержки миллисекундной подсказки используют секундную паузу до загрузки новой страницы; обновлять приложение Telegram для этого не нужно. Лимиты попыток, абсолютные бюджеты, отмена и ограничения admission не меняются.
| Фактор | Влияние и подтверждение |
| --- | --- |
| HTTP uplink | Генерируемый мост предлагает `X-Telemt-Up-Window: 4`; сервер принимает 1–4, при отсутствии согласования используется 1. Окно 1 ждёт ACK перед следующей загрузкой, окно 4 допускает ограниченный параллелизм. Не весь HTTP работает по схеме «отправить и ждать». См. [согласование][runtime] и [обработчик сессии][session]. |
@@ -168,7 +195,7 @@ gantt
| Буферизация фронтенда | Буферизация запросов/ответов или отсутствие поддержки streaming/Upgrade могут задерживать короткие сообщения. Сверьте настройки с существующим примером NGINX, сохраняя маршрутизацию, аутентификацию и лимиты. |
| Планирование клиента | Java accept/read, UI dispatch, WebView/JavaScript и возврат в нативный код добавляют очереди. Нагрузка CPU, энергосбережение и смена мобильной сети могут усиливать задержки. |
| Пересылка и сеть | Могут учитываться оставшийся admission потока, внутренний MTProxy-handshake, подключение Direct или регистрация ME, ответ Telegram, потери/повторная передача и очереди. Готовая WEB-сессия не доказывает готовность upstream. |
| Ошибки и повторы | Telemt может вернуть `503` с `Retry-After: 1`. Мост учитывает его; для других повторов backoff начинается с 250 мс и удваивается до 2000 мс плюс jitter примерно до 25%, в пределах бюджета повторов. Повторяемые HTTP-статусы включают 408/429/502/503/504. Прежде чем объяснять секундную ступень этим механизмом, нужно увидеть события в трассировке. См. [ответы][response] и [повторы][request]. |
| Ошибки и повторы | Повторяемые статусы: 408/429/502/503/504. При выключенном jitter точная подсказка Telemt задаёт паузу 250 мс; без положительной подсказки сервера backoff начинается с 250 мс и удваивается до базовых 2000 мс плюс прежний jitter менее 25%. При включённом jitter пауза равна положительной подсказке сервера или этой базе **плюс** настроенная случайная добавка, заменяющая прежний jitter. Бюджеты и ограничения попыток отдельных вызовов сохраняются. Фиксируйте политику загруженного моста и фактическое время повторов. См. [ответы][response] и [повторы][request]. |
Дедлайны не являются обязательными паузами. Стандартные 10 с для запроса моста, 90 с бюджета повторов, 30 с ожидания первого байта потока и 10 с handshake потока нельзя складывать в обычный ping. `carrier_probe_coalesce_ms=0` отключает соответствующую дополнительную задержку объединения проб. Дедлайны переключения транспорта относятся к неудачным попыткам, а не к каждому успешному обмену. См. [значения по умолчанию](../../src/config/types/web/defaults.rs).
@@ -176,7 +203,7 @@ gantt
## Диагностика с сохранением защит
1. Запишите клиент/сборку, версию Android WebView, транспорт, публичный endpoint, семейство IP, сеть, маршрут Direct/ME, DC и нагрузку. Сравнивайте при одинаковых условиях. Учитывайте двухминутное кеширование Android: повторное чтение интерфейса не означает новый замер.
1. Запишите клиент/сборку, версию Android WebView, политику `web.retry_jitter` загруженного моста, транспорт, публичный endpoint, семейство IP, сеть, маршрут Direct/ME, DC и нагрузку. Сравнивайте при одинаковых условиях. Учитывайте двухминутное кеширование Android: повторное чтение интерфейса не означает новый замер.
2. Разделяйте три эксперимента: новую проверку в списке прокси; новый логический поток на готовом транспорте; прикладной RPC в установленной MTProto-сессии. Последние два требуют подходящих средств измерения в клиенте и не предоставляются автоматически списком прокси. Собирайте отдельные замеры и распределения, а не сравнивайте единичный холодный замер с прогретым.
3. Используйте аутентифицированный `GET /web-status` и существующие настройки `[web.debug]`: `capture_timings=true`, `capture_frames=true`, `body_capture="metadata"`. Включите ограниченный сбор по [руководству диагностики WEB](WEB_PROXY.ru.md), затем восстановите предыдущее состояние. Payload, capabilities и секреты для этой задачи не нужны.
4. Сопоставьте создание сессии, выбор/commit/ошибку транспорта, `stream_admitted`, `stream_first_byte`, `handshake_succeeded`, OPEN/DATA, HTTP-статусы и повторы. `relay_started` предшествует работе с upstream и не означает готовность DC. `GET /v1/runtime/web/status` и `GET /v1/runtime/web/sessions` дают контекст ёмкости и давления очередей, а не сквозной RTT.
@@ -184,7 +211,7 @@ gantt
6. Добавьте измерения соединений/TLS/запросов фронтенда и временные метки клиента, чтобы найти задержку вне Telemt. Проверьте повторное использование соединений, согласованный HTTP, буферизацию и Upgrade. Sideband-события запуска моста/HELLO не дают полную временную шкалу клиента. Для сравнения разных хостов синхронизируйте часы либо используйте локальные длительности.
7. При ME сопоставьте существующий trace `ME RTT sample` (`rtt_ms`, `ema_ms`, `base_ms`, `degraded`). Метка ставится до очереди writer/flush; EMA состоит из 80% прежнего значения и 20% нового замера. Планирование keepalive до этой метки не учитывается. Низкий ME RTT при высоком Android ping указывает на работу вне измеренного участка ME, но не определяет конкретную причину. См. [writer][writer] и [reader][reader].
Примеры интерпретации: быстрая обработка Telemt при поздней доставке клиенту направляет проверку к фронтенду, сети и очередям клиента; `503` вместе с `Retry-After: 1` подтверждает задержку повтора; длительная работа upstream требует изучения Direct/ME. Ни один из признаков сам по себе не доказывает, что 1000–1500 мс вызваны криптографией TLS. При сборе данных сохраняйте совместимость, проверку сертификатов, лимиты admission и backpressure.
Примеры интерпретации: быстрая обработка Telemt при поздней доставке клиенту направляет проверку к фронтенду, сети и очередям клиента; `503` и его retry-заголовки определяют базовую задержку, а политика jitter загруженного моста и клиентские отметки времени позволяют установить фактическую паузу; длительная работа upstream требует изучения Direct/ME. Ни один из признаков сам по себе не доказывает, что 1000–1500 мс вызваны криптографией TLS. При сборе данных сохраняйте совместимость, проверку сертификатов, лимиты admission и backpressure.
## Границы подтверждения