diff --git a/HISTORY/2026-08-14-session-log.md b/HISTORY/2026-08-14-session-log.md index afcac96..095bfb2 100644 --- a/HISTORY/2026-08-14-session-log.md +++ b/HISTORY/2026-08-14-session-log.md @@ -989,3 +989,18 @@ cilium-operator, echo переоценён, нет PMTU/port-forward/второ Pro — методологически полнее, грубых ошибок нет. Рекомендованный синтез-порядок: nginx-логи → PMTU-зонд → сырые TCP → port-forward → tcpdump клиента → второй ISP → cilium monitor → echo → тикет. + +## 2026-08-15 — план v3 от СОННЕТА + сравнение трёх планов + +Сохранён: `doc/thinking/nubes-network-bug-plan-v3-sonnet.md`. + +Оценка (основной агент): план Соннета — лучший из трёх. Ключевые достоинства: +явное разделение явлений A (MTU/PMTUD, 51с = экспонента RTO 1-2-4-8-16) и +B (регулярность 1/37с = таймер gateway/kube-vip/conntrack), port-forward первым +kubectl-тестом, точный список размеров ping-зонда, корреляция по TCP seq. +Поправки: fallback если ICMP закрыт (mtr --tcp/TCP-порог), добавить второй +ISP и контрольный канал YMQ, port-forward идёт через API-сервер (исключает +приложение, но не доказывает шлюз), точный интервал таймаутов мерить новым +тестом с timestamp на каждый таймаут. +Сравнение: Flash — ошибки и недооценка; Pro — силён, но без явного разделения +явлений; Соннет — принять за основу с поправками. diff --git a/doc/thinking/nubes-network-bug-plan-v3-sonnet.md b/doc/thinking/nubes-network-bug-plan-v3-sonnet.md new file mode 100644 index 0000000..bcd8172 --- /dev/null +++ b/doc/thinking/nubes-network-bug-plan-v3-sonnet.md @@ -0,0 +1,150 @@ +# 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.