MAATRIX / Блог / Сколько RAM нужно для GrowthBook

Сколько RAM нужно для GrowthBook

MAATRIX

GrowthBook выделяется среди open-source feature-flag платформ тем, что не хранит у себя результаты экспериментов — он читает их прямо из вашего хранилища аналитики (Postgres, ClickHouse, BigQuery и так далее). Из-за этого вопрос "сколько RAM закладывать" звучит обманчиво просто: сам GrowthBook действительно лёгкий, но часть нагрузки прячется не в контейнере с приложением, а в момент, когда он тянет и агрегирует данные для расчёта эксперимента. Разберём, из чего складывается память self-hosted GrowthBook, какие цифры закладывать под разный масштаб и как не упереться в OOM именно в момент построения отчёта по эксперименту, а не при обычной работе с флагами.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Архитектура GrowthBook: что реально ест память

Self-hosted GrowthBook — это не один процесс, а минимум два компонента, и считать RAM нужно по обоим:

  • growthbook (app) — образ growthbook/growthbook, который объединяет в одном контейнере API-сервер и веб-интерфейс (Next.js/Node.js). Именно здесь живут расчёты статистики по экспериментам, авторизация, вебхуки и раздача feature-флагов SDK по HTTP;
  • MongoDB — единственное поддерживаемое хранилище метаданных: проекты, определения флагов, конфигурации экспериментов, метрик, сегментов, пользователи и API-ключи. Сырые события пользователей здесь не хранятся;
  • GrowthBook Proxy (опционально) — отдельный лёгкий Node.js-сервис, который кэширует payload с флагами и раздаёт его SDK через SSE, снимая нагрузку с основного app-контейнера; разберём его отдельно ниже.

Ключевое отличие GrowthBook от инструментов вроде LaunchDarkly или self-hosted Unleash: он не собственная time-series база для аналитики, а надстройка над вашим data warehouse. Когда вы открываете отчёт по эксперименту, GrowthBook формирует SQL-запрос, отправляет его в ваш Postgres/ClickHouse/BigQuery/Snowflake, получает уже агрегированные по вариантам метрики (среднее, дисперсия, количество юнитов) и досчитывает статистику (байесовский или частотный движок) внутри Node.js-процесса. Именно этот момент — а не хранение флагов — главный источник кратковременных всплесков памяти у app-контейнера.

Второй фактор роста памяти — количество одновременно подключённых SDK. Как и у большинства feature-flag платформ, каждый бэкенд-сервис с SDK периодически опрашивает /api/features/<client-key> либо держит открытое SSE-соединение для realtime-обновлений (streaming включается флагом SSE). Сотни держащихся соединений на один app-контейнер — это сотни файловых дескрипторов и буферов, которые тоже отражаются на RSS процесса.

Сколько RAM нужно: ориентиры по масштабу

Официальные требования GrowthBook для быстрого старта в docker-compose скромные — сервис поднимается и на паре гигабайт свободной памяти хоста в сумме с MongoDB. Но это стартовая точка для знакомства, а не гарантия для боевой нагрузки с активными экспериментами и десятками подключённых SDK. Ориентируйтесь на цифры ниже, а по факту сверяйтесь с docker stats — при больших дашбордах с множеством дименшенов потребление может быть заметно выше.

Профиль использованияЭкспериментов / флаговПодключённых SDKRAM на appRAM на MongoDBИтого сервер
Тест / один разработчикдо 5до 5512 МБ256 МБ1–1,5 ГБ
Стартап, один продукт5–205–30512 МБ–1 ГБ512 МБ2 ГБ
Средняя команда, активная аналитика20–10030–1501–2 ГБ1 ГБ4 ГБ
Несколько команд, тяжёлые отчёты (дименшены, CUPED, квантильные метрики)100+150–5002–4 ГБ1–2 ГБ6–8 ГБ
Крупная инсталляция, Proxy-слой под SDK100+500+2–4 ГБ на app + отдельно Proxy2 ГБ+8 ГБ+

Важный нюанс из архитектуры: рост числа экспериментов сам по себе почти не влияет на базовое потребление — метаданные каждого эксперимента это несколько КБ в MongoDB. RAM растёт от одновременной активности: сколько отчётов открыто прямо сейчас, сколько в них дименшенов и метрик, и сколько SDK висит на API. Пустой, но большой архив завершённых экспериментов почти не заметен в памяти app-контейнера.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Docker Compose с явными лимитами памяти

Официальный быстрый старт GrowthBook — это docker-compose с двумя сервисами. Ниже — тот же набор, но с явными лимитами, чтобы контейнер падал предсказуемо, а не забирал всю память хоста:

services:
  mongo:
    image: mongo:7
    restart: unless-stopped
    volumes:
      - growthbook_mongo_data:/data/db
    mem_limit: 768m
    mem_reservation: 384m
    command: ["--wiredTigerCacheSizeGB", "0.25"]

  growthbook:
    image: growthbook/growthbook:latest
    restart: unless-stopped
    ports:
      - "3000:3000"
      - "3100:3100"
    depends_on:
      - mongo
    environment:
      MONGODB_URI: "mongodb://mongo:27017/growthbook"
      APP_ORIGIN: "https://gb.example.com"
      API_HOST: "https://gb.example.com:3100"
      JWT_SECRET: "${GROWTHBOOK_JWT_SECRET}"
      ENCRYPTION_KEY: "${GROWTHBOOK_ENCRYPTION_KEY}"
      NODE_OPTIONS: "--max-old-space-size=768"
    mem_limit: 1g
    mem_reservation: 512m
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:3100/healthcheck"]
      interval: 15s
      timeout: 5s
      retries: 5

volumes:
  growthbook_mongo_data:

Пример рассчитан на профиль "стартап, один продукт": 1 ГБ на app, 768 МБ на MongoDB с явно ограниченным WiredTiger-кэшем, плюс запас под ОС и файловый кэш — сервер под это стоит брать от 2,5–3 ГБ, а не ровно сумму лимитов. Порт 3000 — веб-интерфейс, 3100 — API, к которому ходят SDK; за внешним доступом обычно ставят обратный проксі с SSL, шаги для этого разобраны в статье про Nginx как reverse proxy на VPS. Если MongoDB уже крутится у вас отдельно под другие сервисы, отдельный контейнер под неё не обязателен — шаги установки чистого инстанса разобраны в статье про установку MongoDB на VPS.

Расчёт экспериментов: почему statistics engine ест больше, чем кажется

Самая частая ошибка при sizing GrowthBook — заложить память только под "хранение флагов" и не учесть момент открытия тяжёлого отчёта. Когда пользователь открывает вкладку с результатами эксперимента, происходит следующее:

  1. GrowthBook строит SQL-запрос под конкретный движок вашего warehouse (диалект для BigQuery отличается от диалекта для ClickHouse) и агрегирует данные на стороне базы — сырые события в Node.js-процесс не тянутся, это важное архитектурное решение;
  2. в ответ приходит таблица с агрегатами: по одной строке на комбинацию вариант × метрика (а если включены дименшены — то ещё умноженная на число значений дименшена);
  3. дальше расчёт байесовской или частотной статистики, доверительных интервалов и (если включено) CUPED-коррекции выполняется уже внутри самого app-процесса на Node.js.

На шаге 2 объём данных, который реально попадает в память, растёт не с числом пользователей в эксперименте, а с произведением количества вариантов, метрик и уникальных значений дименшена. Отчёт с 2 вариантами и 5 метриками — это десятки строк. Тот же эксперимент с разбивкой по дименшену "страна" на 190 значений и квантильными метриками (которые требуют больше агрегатов, чем простое среднее) — это уже тысячи строк одновременно, и заметный кратковременный всплеск RSS у app-контейнера именно в момент открытия отчёта, а не постоянная фоновая нагрузка.

Если у вас mem_limit выставлен впритык по таблице выше, а команда активно использует дименшены и метрики с квантилями, добавьте к app-контейнеру запас 30-50% сверх базового профиля — иначе открытие тяжёлого отчёта несколькими аналитиками одновременно может уронить процесс в рабочий момент, а не при обычной раздаче флагов.

MongoDB: сколько памяти и диска закладывать под метаданные

MongoDB в GrowthBook хранит только конфигурацию — сами флаги, определения экспериментов и метрик, аудит-лог изменений и кэш последних результатов, которые пользователь уже открывал. Это на порядки меньше, чем сырые события аналитики, поэтому даже у организаций с сотней активных экспериментов база редко превышает пару гигабайт на диске.

Единственный параметр, который стоит держать под контролем явно — размер WiredTiger-кэша, который по умолчанию MongoDB считает как половину доступной хосту памяти минус 1 ГБ. На небольшом VPS с общим объёмом RAM 2-4 ГБ, где Mongo делит хост с app-контейнером, это может оказаться слишком щедрым дефолтом и вытеснить память у соседних процессов. Ограничивайте кэш явно:

command: ["--wiredTigerCacheSizeGB", "0.25"]

Или через конфиг-файл mongod.conf:

storage:
  wiredTiger:
    engineConfig:
      cacheSizeGB: 0.25

Если сталкиваетесь с ростом потребления памяти или странным поведением самого MongoDB под нагрузкой — частые причины и их устранение разобраны в статье про типичные ошибки MongoDB на сервере. Для продакшена MongoDB стоит бэкапить регулярно — это единственная точка отказа, которая хранит все ваши флаги и настройки экспериментов.

GrowthBook Proxy: масштабирование под тысячи SDK-клиентов

Пока речь идёт о десятках-сотнях серверных SDK, основной app-контейнер справляется сам — polling раз в 30-60 секунд не создаёт заметной нагрузки. Ситуация меняется, если у вас включён streaming (SSE) и клиентов — тысячи, особенно если это frontend-SDK в браузерах пользователей, а не бэкенд-сервисы: каждое такое соединение держится открытым, и app-процесс начинает тратить память и файловые дескрипторы просто на то, чтобы удерживать эти сокеты.

Для этого случая GrowthBook предлагает отдельный компонент — GrowthBook Proxy, лёгкий Node.js-сервис (образ growthbook/proxy), который разворачивается ближе к клиентам, кэширует уже готовый payload с флагами в памяти и сам обслуживает SSE-подключения, синхронизируясь с основным app по вебхуку при изменении флагов:

  growthbook-proxy:
    image: growthbook/proxy:latest
    restart: unless-stopped
    ports:
      - "3300:3300"
    environment:
      GROWTHBOOK_API_HOST: "http://growthbook:3100"
      PROXY_KEY: "${GROWTHBOOK_PROXY_SECRET}"
    mem_limit: 256m
    mem_reservation: 128m

Ориентировочно один инстанс Proxy с лимитом 256 МБ держит заметно больше одновременных SSE-подключений, чем основной app-контейнер с тем же лимитом, — он не считает статистику экспериментов и не рендерит админку, а только раздаёт закэшированный JSON. Добавлять Proxy имеет смысл, когда в docker stats вы видите синхронный рост памяти app-контейнера с ростом числа подключений на порт 3100, а не с ростом числа флагов или экспериментов в проекте — это надёжный сигнал, что дело в SDK-трафике, а не в конфигурации.

Как отслеживать реальное потребление памяти

Прикидки по таблице — только стартовая точка, дальше сервер нужно наблюдать по факту, особенно вокруг моментов открытия тяжёлых отчётов. Быстрый способ — штатный docker stats:

docker stats growthbook mongo --no-stream

Полезно сопоставить это с логами app-контейнера в момент открытия отчёта по эксперименту — если видите там ошибки таймаута запроса к вашему warehouse одновременно со скачком RSS, скорее всего дело именно в объёме агрегатов, а не в утечке памяти:

docker logs growthbook --since 5m | grep -i "error\|timeout"

Общие принципы работы с лимитами и mem_limit/mem_reservation в Docker Compose подробнее разобраны в статье про лимиты CPU и памяти в Docker, а если сервер уже ушёл в OOM и нужно быстро понять, что делать — общий подход к диагностике на VPS разобран в статье что делать при нехватке RAM.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли запустить GrowthBook на 1 ГБ RAM?

Формально да, для одиночного разработчика с парой флагов и без активных отчётов — это тестовый профиль. С MongoDB на том же сервере комфортнее закладывать от 1,5-2 ГБ суммарно, иначе первый же тяжёлый отчёт с дименшенами рискует упереться в лимит.

Что ест больше памяти — сам GrowthBook или MongoDB?

На небольшом масштабе почти всегда app-контейнер, особенно в моменты открытия отчётов. MongoDB хранит только метаданные и редко становится узким местом, если у вас не тысячи экспериментов с длинной историей аудит-лога.

Нужен ли GrowthBook Proxy с самого начала?

Нет, для инсталляций с несколькими серверными SDK Proxy не нужен — app справляется сам. Добавляйте его, когда счёт подключений идёт на сотни-тысячи, особенно с включённым SSE-streaming и frontend-SDK из браузеров.

GrowthBook хранит у себя данные пользователей из экспериментов?

Нет — сырые события остаются в вашем хранилище аналитики (Postgres, ClickHouse, BigQuery и т.д.), GrowthBook лишь отправляет туда запросы и получает агрегаты. Поэтому объём накопленных данных экспериментов почти не влияет на его память.

Стоит ли сравнивать GrowthBook с Unleash по требованиям к памяти?

Базовые профили похожи — оба легковесны на старте и растут в основном от числа подключённых SDK. Разница в пиках: у GrowthBook добавляется всплеск в момент расчёта статистики по экспериментам. Сравнение — в статье сколько RAM нужно для Unleash.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →