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

Оценка нагрузочной ёмкости dix.su

Снимок на 2026-07-09. Данные получены с прод-сервера (ssh -p 1022 root@217.114.43.49).


Аппаратная база (VPS)

Параметр Значение
CPU 1 × AMD EPYC (Eng Sample)
RAM 1.9 GB (доступно ~631 MB, ещё ~835 MB в buff/cache)
Диск 30 GB, занято 16 GB (55%), свободно 13 GB
ОС Debian GNU/Linux 12 (bookworm), ядро 6.1
Нагрузка в покое load average 0.03 / 0.09 / 0.08

Текущее потребление ресурсов

Контейнер CPU % RAM
dixu_proxy (Elixir/BEAM) 0.17% 328 MB
modulauth (Java ZGC) 0.29% 386 MB
screenshotter (Node/Playwright) 0.00% 101 MB
postgres 0.02% 52 MB
nginx 0.00% 15 MB
redis 4.07% 10 MB
certbot 0.00% 9 MB
Итого ~4.5% ~901 MB

Redis показывает 4% — это артефакт персистентности (appendonly yes): периодический fsync дискового журнала. В реальном времени Redis практически не нагружен (1 ops/sec, 2 подключения).


Компонентный анализ

nginx

  • Конфигурация: worker_processes auto → при 1 CPU = 1 worker
  • Лимит соединений: worker_connections 1024 (только 1 worker → максимум 1024 одновременных TCP-соединений)
  • TLS: терминируется nginx, certbot обновляет сертификаты Let's Encrypt автоматически
  • E2E-трафик: через stream{} с ssl_preread — не терминируется, слепой relay на dixu_proxy:9443
  • Потолок nginx: 1024 одновременных соединений от внешних клиентов

dixu_proxy (Elixir/Phoenix/BEAM)

  • Erlang-планировщики: 1 (однопоточный планировщик — единственный CPU)
  • Текущее количество процессов: 569 (лимит — 1 048 576)
  • Память BEAM: 478 MB всего, из которых под процессы — 27 MB
  • Порты Erlang: 27 открыто (лимит 65 536)
  • ETS-таблиц: 115
  • Pool базы данных: POOL_SIZE=10 (10 соединений к Postgres)

Каждое подключённое устройство (device_client) = 1 Phoenix-канал = ~5–10 BEAM-процессов. При 27 MB на 569 процессов → ~47 KB/процесс в среднем. Один канал устройства: ~250–500 KB памяти + overhead бинарных данных при активном трафике.

Оценка: ~300–500 одновременно подключённых устройств до достижения RAM-потолка в dixu_proxy.

Ограничивающий фактор для пропускной способности — 1 планировщик BEAM: все сообщения между процессами (http_request_, http_response_ события канала) сериализуются через один поток. I/O (сеть, диск) неблокирующий, но CPU-часть — однопоточная.

modulauth (Spring Boot WebFlux / R2DBC)

  • Потоков JVM: 37 (37 задач в /proc/1/task)
  • Куча: -Xms256m -Xmx768m, GC — ZGC (low-latency)
  • R2DBC: реактивный пул к Postgres (по умолчанию ~10–20 соединений)
  • Реактивная модель: Spring WebFlux не блокирует потоки на I/O; 37 потоков могут обслуживать сотни параллельных HTTP-запросов

Modulauth — не узкое место для пользовательских запросов при текущем масштабе.

PostgreSQL

  • max_connections = 100 (жёсткий потолок)
  • Текущих соединений: 17 (из 100)
  • Использование: dixu_proxy pool = 10, modulauth R2DBC pool ≈ 10–20, системные = 3–5
  • Размер БД: 260 MB
  • Данных в таблицах: фактически минимально (см. n_live_tup — система только начала наполняться)

При max_connections=100 с двумя пулами по 10–20 соединений запас составляет ~50–60 дополнительных соединений. Если добавятся новые компоненты или вырастет нагрузка аналитических запросов — max_connections нужно поднять (в postgresql.conf контейнера или через env).

Redis

  • Использование памяти: 1.18 MB (фактически пуст — только сессии Spring Security)
  • Подключений: 2
  • Операций/сек: ~1 (в покое)
  • Лимит памяти: не задан (maxmemory 0B = unlimited, ограничен только RAM сервера)

Redis — не узкое место даже при росте пользователей на порядок.


Оценка пропускной способности

Одновременно подключённых устройств (device_client)

Ресурс Лимит Текущее Запас
BEAM-процессы 1 048 576 569 ~1 000 000
RAM dixu_proxy ~400 MB свободно 328 MB ~200–400 устройств
Порты Erlang 65 536 27 65 000+
PostgreSQL (pool) 10 соединений ~5–8 ограничен по пропускной способности

Практический потолок: 200–400 одновременно подключённых устройств (ограничен RAM, не лимитами BEAM).

Одновременных активных HTTP-запросов через туннели

Каждый проксированный запрос браузера создаёт короткоживущую цепочку: nginx → dixu_proxy → WS-событие → device_client → local server → обратно. Узкое место — 1 планировщик Erlang:

  • При I/O-dominated нагрузке (запросы быстро уходят на устройство и ждут ответа) планировщик почти свободен — могут одновременно находиться в полёте несколько сотен запросов.
  • При CPU-dominated нагрузке (большие тела, частое кодирование/декодирование base64, роутинг сотен сообщений одновременно) — деградация начинается при ~50–100 активных запросах.

Практическая оценка: 50–150 одновременных запросов без заметной задержки, при условии что каждое устройство отвечает быстро (< 200ms).

Одновременных пользователей браузера

Слой Лимит
nginx (TLS соединения) 1024
modulauth (UI-страницы) несколько сотен (WebFlux неблокирующий)
dixu_proxy (проксирование) 50–150 активных запросов (однопоточный планировщик)

Практический лимит: ~100–300 одновременных пользователей, которые активно проксируют трафик через туннели. Пассивных пользователей (кто смотрит профиль, визитку, каталог — всё идёт через modulauth, минуя dixu_proxy) — значительно больше, до 500+.

TCP-туннели (SSH/RDP/VNC/PostgreSQL/MySQL/Redis/MongoDB)

Каждое TCP-соединение: 1 Erlang-процесс для relay + 1 порт Erlang + ~50 KB RAM.

Ресурс Лимит Оценка запаса
Erlang-порты 65 536 ~65 000 TCP-соединений
RAM ~300–400 MB свободно ~6 000–8 000 соединений (50 KB каждое)
Планировщик 1 деградация при ~500+ активных TCP relay

Практический потолок TCP: ~500–1000 одновременных TCP-соединений.


Текущие узкие места (по приоритету)

1. Единственный CPU / один BEAM-планировщик (критично)

Самое жёсткое ограничение. Erlang отлично масштабируется горизонтально (дополнительные ноды), но вертикально ограничен числом ядер. При нагрузке > 70% CPU latency растёт нелинейно.

Порог тревоги: load average > 0.7 (70% одного ядра). Решение при росте: апгрейд VPS до 2–4 CPU — BEAM немедленно задействует все ядра (schedulers_online = число ядер).

2. PostgreSQL max_connections = 100 (среднесрочно)

При появлении новых компонентов или росте аналитической нагрузки можно упереться. dixu_proxy pool=10 + modulauth pool ≈ 20 = 30 занятых → 70 свободных. Запас умеренный.

Решение при необходимости: добавить PgBouncer (connection pooler) или поднять max_connections до 200–300 в postgres секции docker-compose (command: postgres -c max_connections=200).

3. RAM (1.9 GB) — умеренный запас

~900 MB занято, ~631 MB свободно + 835 MB buff/cache (ОС отдаст при необходимости). screenshotter занимает 101 MB при практически нулевой активности (статический Chromium-процесс). При росте числа устройств dixu_proxy потребует больше памяти.

Порог тревоги: RAM available < 200 MB при нагрузке. Решение: апгрейд до 4 GB RAM (dixu_proxy + modulauth вместе могут использовать 1–1.5 GB при нагрузке).

4. nginx worker_connections = 1024 (долгосрочно)

При 1 worker ограничение 1024 одновременных соединений. При реальном трафике это включает keep-alive соединения браузеров — реальная параллельная обработка меньше.

Решение: worker_connections 4096 или worker_processes 2 (если будет > 1 CPU).


Итоговые цифры

Показатель Текущий потолок Узкое место
Подключённых устройств одновременно 200–400 RAM dixu_proxy
Активных HTTP-запросов через туннель 50–150 1 CPU / BEAM-планировщик
Одновременных пользователей (браузер) 100–300 1 CPU / nginx 1024
TCP-соединений (SSH/RDP/VNC/БД) 500–1000 BEAM-планировщик
PostgreSQL соединений 100 max max_connections=100

Текущий сервер рассчитан на десятки пользователей с несколькими активными устройствами — и справляется с этим с очень низкой нагрузкой (load avg 0.03). Для роста до сотен устройств / тысяч пользователей потребуется апгрейд VPS до минимум 2 CPU + 4 GB RAM.


Рекомендации при масштабировании

Целевой масштаб Что сделать
10–50 устройств, ~500 пользователей/сутки Ничего — текущий VPS справляется
50–200 устройств, ~2000 пользователей/сутки Апгрейд до 2 CPU + 4 GB RAM; worker_connections 4096 в nginx
200–500 устройств, ~10 000 пользователей/сутки 4 CPU + 8 GB RAM; PgBouncer; разнести dixu_proxy и modulauth на отдельные инстансы
500+ устройств / высоконагруженные туннели Кластер Erlang (multi-node BEAM) + несколько nixu_proxy нод; балансировщик перед nginx