Files
loadtest/History/2026-07-10-root-cause-analysis.md
T
2026-07-10 21:19:31 +04:00

4.4 KiB
Raw Blame History

2026-07-10 — ИТОГ РАССЛЕДОВАНИЯ: почему режется загрузка

Методология

Тестирование от внутреннего к внешнему — послойная изоляция каждого компонента.

Результаты тестов

# Тест Маршрут Размер Результат
1 Python внутри пода → Flask pod → localhost:5000 100KB base64 (136KB POST) 102400 байт, 4ms
2 Python внутри пода → Ingress HTTPS pod → 10.105.13.158:443 136KB POST 102400 байт, 2ms
3 Python снаружи → Ingress интернет → 185.247.187.151:443 136KB POST СЛУЧАЙНО
4 10×100KB снаружи интернет → 185.247.187.151:443 136KB POST ~50% OK, ~50% RemoteDisconnected

Бинарный поиск предела (снаружи)

Размер POST Результат
1-48 KB всегда
50 KB
52 KB
55-80 KB
100 KB (иногда!)

Твёрдого предела НЕТ. Сбои случайные.

Исключённые причины

Компонент Статус Доказательство
Flask dev-сервер OK Тест #1
nginx ingress OK Тест #2
ModSecurity (128KB NoFilesLimit) OK Тест #2, DetectionOnly
Gunicorn field_size не используется Shturval запускает python app.py

Где проблема

Клиент (интернет)
    │
    ▼
??? Edge-инфраструктура хостера (NUBES LLC, AS212136) ???
    │  ← здесь рвётся TCP-соединение для POST > ~48KB
    ▼
185.247.187.151:443 (hostPort на ноде)
    │
    ▼
nginx ingress pod ─── ModSecurity ─── pythonk8s pod (Flask)
                                     ✅ всё работает

IP в логах ingress: 192.168.255.x — приватный IP хостинг-провайдера. На ноде порт 443 слушает kube-vip/hostPort напрямую (без proxy_protocol). Внутри кластера всё идеально. Снаружи — случайные обрывы.

Аналогичный опыт (contracts)

/home/naeel/nubes/contracts/History/:

  • connection-reset-analysis.md: curl 100KB → HTTP 000 случайно (5 тестов: 2 OK, 3 обрыв)
  • sonnet-upload-from-scratch.md: "64KB — жёсткий предел платформы" (43 версии)
  • session-08-upload-saga.md: чанки 50KB — только первый доходит

Ложные правки (эта сессия)

  • Dockerfile --limit-request-field_size 0 — бесполезно (Gunicorn не используется)
  • Версия 1.0.4 → 1.0.5 — задеплоено, но проблемы не решает (причина вне кода)

Компоненты инфраструктуры (найдены)

  • Shturval v2.12.1
  • kube-vip (DaemonSet) — VIP для LoadBalancer, IP 185.247.187.151
  • nginx ingress через hostPort (порты 80/443 прямо на ноде)
  • ModSecurity OWASP CRS 4.10.0, SecRuleEngine DetectionOnly
  • SecRequestBodyNoFilesLimit 131072 (128KB) — НЕ причина (внутри кластера работает)

РЕШЕНИЕ

Contracts на этой же ВМ работает потому, что использует родной nginx с proxy_request_buffering off:

# /etc/nginx/sites-enabled/nginx-contracts.conf
location /upload {
    proxy_pass http://127.0.0.1:8766;
    client_max_body_size 100m;
    proxy_request_buffering off;    # ← вот почему работает
}

Для loadtest добавлена аннотация в k8s ingress:

nginx.ingress.kubernetes.io/proxy-request-buffering: "off"

Конфиг применился (подтверждено в /etc/nginx/nginx.conf внутри ingress pod):

proxy_request_buffering off;

Причина

Edge-инфраструктура хостера (NUBES LLC) рвёт TCP-соединения при буферизации больших POST-тел. proxy_request_buffering off стримит тело напрямую в бэкенд — edge не рвёт.