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

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

MAATRIX

Keycloak — это не лёгкий сервис вроде статического сайта: под капотом Java-приложение на Quarkus с собственным heap, кешем сессий в памяти и (в кластере) репликацией через Infinispan. Взять минимальный VPS «на глазок» и упереться в OOMKilled на второй день — типичная история. Разберём, сколько RAM реально нужно под разные сценарии, из чего складывается потребление и как не переплатить за железо, которое не используется.

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

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

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

Сколько RAM реально нужно — короткий ответ

Если совсем коротко, для типовых сценариев:

СценарийПользователей / активных сессийRAM для KeycloakvCPU
Dev/тест, локальная разработкадо 50512 МБ – 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 ГБ отдельным сервером.

Если включаете хранение событий (EventsUser eventsSave events) с длинным сроком хранения — таблица EVENT_ENTITY растёт быстро, и это уже вопрос не только RAM, но и дискового I/O. На небольших нагрузках держать Keycloak и PostgreSQL на одном сервере нормально — просто не забывайте, что лимиты памяти для обоих сервисов должны укладываться в общий объём RAM сервера с запасом под ОС (минимум 300-500 МБ). Подробнее про настройку самой базы — в статье про установку PostgreSQL на VPS и про тюнинг PostgreSQL.

Признаки нехватки RAM и как их поймать

Три типичных симптома, что Keycloak упирается в память:

  1. Контейнер уходит в OOMKilled — смотрите docker inspect <container> --format='{{.State.OOMKilled}}'. Если true — heap или контейнерный лимит выставлены слишком туго. Первым делом поднимите -Xmx или общий лимит контейнера.
  2. Долгие паузы GC (Garbage Collector), которые видны как периодические скачки latency на логине или на /health — включите GC-логи флагом -Xlog:gc*:file=/tmp/gc.log и посмотрите на длительность пауз. Частые полные сборки мусора — верный признак, что heap слишком мал относительно нагрузки.
  3. Рост потребления памяти без падения после снижения нагрузки — может быть утечкой в кастомном 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 ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

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