Перейти к содержанию

Масштабирование

Архитектура DataHUB рассчитана на широкий диапазон нагрузок — от десятков сообщений в сутки в небольшой инсталляции до сотен сообщений в секунду в крупных промышленных контурах. Статья описывает, как платформа масштабируется, где находятся пределы текущей архитектуры и какие изменения возможны при росте требований.

Текущая модель — вертикальная

В типовой поставке платформа разворачивается на одном сервере (или одной виртуальной машине), на котором запущены все блоки docker-compose. Это подходит для большинства промышленных нагрузок благодаря тому, что критичные компоненты (PostgreSQL, RabbitMQ, Spring Boot) сами по себе масштабируются вертикально очень хорошо.

Подбор ресурсов сервера — линейный по основным метрикам:

Ресурс На что влияет Когда увеличивать
CPU Скорость обработки REST-запросов, парсинг JSON, JWT Растёт RPS на API, упирается в загрузку процессора backend
RAM JVM-heap backend, кеши Caffeine, shared_buffers PostgreSQL, очереди RMQ Растёт OOM, страдает throughput, наступает swap
Диск (IOPS) PostgreSQL и RabbitMQ — оба критичны к IO Растёт I/O wait, очереди RMQ застревают, БД отвечает медленно
Сеть Только при больших объёмах файлового обмена Большие inline-вложения (антипаттерн), мегатрафик с S3

Минимальные требования и рекомендации по железу — в Развертывание / Системные требования.

Где сходятся естественные пределы

В одноузловой схеме потолок упирается обычно в:

  • Длина очередей RabbitMQ. Если consumer'ы клиентов читают медленнее, чем publisher'ы кладут, очереди растут — это не сбой, это нормальное поведение, но в какой-то момент диск кончится. Решение — оптимизация на стороне consumer'ов (масштабирование клиентских модулей) или ограничение скорости отправителей.
  • Размер PostgreSQL. В текущей схеме БД хранит только конфигурацию обмена и пользователей LK — это десятки–сотни МБ даже на крупной инсталляции, потолок маловероятен. Если после выпуска централизованного трекинга сообщений БД начнёт расти за счёт лога — потребуется настроить политику архивации (это будет описано вместе с выпуском фичи).
  • JVM heap backend. При большом количестве одновременных consumer'ов и больших сообщениях память растёт. Лечится — увеличением -Xmx или вынесением части нагрузки.

В реальных эксплуатациях все эти пределы достигаются на разном железе при разных профилях нагрузки — универсальной формулы «после X сообщений нужно масштабировать вверх» нет.

Горизонтальные возможности

Архитектура backend'а допускает горизонтальное масштабирование в нескольких вариантах. Они не входят в типовую поставку, но возможны при необходимости.

Несколько экземпляров backend

Spring Boot stateless по дизайну — авторизация через JWT не хранит сессий, данные хранятся в БД и кешах. Несколько экземпляров backend за одним nginx — рабочая модель:

flowchart LR
    N[nginx] --> B1[backend-1]
    N --> B2[backend-2]
    N --> B3[backend-3]
    B1 & B2 & B3 --> PG[(PostgreSQL)]
    B1 & B2 & B3 --> MQ[RabbitMQ]

Что нужно учесть:

  • Кеши Caffeine локальны для каждого экземпляра. Инвалидация по событию работает в рамках одного процесса. При нескольких экземплярах нужен либо распределённый кеш (Redis, Hazelcast), либо TTL-only-модель (без явной инвалидации, с короткими TTL).
  • RabbitMQSyncService. Несколько экземпляров будут параллельно пытаться синхронизировать топологию. Нужен либо leader election (через DB lock), либо распределение по zones. Сейчас работает на одном экземпляре по умолчанию.
  • Регламентные задания. То же — нужны leader election или Quartz cluster.

В типовой поставке эти препятствия не решаются «из коробки»; для перехода на multi-backend нужна доработка.

Разделение LK и Exchange

LK-контур и Exchange-контур в текущей реализации делят один Spring Boot-процесс (см. Архитектура сервиса). При сильном дисбалансе нагрузки (Exchange сильно нагружен, LK — почти нет) их можно вынести в отдельные приложения с общей БД:

  • backend-exchange — только пакеты com.datahub.exchange.*.
  • backend-lk — только com.datahub.backend.*.

Преимущества: независимое масштабирование, изоляция сбоев (упавший LK не валит обмен), разные SLA на разные домены. Недостатки: усложнение деплоя, два артефакта, общая БД остаётся узким местом.

Это изменение возможно без переделки модели данных — границы пакетов и сейчас чисто разделены.

RabbitMQ — кластеризация и quorum queues

Текущая поставка использует одиночный узел RabbitMQ с classic-очередями. Для повышения доступности возможны два пути:

Classic mirroring (deprecated в RMQ 3.x, удалено в 4.x). Зеркалирование классических очередей на несколько узлов кластера. Просто, но устарело.

Quorum queues. Очереди, основанные на алгоритме Raft, реплицируются на N узлов кластера, переживают потерю до (N-1)/2 узлов. Это современный путь HA для RabbitMQ. Требует:

  • Кластер из минимум 3 узлов RMQ.
  • Параметризации создания очередей в exchange.rabbit.RabbitMQManagementClient (тип очереди + параметр репликации).
  • Перепланирования топологии — quorum queues имеют другие характеристики по производительности на одном узле.

Это изменение архитектурное, не входит в текущую поставку, но реализуемо при выпуске «HA-edition» платформы.

PostgreSQL — реплики и шардинг

Read-replicas (стандартная streaming replication PostgreSQL) могут разгрузить чтение лога доставки и админ-операций. Запись остаётся на primary. Требует доработки backend'а для маршрутизации запросов read/write — Spring Data JPA позволяет это через @Transactional(readOnly=true) и multiple datasource.

Шардинг (Citus, partitioning by tenant) — для очень крупных инсталляций с многими тенантами. В типовом сценарии не нужен; обсуждается отдельно при проектировании конкретного крупного развёртывания.

Кеши

Caffeine — локальный in-memory кеш. На одном экземпляре backend работает отлично; при переходе на multi-backend требует замены на распределённый (Redis, Hazelcast) — иначе инвалидация по событию между экземплярами не работает.

Текущая стратегия — TTL ~ 60 секунд + явная инвалидация. При переходе на TTL-only модель (без инвалидации) задержка между изменением настройки и применением может вырасти, но это допустимо для большинства сценариев.

Файловое хранилище

S3-совместимое хранилище по своей природе горизонтально масштабируемо — это сделано облачными провайдерами или MinIO в кластерном режиме. Backend и шина в файловом обмене не участвуют в горячем пути (см. Файловое хранилище) — отдают только ссылку. Это означает, что рост файлового трафика не нагружает основную инфраструктуру шины, а упирается только в характеристики S3.

Что НЕ масштабируется горизонтально из коробки

  • devops-core — один блок, создаёт сеть dh_network. Не масштабируется и не нужен в множественном числе.
  • nginx — в типовой схеме один. Может быть несколько за внешним балансировщиком (HAProxy, облачный LB), но это уже отдельный сценарий.
  • flyway — одноразовое задание, по определению однократно.
  • pg-agmin — UI-инструмент, в множественном числе не нужен.

Метрики и сигналы для решения о масштабировании

Сигнал Что значит Что делать
CPU backend > 70% устойчиво Нагрузка на API упёрлась в CPU Вертикально (больше CPU) или горизонтально (больше backend-инстансов)
RAM PostgreSQL близко к лимиту shared_buffers + work_mem не помещаются Вертикально (больше RAM) или тюнинг параметров postgresql.conf
Растущая длина очередей RMQ Consumer'ы клиентов отстают Не платформа, а клиенты — масштабируйте на их стороне
IO wait > 30% Диск не справляется SSD/NVMe, отдельный диск под PG, отдельный под RMQ
Длинная задержка между приёмом и доставкой Любая из причин выше По диагностике конкретной точки замедления (см. Диагностика / Производительность)

Что дальше