Files
naeel f6b4fab5c2
Deploy loadtest / validate (push) Has been cancelled
docs: README — project overview, problem, fix, usage
2026-07-11 15:22:13 +04:00

4.1 KiB
Raw Permalink Blame History

loadtest — загрузка файлов через Managed Flask (Shturval)

Тестовый проект для проверки Managed Flask на платформе Shturval 2.12.1. Задача: принять загрузку файлов 3-5 MB через веб-интерфейс стабильно и быстро.

Как работает

  • Фронтенд: HTML + vanilla JS, выбор файлов, прогресс-бар, drag-and-drop
  • Бэкенд: Flask 3.1 + flask-sock (WebSocket) + Gunicorn (gevent worker)
  • Загрузка: WebSocket, 64KB чанки, один connection на все файлы
  • Деплой: git push → Shturval auto-deploy

Проблема: 51-секундный TCP stall

Симптом

Файл 3.7 MB — 90% мгновенно, затем пауза ровно 51 секунда. В ~80% соединений.

Корень

externalTrafficPolicy: Cluster (дефолт) на LoadBalancer-сервисе shturval-ingress-controller-controller. Kube-vip в ARP-режиме форвардил трафик на ноды без локального ingress-пода → cross-node форвардинг через Geneve → TCP zero window oscillation → 51 секунда.

Исправление (платформа)

kubectl patch svc -n ingress shturval-ingress-controller-controller \
  -p '{"spec":{"externalTrafficPolicy":"Local"}}'

kubectl scale deploy -n ingress shturval-ingress-controller-controller --replicas=4

С Local трафик идёт только на ноды с локальными ingress-подами. Cross-node форвардинг исключён.

Что НЕ помогло

  • Flow control на клиенте (bufferedAmount, ACK)
  • Gunicorn вместо Werkzeug
  • nginx keepalive, buffering, таймауты
  • nodeSelector, hostNetwork
  • HTTP POST вместо WebSocket

Внутри кластера всё работало мгновенно — проблема была только при проходе через VIP извне.

Как юзать загрузку

  1. Открыть https://loadtest.pythonk8s.dev.nubes.ru/
  2. Нажать «Выбрать файлы» или перетащить файлы в зону загрузки
  3. Нажать «Загрузить»
  4. Прогресс-бар показывает реальный прогресс
  5. После загрузки — ✓ с временем и скоростью

Поддерживается множественная загрузка (несколько файлов подряд через один WebSocket).

Структура проекта

.
├── Dockerfile              # Gunicorn CMD (не используется Shturval)
├── requirements.txt        # flask, gunicorn, gevent, flask-sock
├── site/
│   ├── app.py              # Flask: /, /health, /upload (HTTP), /ws-upload (WS)
│   ├── static/
│   │   └── app.js          # Клиент: выбор файлов, WebSocket загрузка
│   └── templates/
│       └── index.html      # UI
└── History/                # Полная история расследования
    ├── 2026-07-11-fix-externalTrafficPolicy.md  # Финальный фикс
    ├── 2026-07-11-sonnet-review.md              # Отчёт для ревью
    └── 2026-07-11-review-response.md            # Рецензия и выводы

Выводы для других проектов на Shturval

  1. Managed Flask может принимать большие файлы — после фикса платформы
  2. Всегда проверять «работает ли изнутри кластера» — это изолирует платформу от кода
  3. WebSocket через managed ingress работаетс правильным externalTrafficPolicy
  4. Если платформа не чинится — вынести загрузку на ВМ с родным nginx (как в проекте contracts)

Версия

Текущая: 1.0.25 (baseline WebSocket + Gunicorn gevent)