# Проблема загрузки файлов: диагностика и решение **Дата:** 2026-07-14 --- ## Суть проблемы При передаче данных через HTTP POST из внешней сети на managed-сервисы кластера (Flask и другие) периодически возникала константная задержка **51 секунда**. Проблема проявлялась на любом объёме данных — даже на 100 КБ. Внутри кластера (pod → ingress pod напрямую) передача работала мгновенно. Задержка возникала исключительно при прохождении трафика снаружи через VIP (kube-vip), который распределяет запросы по всем нодам кластера. --- ## Причина **Несоответствие MTU:** канал между серверами — **1450 байт**, а каждый Geneve-туннель добавляет к пакету **50 байт**. При дефолтном MTU пода в 1500 байт любой cross-node-переход через туннель создаёт пакет размером 1550 байт, который не помещается в канал и дропается. Ядро ждёт повторной передачи — отсюда и 51-секундная пауза. В зависимости от того, на каких нодах окажутся поды, запрос проходит через 0, 1 или 2 Geneve-туннеля: | Путь | Туннелей | Размер пакета | Проходит? | |------|----------|---------------|-----------| | Клиент → нода с ingress → drhider на той же ноде | 0 | 1500 б | ✅ | | Клиент → нода с ingress → drhider на другой ноде | 1 | 1500 + 50 = **1550 б** | ❌ | | Клиент → нода без ingress → ingress → drhider | 2 | 1500 + 50 + 50 = **1600 б** | ❌ | Снижение MTU пода до **1400 байт** устраняет проблему: 1400 + 50 = 1450, что точно вписывается в канал на каждом переходе. --- ## Архитектура кластера Кластер `iot-naeel`: 4 ноды (3 worker + 1 control-plane), Cilium с Geneve-энкапсуляцией, kube-vip. ``` Ноды: 6f74n | bhbvs | v8zq4 | control-plane Ingress: 2 пода (Штурвал, всегда на разных нодах) Drhider: 1 под (размещается на случайной worker-ноде) VIP: 185.247.187.151 → kube-vip анонсирует на все 4 ноды через ARP ``` **Маршрут запроса:** браузер → VIP (случайная нода) → kube-proxy → ingress-под → kube-proxy → drhider-под. Каждый переход между нодами — Geneve-туннель (+50 байт). Примеры возможных размещений: | Ситуация | Drhider | Ingress | Туннелей ingress→drhider | |----------|---------|---------|--------------------------| | A | 6f74n | 6f74n + bhbvs | 50% без туннеля, 50% через | | B | bhbvs | 6f74n + v8zq4 | 100% через туннель | | C | v8zq4 | bhbvs + v8zq4 | 50% без туннеля, 50% через | Если клиент попадает на ноду без ingress-пода, kube-proxy добавляет ещё один Geneve-переход. --- ## Тестирование (curl с ВМ, 30 запросов, 63 КБ) **Цель:** подтвердить, что только MTU 1400 работает стабильно при любом размещении подов. | MTU пода | Размещение drhider / ingress | Результат | |----------|------------------------------|-----------| | **1400** | bhbvs / bhbvs + v8zq4 | **30/30** ✅ | | **1400** | 6f74n / 6f74n + bhbvs | **30/30** ✅ | | 1450 | 6f74n / 6f74n + bhbvs | 30/30 (50% без туннеля — повезло) | | 1500 | 6f74n / 6f74n + bhbvs | 30/30 (50% без туннеля — повезло) | | 1500 | v8zq4 / v8zq4 + ctrl | 23/30 | | **1500** | bhbvs / 6f74n + bhbvs | **0/30** ❌ | При MTU 1500 и drhider на bhbvs с ingress на 6f74n+bhbvs — все запросы идут через Geneve, результат 0/30. **Вывод:** MTU 1500 работает только случайно (когда поды оказываются на одной ноде). MTU 1400 — единственно надёжное решение. --- ## Текущая конфигурация (2026-07-14) | Параметр | По умолчанию | Текущее | Причина изменения | |----------|-------------|---------|-------------------| | Cilium `mtu` | 1500 | **1400** | 1400 + 50 (Geneve) = 1450 = underlay | | `proxy-body-size` (ingress) | 8m | **1024m** | Поддержка загрузки файлов до 1 ГБ | | HTTP/2 | включён | включён | — | | `externalTrafficPolicy` | Cluster | Cluster | — | | Реплик ingress | 2 | 2 | — | Код v0.0.22: XHR-таймаут 30 с, cache-busting, обработка SSE `GeneratorExit`.