# Plan: Доказательство сетевого бага Nubes — v3 (СОННЕТ) > ✅ **ПОМЕТКА: это план от Соннета** (пользователь передал ответ Соннета). > Сохранено 2026-08-15. Сравнение с v1 (DeepSeek Flash) и v2 (DeepSeek Pro) — > в конце файла и в HISTORY. ## TL;DR Два РАЗНЫХ явления с разными причинами — нельзя объяснять одной гипотезой и нельзя ловить одним методом. Цепочка: nginx-логи → port-forward (бесплатное доказательство невиновности приложения) → PMTUD-зонд → tcpdump → cilium monitor → echo-сервис (только если предыдущих данных не хватает). ## Разделение двух явлений (критически важно) **Явление A — большие POST (~51с).** Причина: MSS=1448, underlay MTU=1450, сегменты 1488 → дроп. PMTUD сломан (ICMP Type 3 Code 4 заблокирован шлюзом) → TCP ретрасмитит по экспоненте: 1с,2с,4с,8с,16с ≈ 31с, ещё попытка → ~51с. Задача: подтвердить ping-зондом и зафиксировать в тикете. **Явление B — малые POST 512 байт (~1/37с).** MTU-моделью НЕ объясняется. Ключевая улика: РЕГУЛЯРНОСТЬ 1/37с — это таймер, не случайные потери. Кандидаты: сессионный таймер gateway на VIP 185.247.187.151 (вероятнее всего), kube-vip ARP keepalive цикл (флап при смене лидера), conntrack GC с агрессивным idle-таймером. ## 1. Echo vs сырые TCP Сырые TCP на 32391 — недостаточны (проверяют только фазу установления; проблемы в фазе ДАННЫХ; nginx ответит RST/400 на мусор — неинформативно). Правильный порядок: 1. kubectl port-forward (бесплатно, 5 минут) — чище и быстрее echo. 2. Echo NodePort без ingress — если port-forward и логи не дали ответа. Echo: принимает POST, возвращает тело; `?bytes=N` для размера ответа (обратный путь отдельно от прямого). Деплой БЕЗ ingress, прямой NodePort. ## 2. Как поймать таймаут: tcpdump Клиент (запустить ДО теста, параллельно): `tcpdump -i -s 0 -w /tmp/sqs.pcap 'host 185.247.187.151 and port 32391'` Явление A (51с, большой POST): ICMP Type 3 Code 4 от 185.x → PMTUD работает; нет ICMP, ретрасмиты 1/2/4/8/16с → PMTUD сломан (основная гипотеза); кто шлёт RST в конце и через сколько — чей таймаут (клиент vs nginx/шлюз). Явление B (30с, 512 байт): ACK на запрос получен → запрос дошёл, ответ потерян на обратном пути; ACK нет → потеря до nginx (kube-vip/NodePort/gateway); точный интервал между таймаутами (~37с ± 1с → таймер подтверждён); RST от сервера — чей (nginx idle keepalive или gateway). Ключевой приём: корреляция по TCP seq/ack, не по времени. ## 3. kube-vip / NodePort / nginx — только kubectl nginx access log: `kubectl logs -n ingress --since=35m | grep -E " (499|5[0-9][0-9]) "`. Нужны поля `$request_time $upstream_response_time`. Если нет — проверить ConfigMap nginx. | Запись в nginx log | Вывод | |---|---| | 499 + большой request_time | клиент ушёл до ответа (наш ReadTimeout) | | 200 + upstream <100мс, клиент получил таймаут | ответ потерян между nginx и клиентом | | записи нет | потеря ДО nginx: kube-vip/NodePort/gateway | kube-vip: `kubectl get pods -A | grep -i vip`, логи (leader/ARP/flap/error). ARP-флап во время теста → кратковременная потеря VIP → дропы. Cilium (на ПОДЕ, не на operator): `kubectl get pods -n kube-system -l k8s-app=cilium -o wide`; `kubectl exec -n kube-system -- cilium monitor --type drop` параллельно с тестом. NodePort/SNAT: `externalTrafficPolicy` — Cluster → любая нода + SNAT (лишний хоп, conntrack); Local → только нода-держатель VIP (миграция VIP → brief outage). port-forward: `kubectl port-forward -n svc/ 14100:4100` — тот же скрипт на localhost:14100. 0 таймаутов → приложение невиновно. ## 4. Пошаговый план: дешевле → дороже **Фаза 0 — бесплатно, уже есть данные:** 1. nginx access log за период прошлого теста (499, request_time/upstream_response_time). 2. kube-vip логи: флапы в тот же промежуток. 3. Тикет Nubes: два явления отдельно — (A) MTU/PMTUD порог 1448, (B) таймер ~37с. **Фаза 1 — клиентские тесты, 30 минут:** 4. PMTUD-зонд: `ping -M do -s N 185.247.187.151` для N=1300,1400,1420,1422, 1448,1450,1460,1472 — точный порог. Нет ответа ≥1448 → ICMP заблокирован → тикет с числами. 5. tcpdump + тот же 30-мин тест. Wireshark: `tcp.analysis.retransmission || icmp`. Точный интервал между таймаутами. **Фаза 2 — kubectl, без деплоя:** 6. port-forward тест ПЕРВЫМ: 15-мин прогон через туннель. 0 таймаутов → приложение доказанно невиновно. 7. cilium monitor параллельно со свежим тестом против внешнего IP. 8. Если нет upstream_response_time в формате — обновить ConfigMap, повторить. **Фаза 3 — echo (только если 0–2 не дали ответа):** 9. Minimal Go echo (NodePort, без ingress), тот же тест. Воспроизвелось → nginx и приложение исключены → kube-vip/NodePort/gateway. Нет → echo через ingress → изоляция nginx. 10. Матрица размеров 512/1000/1400/1448/1460/1500 × 10 мин, порог бинарным поиском. **Фаза 4 — финальная корреляция для тикета:** 11. Одновременно tcpdump + nginx access log + cilium monitor. Корреляция по seq: «запрос ушёл, ACK получен, ответа нет» = потеря между nginx и клиентом. Артефакты: pcap + логи + ping-зонд → тикет. **Решения о приоритетах:** - port-forward — самый дешёвый и чистый способ изолировать приложение. ДО echo. - Сырые TCP на 32391 — пропустить. - Echo — только если port-forward + nginx-логи не дали ответа. - Явления A и B документировать в тикете РАЗДЕЛЬНО. --- ## Поправки основного агента (GitHub Copilot) 1. **ICMP может быть закрыт на шлюзе** — тогда ping-зонд не даст порога. Нужен fallback: mtr --tcp / tcptraceroute или TCP-сегменты переменного размера (то, что Соннет отбросил как «сырые TCP» — но для определения ПОРОГА размера они валидны). 2. **Второй клиент с другого ISP** (был у Pro) — отсутствует. Дешёво исключает локальную сеть пользователя. Добавить в фазу 1. 3. **Параллельный контрольный канал YMQ** — стоит сохранить во всех тестах: отделяет «плохой интернет вообще» от «плох путь до Nubes». 4. **port-forward идёт через API-сервер** — не тот сетевой путь; чистый результат исключает приложение, но НЕ доказывает шлюз. Формулировка Соннета «доказательство невиновности приложения» — корректна, использовать её. 5. **Точный интервал таймаутов** надо измерять новым тестом с timestamp на каждый таймаут (в прошлом тесте тайминги не логировались поштучно). 6. Смена nginx log format (ConfigMap) на managed может требовать релода/помощи платформы — держать как запасной шаг. ## Сравнение трёх планов | | Flash (v1) | Pro (v2) | Соннет (v3) | |---|---|---|---| | Разделение явлений A/B | нет | частично | **явно, с причиной B=таймер** | | Ошибки команд | cilium через operator | нет | нет | | PMTU-зонд | нет | есть | есть, точный список размеров | | port-forward | нет | есть | **первым kubectl-тестом** | | Сырые TCP | недооценены | да | отброшены (спорно для порога) | | Второй ISP | нет | есть | нет | | Критерии доказательства | слабые | таблица | таблицы + фазы | | Объяснение 51с | нет | «прикладной таймер» | **экспонента RTO 1-2-4-8-16** | Вердикт: план Соннета — лучший из трёх. Принять за основу с поправками 1–6.