10 KiB
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 на мусор — неинформативно).
Правильный порядок:
- kubectl port-forward (бесплатно, 5 минут) — чище и быстрее echo.
- Echo NodePort без ingress — если port-forward и логи не дали ответа.
Echo: принимает POST, возвращает тело; ?bytes=N для размера ответа
(обратный путь отдельно от прямого). Деплой БЕЗ ingress, прямой NodePort.
2. Как поймать таймаут: tcpdump
Клиент (запустить ДО теста, параллельно):
tcpdump -i <iface> -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 <nginx-pod> --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-pod> -- cilium monitor --type drop
параллельно с тестом.
NodePort/SNAT: externalTrafficPolicy — Cluster → любая нода + SNAT (лишний хоп,
conntrack); Local → только нода-держатель VIP (миграция VIP → brief outage).
port-forward: kubectl port-forward -n <ns> svc/<sqs-svc> 14100:4100 — тот же
скрипт на localhost:14100. 0 таймаутов → приложение невиновно.
4. Пошаговый план: дешевле → дороже
Фаза 0 — бесплатно, уже есть данные:
- nginx access log за период прошлого теста (499, request_time/upstream_response_time).
- kube-vip логи: флапы в тот же промежуток.
- Тикет 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)
- ICMP может быть закрыт на шлюзе — тогда ping-зонд не даст порога. Нужен fallback: mtr --tcp / tcptraceroute или TCP-сегменты переменного размера (то, что Соннет отбросил как «сырые TCP» — но для определения ПОРОГА размера они валидны).
- Второй клиент с другого ISP (был у Pro) — отсутствует. Дешёво исключает локальную сеть пользователя. Добавить в фазу 1.
- Параллельный контрольный канал YMQ — стоит сохранить во всех тестах: отделяет «плохой интернет вообще» от «плох путь до Nubes».
- port-forward идёт через API-сервер — не тот сетевой путь; чистый результат исключает приложение, но НЕ доказывает шлюз. Формулировка Соннета «доказательство невиновности приложения» — корректна, использовать её.
- Точный интервал таймаутов надо измерять новым тестом с timestamp на каждый таймаут (в прошлом тесте тайминги не логировались поштучно).
- Смена 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.