Сколько RAM нужно для ZITADEL
ZITADEL позиционируют как cloud-native альтернативу Auth0 и Okta — с мультитенантностью «из коробки», OIDC/SAML и модной event-sourcing архитектурой. Но перед тем как поднимать self-hosted инсталляцию, встаёт практичный вопрос: сколько RAM закладывать в сервер, чтобы не упереться в OOM на первой сотне пользователей и не переплатить за железо, которое простаивает. У ZITADEL здесь есть особенность, которая отличает его от того же Keycloak — сам сервис написан на Go и по памяти лёгкий, а вот база данных под ним может съесть больше, чем ожидаете. Разберём по порядку.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Сколько RAM реально нужно — короткий ответ
Для ориентира по типовым сценариям (ZITADEL + база на одном сервере):
| Сценарий | Пользователей / организаций | RAM для ZITADEL | RAM для БД | Итого на сервер |
|---|---|---|---|---|
| Dev/тест, локальный запуск | до 20 | 128–256 МБ | 256–512 МБ (Postgres) | 1 ГБ |
| Малый self-hosted прод (1 инстанс, PostgreSQL) | до 1000, несколько организаций | 256–512 МБ | 512 МБ – 1 ГБ | 2 ГБ |
| Средний прод (SSO для нескольких приложений, PostgreSQL) | до 10 000 | 512 МБ – 1 ГБ | 1–2 ГБ | 3–4 ГБ |
| Прод с CockroachDB (мультирегион / отказоустойчивость) | 10 000+ | 512 МБ – 1 ГБ на ноду ZITADEL | от 4 ГБ на ноду CockroachDB | от 6 ГБ на весь кластер |
Это ориентир, не гарантия — точное потребление зависит от числа одновременных сессий, интенсивности выпуска и валидации токенов (каждая проверка OIDC access token — это чтение из БД или из кеша проекций), количества организаций и проектов, и от того, включён ли подробный audit trail событий. Главный практический вывод: сам процесс ZITADEL почти никогда не будет узким местом по памяти — на Go-бинарнике это редкость. Узкое место почти всегда база данных, и именно её выбор определяет реальный бюджет RAM.
Из чего складывается потребление памяти у ZITADEL
Архитектура ZITADEL построена на событийном сорсинге (event sourcing) и CQRS: каждое действие — создание пользователя, вход, смена пароли, выпуск токена — записывается как событие в базу, а текущее состояние (кто есть пользователь, какие у него роли) вычисляется через проекции (projections), которые тоже материализуются в БД и частично кешируются в памяти процесса.
Из чего складывается RAM самого ZITADEL-процесса:
- Go runtime и базовый footprint — статически собранный бинарник, без JVM, без отдельного рантайма для загрузки. Стартует за секунды и в простое ест заметно меньше, чем Java-решения вроде Keycloak.
- Кеш проекций и конфигурации — активные организации, проекты, OIDC-клиенты кешируются в памяти для скорости ответа на запросы
/oauth/v2/authorizeи/oidc/v1/token. При росте числа организаций и клиентов кеш растёт, но линейно и не так резко, как realm-кеш в Keycloak. - HTTP/gRPC-слой — ZITADEL отдаёт и REST/gRPC Management API, и OIDC/SAML эндпоинты одним процессом; под нагрузкой держит пул соединений к БД (
ZITADEL_DATABASE_POSTGRES_MAX_OPEN_CONNSи аналоги) — каждое соединение расходует память и на стороне ZITADEL, и на стороне БД. - Очередь фоновых задач (notification, actions) — если включены email/SMS-уведомления или кастомные Actions (JS-скрипты, выполняемые на события), это добавляет небольшой, но ненулевой оверхед.
Отдельно и почти всегда весомее — сама база данных, о которой ниже.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверDocker Compose: ZITADEL + PostgreSQL с ограничением памяти
Для self-hosted инсталляции среднего размера рабочий минимальный конфиг с PostgreSQL:
services:
zitadel:
image: ghcr.io/zitadel/zitadel:v2.63
command: start-from-init --masterkey "${ZITADEL_MASTERKEY}" --tlsMode disabled
environment:
ZITADEL_DATABASE_POSTGRES_HOST: postgres
ZITADEL_DATABASE_POSTGRES_PORT: "5432"
ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel
ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel
ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: "${ZITADEL_DB_PASSWORD}"
ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable
ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: postgres
ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: "${ZITADEL_DB_ADMIN_PASSWORD}"
ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable
ZITADEL_EXTERNALSECURE: "true"
ZITADEL_EXTERNALDOMAIN: sso.example.com
deploy:
resources:
limits:
memory: 768m
reservations:
memory: 256m
ports:
- "8080:8080"
depends_on:
- postgres
restart: unless-stopped
postgres:
image: postgres:16
environment:
POSTGRES_DB: zitadel
POSTGRES_USER: postgres
POSTGRES_PASSWORD: "${ZITADEL_DB_ADMIN_PASSWORD}"
volumes:
- zitadel_db:/var/lib/postgresql/data
deploy:
resources:
limits:
memory: 1.5g
restart: unless-stopped
volumes:
zitadel_db:
На средний прод такой связке (768 МБ на ZITADEL + 1.5 ГБ на Postgres) достаточно с запасом. Обратите внимание: start-from-init используется только при первом запуске для инициализации схемы — дальше переключайтесь на обычный start с теми же переменными окружения, чтобы не гонять миграции при каждом рестарте контейнера.
Официальный образ также умеет читать конфиг из YAML-файла (--config /path/to/config.yaml) вместо длинного списка переменных окружения — удобнее, когда параметров становится много, но по потреблению памяти разницы нет, это только про удобство конфигурации.
CockroachDB vs PostgreSQL: что выбрать и как это меняет бюджет RAM
Это ключевое архитектурное решение, которое сильнее всего влияет на итоговый расход RAM. Исторически ZITADEL проектировался под CockroachDB — распределённую SQL-базу с сильной консистентностью, которая нужна была для гарантий event-sourcing модели в мультирегиональных инсталляциях. Поддержка PostgreSQL добавлена позже и сейчас — стандартный выбор для большинства self-hosted инсталляций, включая рекомендации самого проекта для типовых сценариев.
Разница по памяти ощутимая:
- PostgreSQL — предсказуемая, экономная по памяти база. Для типовой self-hosted инсталляции достаточно 512 МБ – 2 ГБ в зависимости от нагрузки (см. таблицу выше), настройки
shared_buffersиwork_memподбираются так же, как для любого другого сервиса на Postgres. - CockroachDB — распределённая база, спроектированная под кластер из нескольких нод с репликацией. У неё заметно выше базовый аппетит к памяти даже в single-node режиме — официальные рекомендации CockroachDB для стабильной работы называют от 4 ГБ RAM на ноду, и это без учёта нагрузки от самого ZITADEL. В single-node конфигурации (без реальной отказоустойчивости, которую CockroachDB и даёт) вы платите memory-оверхедом распределённой системы, не получая её главного преимущества.
Практический вывод: если вам не нужна мультирегиональная отказоустойчивость на уровне БД, для self-hosted ZITADEL выбирайте PostgreSQL — вы получите ту же функциональность продукта при заметно меньшем бюджете RAM. CockroachDB имеет смысл закладывать, только если вы действительно строите географически распределённый кластер с несколькими нодами БД и готовы платить за это ресурсами каждой ноды. Подробнее про настройку самой PostgreSQL — в статье про установку PostgreSQL на VPS и про тюнинг PostgreSQL под нагрузку.
Тюнинг Go-рантайма: GOGC и GOMEMLIMIT
В отличие от Keycloak, где тюнинг памяти — это -Xms/-Xmx для JVM heap, у ZITADEL (как у любого Go-приложения) память контролируется через переменные окружения Go-рантайма:
environment:
GOGC: "75"
GOMEMLIMIT: "700MiB"
GOGC— определяет, насколько агрессивно работает сборщик мусора относительно роста живых объектов в памяти. Дефолт — 100. Понижение до 50-75 заставляет GC срабатывать чаще и держать пиковое потребление ниже ценой небольшого прироста нагрузки на CPU — разумный компромен на память-ограниченном VPS.GOMEMLIMIT— soft-лимит общей памяти рантайма (появился в Go 1.19+). В отличие отGOGC, это не «доля от роста», а абсолютный потолок, к которому Go старается подстроить агрессивность сборки мусора. Ставьте его немного ниже, чем лимит контейнера (deploy.resources.limits.memory), чтобы GC успевал реагировать до того, как контейнер поймает OOMKilled от ядра.
На практике для среднего прод-сценария связка GOMEMLIMIT чуть ниже лимита Docker-контейнера и стандартный GOGC — самый безопасный старт; играть с понижением GOGC имеет смысл, только если мониторинг показывает, что процесс регулярно подходит к лимиту памяти при нормальной нагрузке.
Признаки нехватки RAM и как их поймать
Три типичных сигнала, что памяти не хватает — либо самому ZITADEL, либо (чаще) базе под ним:
- Контейнер ZITADEL или Postgres уходит в
OOMKilled— проверяется командойdocker inspect <container> --format='{{.State.OOMKilled}}'. Если это Postgres — почти всегда причина вshared_buffersилиwork_mem, выставленных без учёта реального лимита контейнера, либо в резком росте числа одновременных соединений от ZITADEL при пиковой нагрузке. - Рост латентности на
/oidc/v1/tokenи/oauth/v2/authorizeпод нагрузкой — если запросы на выпуск и проверку токенов начинают заметно тормозить при росте RPS, это часто не CPU, а нехватка кеша проекций в памяти: ZITADEL начинает чаще ходить в БД за данными, которые в норме отдал бы из кеша. - Постоянный рост RSS процесса без стабилизации — понаблюдайте
docker statsили системный мониторинг за несколько часов под ровной нагрузкой. Если память растёт монотонно и не выходит на плато — это повод проверитьGOMEMLIMIT/GOGCи версию образа (в некоторых промежуточных релизах фиксировались утечки, которые закрывались патч-версиями — стоит держать актуальную минорную версию).
Для постоянного контроля памяти на сервере в целом полезно поднять базовый мониторинг — например, Grafana и Prometheus по шагам, с алертом на приближение к лимиту контейнера. Общие правила по лимитам CPU и памяти в Docker разобраны в статье про ресурсы и лимиты контейнеров, а если сервер в целом упирается в память — общий чек-лист есть в статье что делать при нехватке RAM. Если ZITADEL стоит за reverse-proxy (а в проде это почти всегда так из-за TLS-терминации) — практическая настройка описана в статье Nginx как reverse proxy.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
ZITADEL действительно легче Keycloak по памяти?
Сам процесс ZITADEL — да, заметно легче: Go-бинарник против JVM-приложения на Quarkus, без heap-разогрева и метаспейса классов. Но итоговая экономия сильно зависит от базы данных — если сравнивать ZITADEL с PostgreSQL против Keycloak с PostgreSQL, разница в первую очередь в самом сервисе identity-провайдера, и она в пользу ZITADEL. Сравнение по Keycloak — в статье сколько RAM нужно для Keycloak.
Хватит ли 1 ГБ RAM для прод-инсталляции ZITADEL?
Для небольшого прода с PostgreSQL на том же сервере — впритык, но реально: закладывайте 256-512 МБ на ZITADEL и 512 МБ на Postgres плюс запас под ОС. Для комфортной работы под реальным трафиком безопаснее закладывать от 2 ГБ суммарно.
Нужна ли CockroachDB для self-hosted инсталляции?
В большинстве случаев нет. CockroachDB нужна, когда вам критична отказоустойчивость на уровне БД в распределённом кластере из нескольких дата-центров. Для одного сервера или пары нод PostgreSQL даёт ту же функциональность ZITADEL при заметно меньшем расходе RAM.
Растёт ли память ZITADEL с числом организаций (мультитенантность)?
Растёт, но умеренно — кешируются метаданные активных организаций и их OIDC-клиентов, а не полный слепок данных каждого тенанта. Для десятков и даже сотен организаций с разумным числом клиентов в каждой прирост по памяти не станет доминирующим фактором — куда сильнее на бюджет влияет число одновременных активных сессий и интенсивность обращений к токен-эндпоинту.
Можно ли уменьшить память без потери функциональности?
Да: выставьте GOMEMLIMIT и, при необходимости, понизьте GOGC, отключите ненужные фоновые Actions и уведомления, ограничьте пул соединений к БД (ZITADEL_DATABASE_POSTGRES_MAX_OPEN_CONNS) до значения, реально нужного под вашу нагрузку — избыточный пул соединений держит память впустую и с обеих сторон.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →