
Мониторить сеть в тысячах магазинов — задача не для слабонервных. JYSK, датский ритейлер мебели и товаров для дома, известный не только кроватями, но и IT-инновациями, поделился, как они запустили speed-тесты в 3500+ магазинах, используя Kubernetes и Talos. Это история про edge-вычисления, автоматизацию и борьбу с типичными граблями CI/CD. Разбираем, как это работает и что можно взять для ваших проектов.
Контекст
JYSK управляет тысячами магазинов по всему миру, открывая новые точки ежемесячно (в марте 2025 — 9 новых магазинов в 8 странах). Для бесперебойной работы нужна стабильная сеть.
Задача: создать дашборд с метриками скорости, задержки и потерь пакетов для каждого магазина. Выбрали Talos — минималистичный Linux для Kubernetes, идеальный для edge (устройств на периферии, вроде POS-терминалов в магазинах).
Запрос был на визуализацию bandwidth, но готовые инструменты (LibreSpeed, OpenSpeedTest) не подошли из-за ограничений масштабируемости и отсутствия поддержки ручных тестов.
Требования
- Масштаб: тесты из 3500+ магазинов в случайные интервалы, без перегрузки сети (без пиков в мониторинге).
- Метрики: скорость загрузки/выгрузки, задержка, потери пакетов, сравнение за дни/недели.
- Гибкость: ручной запуск тестов для поддержки и операций.
- Надёжность: поддержка параллельных тестов (вероятность коллизий — 11.57%) с ограничением нагрузки.
- Анализ: экспорт данных для сетевого отдела или провайдеров (ISP).
- Условие: минимальное влияние на операции магазинов, без подготовки персонала.
Решение: многопоточный сервер тестирования скорости, клиенты, база данных и дашборд.
Архитектура
Система построена на Kubernetes с Talos на нодах в магазинах. Кастомный сервис speedtest-api-service написан на Golang (клиент и сервер). Данные хранятся в InfluxDB (база данных временных рядов), визуализируются в Grafana. Ключевой компонент — iperf-lb (балансировщик для iperf3): запускает новые процессы по запросу, распределяет сессии по cookie, поддерживая параллельные тесты с ограничением нагрузки.
Как работает:
- Клиент (на нодах Talos): запрашивает расписание у сервера, ожидает теста, принимает ручные триггеры. Выполняет тесты загрузки/выгрузки/пинга (iperf3), отправляет результаты.
- Сервер: прокси для триггеров, хранит расписания, записывает данные в InfluxDB.
- Обновления: клиент периодически проверяет расписание (учитывая рост JYSK).
- Контроль коллизий: iperf-lb и хэширование для равномерного расписания.
Тесты длятся 10 секунд, минимизируя нагрузку на сеть. Это решает задачи CI/CD: автоматизация и прозрачность метрик.

Планировщик
Обеспечивает равномерное распределение тестов.
Сервер:
- API TimeSchedule возвращает расписание и статистику:
type TimeSchedule struct {
Statistics struct {
MeanGap time.Duration `json:"meanGap"`
StdDev time.Duration `json:"stdDev"`
MeanGapText string `json:"meanGapText"`
StdDevText string `json:"stdDevText"`
Count int `json:"count"`
} `json:"statistics"`
Timeslots []Timeslot `json:"timeslots"`
}
type Timeslot struct {
Store string `json:"store"`
Cron string `json:"cron"`
Text string `json:"text"`
}
- Хэширование: FNV-1a распределяет магазины по слотам (modulo числа магазинов). Seed (UUID как int64) обновляется еженедельно для нового расписания:
func hashStoreID(storeID string) (int, error) {
h := fnv.New32a()
_, err := h.Write([]byte(storeID))
if err != nil { return 0, err }
return int(h.Sum32()) % totalStores, nil
}
- Метрики (MeanGap, StdDev) проверяют равномерность.
Клиент:
- Запрашивает расписание каждые несколько минут, использует cron-пакет (с поддержкой секунд, пропуск при выполнении).
- Тест: exec.Command("iperf3", "-c", server, "--json", direction, "-P", "2", "-t", "10"). Результаты парсятся в JSON, отправляются на сервер.
Дашборд
Grafana показывает:
- Обзор: метрики за 30 дней, 95-й перцентиль для выявления аномалий.
- Детализация: скорость, задержка, потери пакетов, средние значения по каждому магазину.

Улучшения
По запросу пользователей добавлен ручной запуск:
- Ingress в Kubernetes и HTTP-роут на Fiber (Golang):
func tryLock(m *sync.Mutex) bool {
if locked { return false }
m.Lock()
locked = true
return true
}
- Роут: app.Get("/api/v1/speedtest", handlers.Speedtest) (409 Conflict при параллельных тестах).
- Интеграция: UI в Store Platform для запуска тестов по GET-запросу.
- Планы: экспорт данных для ISP, API для raw-данных, настройка флагов iperf3.
Результаты
Система автоматизировала мониторинг сети:
- Магазины не были вовлечены, операции не пострадали.
- Решение изменило подход к мониторингу сети.
- Автоматизация обеспечила данные для решений в реальном времени.
Проблемы и уроки:
- Кэширование: iperf3 на Linux/Talos показал расхождения с Windows. Фикс: запуск загрузки перед выгрузкой. Причина не определена (CNI, iperf3, Talos?). Рекомендация: тестировать на разных ОС.
- CI/CD: использование staging-среды на Talos могло бы снизить риски деплоя. Автоматизация через GitOps (например, ArgoCD) упростила бы обновления.


