Как JYSK масштабировала мониторинг сети в 3500+ магазинах с Kubernetes и Talos

Мониторить сеть в тысячах магазинов — задача не для слабонервных. 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) упростила бы обновления.

Закажите аудит мониторинга

Даже если у вас нет четкой задачи, мы все обсудим и подскажем.

Узнать больше