Files
drhider/PROBLEM-AND-SOLUTION.md
T
2026-07-16 12:24:47 +04:00

136 lines
5.7 KiB
Markdown
Raw 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-16
**Версия приложения:** v0.0.31
**Кластер:** `iot-naeel` (4 ноды, Cilium Geneve, kube-vip, Штурвал)
---
## Проблема 1: 51-секундная задержка (MTU)
### Суть
При передаче POST из внешней сети — пауза 51с на любом объёме данных. Внутри кластера — мгновенно.
### Причина
Underlay MTU = 1450. Cilium Geneve добавляет 50 байт. Дефолтный MTU пода = 1500.
Cross-node пакет = 1500+50 = 1550 → фрагментация → дроп → ядро ждёт повторной передачи 51с.
### Решение
`cilium-config``mtu: 1400`. 1400+50 = 1450 = underlay.
Задокументировано 2026-07-13, применено 2026-07-14.
---
## Проблема 2: ERR_CONNECTION_RESET после фикса MTU
### Суть
curl с ВМ работает. Браузер — `ERR_CONNECTION_RESET` или `⏳ 100%`.
После `rollout restart` ingress — работает 5-10 минут, потом снова RST.
### Ложные следы (опровергнуты)
| Гипотеза | Почему неверна |
|----------|---------------|
| kube-vip ARP flapping | `kube-vip.io/vipHost: control-plane` — VIP жёстко на одной ноде |
| hostPort на 2 из 4 нод | Трафик только на control-plane, не на все 4 |
| upstream keepalive stale | `upstream-keepalive-connections: 0` не помог |
| conntrack | ETPolicy Cluster не при чём — трафик на одну ноду |
| MTU | Решено в проблеме 1 |
| HTTP/2 | `ERR_HTTP2_PROTOCOL_ERROR` → отключили → `ERR_CONNECTION_RESET` — симптом тот же |
### Истинная причина
**`keep-alive: 10`** — Штурвал ставил nginx `keep-alive: 10` (вместо дефолта 75).
Сценарий:
1. Браузер грузит страницу — TCP открыт
2. Пользователь выбирает файлы (>10с) — nginx закрывает idle соединение
3. Браузер не замечает FIN (буферизация ОС)
4. POST 63KB летит в закрытый сокет → TCP RST
### Решение (применено в платформе Штурвала 2026-07-15)
Через `ShturvalServiceConfig` (не kubectl — ArgoCD откатывает):
```yaml
controller:
config:
keep-alive: "75"
proxy-body-size: "1024m"
client-body-timeout: "60"
client-header-timeout: "30"
hostPort:
enabled: true
replicaCount: 2
service:
type: LoadBalancer
```
Также в коде — `fetch('/health')` при загрузке страницы (прогрев upstream).
### v0.0.30 — .doc в диалоге выбора файлов
Добавлен `accept=".doc,.docx,.pdf,.txt,.zip"` в `<input type="file">`.
`doc_to_markdown()` переписан: вместо `soffice` (LibreOffice на ВМ) — HTTP-вызов `liberta.containerk8s.dev.nubes.ru/convert` через `httpx`.
### v0.0.31 — .doc обрабатывается обфускацией
`.doc` теперь не просто конвертируется, а проходит полную обфускацию (замена сущностей, mapping.csv). В архиве — `.md` с заменённым текстом, не исходный `.doc`.
### Результаты тестов (v0.0.29, 2026-07-15)
| Тест | Результат |
|------|-----------|
| 10× POST 63KB (свежие страницы) | **10/10 OK:200** |
| UI: 5 файлов + SSE + ZIP + CSV | ✅ полный цикл |
| 5× POST через 75с (keep-alive окно) | **5/5 OK:200** |
| 5MB PDF через curl | ✅ 200 OK, 0.62с |
| **ИТОГО** | **25/25 успешно, 0 RST** |
---
## Итоговая конфигурация кластера
### Ingress (через платформу Штурвала, несбрасываемо ArgoCD)
| Параметр | Дефолт nginx | Было (Штурвал) | Сейчас |
|----------|-------------|----------------|--------|
| `keep-alive` | 75 | **10** | **75** |
| `proxy-body-size` | 8m | 8m | **1024m** |
| `client-body-timeout` | 60 | **10** | **60** |
| `client-header-timeout` | 60 | **10** | **30** |
| `use-http2` | true | true | **false** |
| `upstream-keepalive-connections` | 0 | 50 | 0 |
| `error-log-level` | info | info | **debug** (вернуть info) |
### Cilium (через kubectl, не сбрасывается)
| Параметр | Дефолт | Сейчас |
|----------|--------|--------|
| `mtu` | 1500 | **1400** |
### Приложение (drhider v0.0.29)
```python
# site/app.py
VERSION = "0.0.29"
app.config["MAX_CONTENT_LENGTH"] = 200 * 1024 * 1024 # 200 MB
```
```javascript
// site/templates/index.html — warmup при загрузке
window.addEventListener('load', () => {
sf = []; fi.value = ''; rr();
fetch('/health').catch(() => {}); // прогрев upstream
});
```
---
## Документация
| Файл | Что |
|------|-----|
| `docs/ARCHITECTURE.md` | Архитектура + требования к Flask |
| `docs/MIGRATION-GUIDE.md` | Инструкция переноса UI на Flask |
| `History/2026-07-14-browser-rst-debug.md` | Полная история диагностики RST |
| `History/2026-07-15-rst-root-cause.md` | Финальный диагноз |
| `History/2026-07-15-cluster-dump.md` | Дамп кластера |
| `STATE-2026-07-15.md` | Состояние проекта на 2026-07-15 |