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

98 lines
4.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`:
```nginx
# /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 не рвёт.