diff --git a/HISTORY/2026-08-16-session-log.md b/HISTORY/2026-08-16-session-log.md index 27d9860..d974caa 100644 --- a/HISTORY/2026-08-16-session-log.md +++ b/HISTORY/2026-08-16-session-log.md @@ -1256,3 +1256,18 @@ paho connect() rc=0 даже при CONNACK≠0 (on_connect обязателен - v0.1.13 (digest 0450fd91b8f5) задеплоен; отдаваемый SVG идентичен локальному (4595 байт, viewBox 640x1060). При просмотре в браузере — жёсткое обновление (Ctrl+F5), т.к. браузер может держать старый SVG в кэше. + +--- + +## 37. Отчёт для DevOps Nubes (20:50 GMT+03) + +- Создан `doc/thinking/nubes-devops-report-2026-08-16.md`: + - Часть 1 — что не работает: wss ~150с (доказательства 5/5 станций, + Vultr, 600с внутри), MTU/51с (три контура: drhider MTU 1450+Geneve 50 + vs pod 1500 → дроп → ретрансмиссия 51с; SQS >1.4KB; IoT >15KB, + MSS 1448/MTU 1400), таймауты малых тел ~5.5% (512B, 31-33с, + внутри 24977 раундов 0 сбоев). + - Часть 2 — как исправить: MSS-clamping (TCPMSS clamp-to-pmtu), MTU + подов 1400, проверка ICMP fragmentation needed, idle-timeout + edge-шлюза ≥600с + ws ping/pong, критерии приёмки. + - Отдельно: что мы уже обошли сами и что нужно от DevOps. diff --git a/doc/thinking/nubes-devops-report-2026-08-16.md b/doc/thinking/nubes-devops-report-2026-08-16.md new file mode 100644 index 0000000..4dce77d --- /dev/null +++ b/doc/thinking/nubes-devops-report-2026-08-16.md @@ -0,0 +1,143 @@ +# Отчёт для DevOps Nubes — сетевые проблемы платформы + +**Кластер:** iot-naeel +**Дата:** 2026-08-16 +**Статус:** предварительный, все факты подтверждены тестами и дампами. +Готовы предоставить скрипты воспроизведения и провести совместные тесты. + +--- + +## Часть 1. Что не работает (наблюдения и доказательства) + +### 1.1 Внешние WebSocket-соединения закрываются ~через 150 секунд + +**Симптом.** WebSocket-соединения из внешних сетей (wss, TLS) закрываются +в районе 150 секунд после установления. Для клиентов это выглядит как +разрыв без видимой причины (close 1006/1005) с необходимостью +переподключения. + +**Доказательства.** +- 5 из 5 внешних станций (разные сети) — разрыв ~150 с, стабильно. +- Чистый VPS (Vultr) — 1 из 1, тот же разрыв ~150 с. +- Внутри кластера (под → сервис) — 600 с без единого разрыва. +- Машина за тем же шлюзом, но вне платформы — 300 с чисто. +- Контрольные wss-соединения к внешним ресурсам (nginx, echo-серверы) + с тех же станций — чисто. + +**Вывод.** Обрывает именно edge-шлюз платформы (или балансировщик перед +ним), по таймеру. Похоже на фиксированный лимит времени жизни +соединения (idle/lifetime timeout) на проксирующем слое. + +**Влияние.** Любой долгоживущий протокол поверх WebSocket (например, +MQTT) вынужден переподключаться каждые ~150 с. Наши клиенты это +переживают (автопереподключение), но это лишний трафик и окна потерь. + +### 1.2 Зависание внешних соединений ~на 51 секунду при объёмном трафике (MTU) + +**Симптом.** Из внешней сети операции с телом/ответом крупнее ~1,4 КБ +периодически «зависают» ровно на ~51 секунду, после чего либо +завершаются, либо обрываются. Внутри кластера те же операции проходят +мгновенно. + +**Доказательства (три независимых контура).** +- Контур A (HTTP-сервис за платформой): POST снаружи — пауза ~51 с на + любом объёме данных выше порога; изнутри — мгновенно. При + внешнемTrafficPolicy: Cluster большие файлы (>5 МБ) дают TCP-stall + ровно на 51 с. +- Контур B (очередь с AWS-совместимым API): тела >~1,4 КБ виснут ~51 с + (классическая экспонента TCP-ретрансмитов). +- Контур C (REST API): HTTP-ответы крупнее ~15 КБ приходят частично и + виснут (в тесте получено 15 672 байта — далее стоп); маленькие ответы + (до ~15 КБ) проходят стабильно. + +**Диагностика (наша гипотеза, подтверждённая измерениями).** +- Underlay MTU = 1450. +- Оверлей (Cilium Geneve) добавляет ~50 байт инкапсуляции. +- MTU контейнеров остаётся дефолтным 1500. +- Кросс-нодовый пакет полного размера = 1500 + 50 = 1550 > 1450 → + фрагментация невозможна (DF) → пакет дропается → ядро ждёт + ретрансмиссии по экспоненте → суммарная пауза ~51 с. +- На внешнем пути наблюдается MSS 1448 при MTU 1400 — т.е. ICMP + «fragmentation needed» до клиентов, вероятно, не доходит (PMTUD + сломан на каком-то из хопов). + +**Влияние.** Любой объёмный запрос/ответ снаружи рискует зависнуть на +~51 с; клиенты с таймаутами 30 с получают «таймаут», хотя сервис +ответил мгновенно. + +### 1.3 Периодические таймауты внешних запросов на малых объёмах (~5,5%) + +**Симптом.** Даже запросы размером ~512 байт снаружи в ~5,5% случаев не +получают ответ 30+ секунд; характерный паттерн — зависание на 31–33 с. + +**Доказательства.** +- Внутри кластера: 24 977 запросов подряд — 0 сбоев (порт-форвард). +- Снаружи: периодические зависания подтверждены tcpdump-ом (запрос + уходит, ответ не возвращается в течение 30+ с). +- Маловероятно, что это наша прикладная логика: те же операции изнутри + кластера стабильны. + +**Гипотеза.** Связь с пунктом 1.2 (потеря крупных сегментов при +переговорах TLS/подтверждениях) или лимиты conntrack/сессий на +балансировщике. + +--- + +## Часть 2. Как это исправить (наши предложения) + +### 2.1 К пункту 1.1 (wss ~150 с) + +1. Найти слой, который закрывает соединения: проверить настройки + idle/lifetime timeout на edge-шлюзе и балансировщике перед кластером + (nginx: `proxy_read_timeout`, `proxy_send_timeout`; LB: idle timeout). +2. Для wss-трафика выставить таймауты ≥ 600 с (или «без таймаута»). +3. Включить WebSocket ping/pong на прокси-слое (keepalive-фреймы каждые + 30–60 с), чтобы соединение не считалось простаивающим. +4. После изменения — прогнать наш контрольный тест (wss-клиент держит + соединение 10 минут; критерий — 0 разрывов). + +### 2.2 К пункту 1.2 (MTU / 51 с) + +Варианты, в порядке предпочтения: + +1. **Включить MSS-clamping на внешнем пути** (на шлюзе/на узлах): + `iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \ + -j TCPMSS --clamp-mss-to-pmtu` (или фиксированный MSS под MTU + внешнего интерфейса). Это дешёвое и надёжное решение: клиент не будет + слать сегменты крупнее, чем проходит путь. +2. **Привести MTU контейнеров к underlay**: MTU подов 1450 − 50 + (инкапсуляция) = 1400. Тогда кросс-нодовые пакеты перестанут + превышать underlay, и дропы исчезнут в принципе. +3. **Проверить, что ICMP «fragmentation needed» не режется** на всём + внешнем пути (firewall/LB) — восстановление PMTUD решит проблему + для больших ответов. +4. Отключить запрет фрагментации на edge для исходящих сегментов (менее + желательно). + +Критерий приёмки: POST/GET с телами 1 КБ…1 МБ снаружи проходят без +пауз >2 с (наш тест: 100 запросов разных размеров, 0 зависаний). + +### 2.3 К пункту 1.3 (таймауты малых тел) + +1. Сначала применить 2.2 — вероятно, это тот же корень. +2. Если проблема останется: проверить лимиты conntrack на шлюзе + (`nf_conntrack_max`, `table-full` в логах) и пул/лимиты соединений + балансировщика. +3. Критерий: 10 000 запросов по 512 байт снаружи — 0 таймаутов. + +--- + +## Что мы уже сделали со своей стороны (обходы) + +- Клиенты переподключаются автоматически (переживают пункт 1.1). +- Внутренние взаимодействия ходят по внутренним DNS, минуя внешний + шлюз (таймауты 1.3 нас не блокируют). +- Чтение больших списков разбито на страницы небольшого размера + (обход пункта 1.2). + +## Что нужно от вас + +1. Подтверждение/опровержение по каждому пункту. +2. Если нужны воспроизведения — дайте окно и среду, прогоним тесты + совместно (скрипты готовы). +3. Оценка сроков по пунктам 2.1–2.3.