Сколько RAM нужно для Keycloak
Keycloak — это не лёгкий сервис вроде статического сайта: под капотом Java-приложение на Quarkus с собственным heap, кешем сессий в памяти и (в кластере) репликацией через Infinispan. Взять минимальный VPS «на глазок» и упереться в OOMKilled на второй день — типичная история. Разберём, сколько RAM реально нужно под разные сценарии, из чего складывается потребление и как не переплатить за железо, которое не используется.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Сколько RAM реально нужно — короткий ответ
Если совсем коротко, для типовых сценариев:
| Сценарий | Пользователей / активных сессий | RAM для Keycloak | vCPU |
|---|---|---|---|
| Dev/тест, локальная разработка | до 50 | 512 МБ – 1 ГБ | 1 |
| Малый прод (один сервис, внутренняя команда) | до 1000, ~50-100 онлайн | 1.5–2 ГБ | 1-2 |
| Средний прод (SSO для нескольких приложений) | до 10 000, ~500-1000 онлайн | 3–4 ГБ | 2 |
| Крупный прод / кластер из 2-3 нод | 50 000+, несколько тысяч онлайн | 4–6 ГБ на ноду | 2-4 |
Это ориентир, а не гарантия — реальное потребление зависит от количества клиентов (client registrations), кастомных SPI-плагинов, длины сессии (session timeout) и того, включён ли полный аудит событий. Если у вас 20 реалмов с сотнями клиентов в каждом — закладывайте больше даже при малом числе пользователей, потому что метаданные конфигурации тоже живут в памяти и кешируются.
Отдельно закладывайте память под саму базу данных (обычно PostgreSQL) — она либо на этом же сервере, либо на соседнем. Про это ниже отдельным разделом.
Из чего складывается потребление памяти
Keycloak с версии 17+ работает на Quarkus (раньше был WildFly), и его память делится на несколько частей:
- JVM heap — где живут объекты приложения: обработка запросов, кеш realm-конфигурации, in-memory кеши Infinispan (user cache, realm cache, authorization cache).
- Off-heap / native память — метаспейс классов, буферы Netty (HTTP-сервер), JIT-компиляция. У Quarkus native-образа off-heap меньше, чем у JVM-образа, но JVM-образ (по умолчанию в официальном Docker-образе
quay.io/keycloak/keycloak) стабильнее и предсказуемее под нагрузкой — большинство прод-инсталляций используют именно его. - Кеш сессий пользователей (user sessions cache) — растёт линейно с числом одновременно залогиненных пользователей. Каждая активная сессия занимает небольшой, но ненулевой объём — при десятках тысяч онлайн-сессий это заметная доля heap.
- Кеш реалмов и клиентов (realm/client cache) — конфигурация всех realm, clients, roles, groups кешируется в памяти для скорости. Если у вас один реалм с 20 клиентами — это копейки. Если 100 реалмов с сотнями клиентов каждый (мультитенантная схема) — счёт идёт на сотни МБ.
По умолчанию контейнерный образ Keycloak сам определяет heap как долю от лимита памяти контейнера (через -XX:MaxRAMPercentage), так что если вы просто зададите mem_limit в Docker Compose без явного heap — Keycloak подстроится, но лучше настраивать явно (см. раздел про JVM-тюнинг).
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверDocker Compose и ограничение памяти контейнера
Рабочий минимальный конфиг для отдельного Keycloak с внешней PostgreSQL — под средний прод:
services:
keycloak:
image: quay.io/keycloak/keycloak:26.0
command: start --optimized
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: ${KC_DB_PASSWORD}
KC_HOSTNAME: sso.example.com
KC_PROXY_HEADERS: xforwarded
KC_HTTP_ENABLED: "true"
JAVA_OPTS_APPEND: "-Xms512m -Xmx2048m"
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD}
deploy:
resources:
limits:
memory: 2.5g
reservations:
memory: 1g
ports:
- "8080:8080"
depends_on:
- postgres
restart: unless-stopped
postgres:
image: postgres:16
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: ${KC_DB_PASSWORD}
volumes:
- keycloak_db:/var/lib/postgresql/data
deploy:
resources:
limits:
memory: 1g
restart: unless-stopped
volumes:
keycloak_db:
Обратите внимание: лимит контейнера (memory: 2.5g) всегда должен быть больше, чем -Xmx (2048m), потому что помимо heap контейнеру нужна память под метаспейс, стеки потоков и буферы Netty — обычно закладывают запас 400-600 МБ сверх -Xmx. Если поставить лимит контейнера впритык к heap, вы получите OOMKilled даже при нормальной нагрузке на heap.
Команда start --optimized предполагает, что образ уже собран (kc.sh build) с нужными фичами — это экономит и память, и время старта по сравнению с start-dev, который держит лишние dev-инструменты и не оптимизирован под прод.
JVM-тюнинг heap под Keycloak
Два ключевых параметра — -Xms (стартовый heap) и -Xmx (максимальный heap). Практика:
- Dev/малый прод:
-Xms256m -Xmx1024m - Средний прод:
-Xms512m -Xmx2048m - Крупный прод / кластер:
-Xms1024m -Xmx4096mна ноду
Задаются через переменную JAVA_OPTS_APPEND в официальном образе (не перезаписывайте JAVA_OPTS напрямую — так вы снесёте дефолтные настройки образа, которые включают нужные модули и G1GC).
Полезные дополнительные флаги для стабильности под нагрузкой:
JAVA_OPTS_APPEND: "-Xms512m -Xmx2048m -XX:+ExitOnOutOfMemoryError -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m"
-XX:+ExitOnOutOfMemoryError — важная штука: без неё Java-процесс при OutOfMemoryError может «зависнуть» в нерабочем состоянии, но не упасть, и оркестратор (Docker/systemd) не поймёт, что нужен рестарт. С этим флагом процесс падает сразу, и restart: unless-stopped (или Restart=on-failure в systemd) поднимает его заново — быстрее приходите в рабочее состояние, чем разбираться руками почему сервис «висит, но не отвечает».
Если держите Keycloak через systemd без Docker, аналогичные флаги передаются через KC_JAVA_OPTS в unit-файле или standalone.conf в зависимости от версии — детали смотрите в официальной документации под вашу конкретную версию, они меняются между мажорными релизами.
PostgreSQL для Keycloak: сколько RAM отдельно
Keycloak может работать и с MySQL/MariaDB, но PostgreSQL — самый предсказуемый вариант, и он же рекомендован в официальной документации. Отдельно под базу:
- До 1000 пользователей: 512 МБ – 1 ГБ RAM,
shared_buffers = 256MBдостаточно. - До 10 000 пользователей, активный аудит событий (event listener → БД): 1-2 ГБ,
shared_buffers = 512MB. - 50 000+ пользователей, полное логирование admin events: 2-4 ГБ отдельным сервером.
Если включаете хранение событий (Events → User events → Save events) с длинным сроком хранения — таблица EVENT_ENTITY растёт быстро, и это уже вопрос не только RAM, но и дискового I/O. На небольших нагрузках держать Keycloak и PostgreSQL на одном сервере нормально — просто не забывайте, что лимиты памяти для обоих сервисов должны укладываться в общий объём RAM сервера с запасом под ОС (минимум 300-500 МБ). Подробнее про настройку самой базы — в статье про установку PostgreSQL на VPS и про тюнинг PostgreSQL.
Признаки нехватки RAM и как их поймать
Три типичных симптома, что Keycloak упирается в память:
- Контейнер уходит в
OOMKilled— смотритеdocker inspect <container> --format='{{.State.OOMKilled}}'. Еслиtrue— heap или контейнерный лимит выставлены слишком туго. Первым делом поднимите-Xmxили общий лимит контейнера. - Долгие паузы GC (Garbage Collector), которые видны как периодические скачки latency на логине или на
/health— включите GC-логи флагом-Xlog:gc*:file=/tmp/gc.logи посмотрите на длительность пауз. Частые полные сборки мусора — верный признак, что heap слишком мал относительно нагрузки. - Рост потребления памяти без падения после снижения нагрузки — может быть утечкой в кастомном SPI (кастомные Event Listener, кастомный User Storage Provider) или следствием неограниченного роста realm/client cache при большом числе тенантов. Тут поможет heap dump (
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp) и анализ через Eclipse MAT или аналог.
Для постоянного контроля памяти на самом сервере (не только внутри контейнера) удобно поднять базовый мониторинг — например, Grafana и Prometheus по шагам, с алертом на использование памяти близкое к лимиту контейнера. Общие правила про лимиты CPU и памяти в Docker разобраны в статье про ресурсы и лимиты контейнеров, а если сервер в целом начал упираться в память — там же и общий чек-лист в статье что делать при нехватке RAM.
Если Keycloak стоит за reverse-proxy (что почти всегда так в проде, из-за TLS-терминации и заголовков X-Forwarded-*), убедитесь, что сам прокси не съедает лишнюю память буферизацией — практическая настройка описана в статье Nginx как reverse proxy.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Хватит ли 1 ГБ RAM для прод-инсталляции Keycloak?
Технически запустится, но с минимальным запасом — на 1 ГБ безопаснее держать только dev/тест или совсем небольшой прод (до пары сотен пользователей, единичные онлайн-сессии). Для боевого SSO с реальным трафиком закладывайте от 1.5-2 ГБ на сам Keycloak плюс отдельно память под БД.
Можно ли уменьшить потребление памяти без потери функциональности?
Да, частично: отключите start-dev в пользу start --optimized, ограничьте Realm cache и User cache размер через spi-cache настройки, если реалмов много, и не держите избыточно долгий SSO Session Max — чем больше живут сессии, тем больше их одновременно в кеше.
Нужен ли отдельный сервер под кластер Keycloak, если у меня 2-3 инстанса?
Каждая нода кластера — это отдельный JVM-процесс со своим heap, они не шарят память между собой напрямую (только через Infinispan-репликацию состояния сессий по сети). Считайте память на каждую ноду отдельно по таблице выше, а не делите общий бюджет на количество нод.
Keycloak на native-образе (GraalVM) ест меньше памяти, чем на JVM?
Да, стартовый footprint у native-сборки заметно ниже и старт быстрее, но у неё меньше предсказуемости под пиковую нагрузку и сложнее диагностика (не все JVM-инструменты профилирования работают с native-образом). Для большинства прод-сценариев официально рекомендуемый и наиболее протестированный вариант — JVM-образ с явно заданным heap.
Что будет, если превысить лимит памяти контейнера?
Docker/containerd пришлёт процессу SIGKILL (это и есть OOMKilled) без возможности штатно завершиться — незавершённые транзакции к БД откатятся, активные HTTP-запросы оборвутся с ошибкой на клиенте. Поэтому лучше держать разумный запас между -Xmx и лимитом контейнера, а не подгонять их вплотную.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →