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

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

MAATRIX

Официальный минимум для Umami — 1 ГБ RAM, и это не маркетинговое приуменьшение: сервис действительно поднимается на слабом VPS и первые месяцы работает без единого сбоя. Вопрос в другом — что происходит через полгода, когда таблица событий набирает миллионы строк, а дашборд «за последний год» вдруг начинает грузиться заметно дольше. Разберём, из чего реально складывается память Umami, чем она принципиально отличается от тяжёлых аналитических систем вроде Matomo, и как посчитать запас под свой трафик.

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

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

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

Короткий ответ: сколько закладывать по трафику

Ориентиры для связки Next.js-приложение Umami 2.x + PostgreSQL 16 в Docker на Ubuntu 24.04, без Redis.

ТрафикRAMvCPUДискЧто случится на шаг ниже
До 20 тыс. просмотров/мес, 1–3 сайта1 ГБ115 ГБ NVMeпри одновременном открытии дашборда двумя людьми сервер иногда уходит в своп на пару секунд
20–150 тыс./мес, до 10 сайтов2 ГБ1–225–30 ГБ NVMeна 1 ГБ дефолтный shared_buffers Postgres (128 МБ) не держит индексы, отчёты за год читают с диска
150 тыс.–1 млн/мес, до 30 сайтов4 ГБ250–80 ГБ NVMeна 2 ГБ параллельные записи трекинга и открытые дашборды начинают конкурировать за буфер
1 млн+/мес, десятки сайтов8 ГБ и больше4150+ ГБ NVMeтаблица событий разрастается настолько, что агрегатные запросы без партиционирования упираются в диск и CPU

Ключевое отличие от большинства self-hosted аналитик: сам Umami почти не потребляет память сам по себе — весь вопрос упирается в PostgreSQL и объём накопленных данных. Это не батч-система с фоновым пересчётом, а тонкий Node.js-слой поверх обычной реляционной базы.

Из чего складывается память: два процесса, а не три

У Umami нет отдельного тяжёлого background-воркера — в этом его принципиальное отличие от аналитики с архивированием. Есть два (при желании — три) независимых потребителя памяти.

Node.js-процесс самого Umami. Это Next.js-приложение, которое отдаёт API-эндпоинт /api/send для приёма событий с сайта и рендерит дашборд администратора. В состоянии покоя занимает 100–180 МБ RSS. Приём события — это простой INSERT в базу без какой-либо тяжёлой обработки на стороне Node.js, поэтому даже при всплеске трафика память процесса растёт незначительно и быстро возвращается к базовому уровню. Разовые скачки дают одновременные запросы к дашборду — там строится несколько SQL-запросов и рендерится JSON-ответ, но это доли секунды, а не минуты, как archiving у более тяжёлых систем.

PostgreSQL. Вот где на самом деле живёт вопрос памяти. Все просмотры и события пишутся в одну растущую таблицу событий (в схеме Umami 2.x это website_event), плюс таблицы session и event_data для пользовательских свойств. Чем больше строк в этих таблицах, тем важнее, помещаются ли рабочие индексы в shared_buffers — если да, запросы дашборда быстрые; если нет, каждое открытие отчёта за длинный период читает с диска.

Redis (опционально). Начиная с определённой нагрузки имеет смысл подключить Redis как кеш для сессий трекинга — это снижает число обращений к Postgres при частых событиях с одного и того же посетителя. Для типичного самостоятельного проекта Redis добавляет 20–50 МБ и не обязателен: подключайте его, когда видите реальную конкуренцию за соединения с базой, а не заранее «про запас».

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

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

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

Почему Umami легче Matomo — и в чём здесь подвох

У Matomo основной потребитель памяти — фоновый core:archive, который раз в час пересчитывает сырые визиты в готовые отчёты; именно он чаще всего роняет сервер по OOM. У Umami такого процесса нет вообще: дашборд считает статистику SQL-запросами по живым данным прямо в момент открытия страницы, без предварительного пересчёта и без риска, что незапущенный вовремя cron обвалит сервер ночью.

Оборотная сторона этой простоты — цена каждого запроса растёт вместе с объёмом накопленных данных, и расти будет постоянно, а не разово. У Matomo тяжёлый archiving идёт по расписанию и его можно ограничить --concurrent-requests-per-website; у Umami тяжелеет сам SQL-запрос дашборда, и повлиять на это можно только индексами, буфером базы и, в конечном счёте, партиционированием таблицы при действительно больших объёмах. Для 90% сайтов с трафиком до сотен тысяч визитов в месяц это не проблема — Postgres прекрасно агрегирует миллионы строк по индексированной колонке времени за миллисекунды. Проблема начинается, когда на сервере с 1–2 ГБ RAM накапливается многолетняя история по десятку сайтов одновременно и индексы физически перестают помещаться в память.

Как измерить реальный расход на своём сервере

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

docker stats umami umami-db --no-stream

Размер самих данных и то, насколько таблица событий уже выросла:

SELECT pg_size_pretty(pg_total_relation_size('website_event')) AS total_size,
       (SELECT count(*) FROM website_event) AS rows;

Ключевая проверка — реально ли Postgres укладывается в буфер при типичном запросе дашборда за длинный период, или уходит на диск:

EXPLAIN (ANALYZE, BUFFERS)
SELECT date_trunc('day', created_at) AS d, count(*)
FROM website_event
WHERE website_id = '00000000-0000-0000-0000-000000000000'
  AND created_at > now() - interval '12 months'
GROUP BY d;

Строки Buffers: shared hit=... read=... в выводе — то, что нужно смотреть. Большая доля read относительно hit означает, что данные не в кеше и читаются с диска при каждом открытии графика — сигнал поднимать shared_buffers, а не сразу расширять диск. Общую логику free -m, доступной памяти и того, когда сервер уже реально упирается в своп, разбирали в статье про правильный размер swap для VPS.

Настройка Postgres и лимитов контейнеров под свой объём памяти

Дефолтный образ postgres:16-alpine из типовых docker-compose для Umami запускается с shared_buffers=128MB — это подходит только для самого младшего тарифа. На сервере с 2–4 ГБ имеет смысл явно задать параметры в команде запуска контейнера:

# docker-compose.yml
services:
  db:
    image: postgres:16-alpine
    command: >
      postgres
      -c shared_buffers=512MB
      -c effective_cache_size=1536MB
      -c work_mem=16MB
      -c maintenance_work_mem=128MB
    mem_limit: 1024m
    mem_reservation: 512m

  umami:
    image: docker.umami.is/umami-software/umami:postgresql-latest
    mem_limit: 384m
    mem_reservation: 128m

work_mem отвечает за память на сортировки и группировки внутри одного запроса — именно это использует дашборд при GROUP BY date_trunc(...). Ставить его слишком большим на маленьком сервере опасно: work_mem выделяется на каждую операцию сортировки в каждом одновременном запросе, и при нескольких открытых дашбордах цифры быстро складываются. Общие принципы подбора этих параметров под конкретный объём RAM и частые ошибки конфигурации разобраны в статье про тюнинг PostgreSQL на сервере — механика применима к Umami без изменений, это обычная база данных без специфики аналитики.

mem_limit для самого контейнера Umami можно держать скромным — 256–384 МБ с запасом покрывают даже пиковую нагрузку на Node.js-процесс, сюда не нужно закладывать «на всякий случай» так же, как под archiving у более тяжёлых систем.

Рост таблицы событий: что делать, когда данных становится много

Umami не удаляет старые события автоматически — по умолчанию таблица растёт без ограничения, и это осознанный выбор архитектуры: вся статистика (включая произвольные периоды в прошлом) считается по сырым данным, а не по заранее агрегированным срезам. Для одного-двух сайтов с обычным трафиком это не создаёт проблем годами. Если у вас десятки сайтов или трафик исчисляется миллионами просмотров в месяц, разумно предусмотреть ручную политику хранения — например, переносить события старше двух-трёх лет в отдельную архивную таблицу или выгружать их во внешнее хранилище перед удалением, если такая история вообще нужна для отчётности.

-- пример: посмотреть, сколько строк старше 2 лет, прежде чем что-то удалять
SELECT count(*) FROM website_event WHERE created_at < now() - interval '2 years';

Прежде чем удалять данные, обязательно снимите бэкап базы — восстановить статистику посещений задним числом неоткуда, в отличие от файлов на диске. Отдельно стоит следить за autovacuum: таблица событий у Umami в основном только растёт (INSERT, почти без UPDATE/DELETE), поэтому раздувание от мёртвых строк ей не грозит так, как таблицам с частыми обновлениями, но регулярный ANALYZE всё равно важен, чтобы планировщик запросов правильно оценивал объём данных при построении графиков.

Какой сервер взять под Umami

Правило простое: на старте память почти не имеет значения, дальше всё решает объём накопленных строк и число одновременно открытых дашбордов, а не сырой трафик по просмотрам.

Минимум: 1 vCPU, 1 ГБ RAM, 15 ГБ NVMe. Один-три небольших сайта, до 20 тысяч просмотров в месяц суммарно. Именно эту конфигурацию честно заявляет официальная документация Umami, и на практике она действительно работает — но без запаса: если сервер занят ещё чем-то (например, тем же сайтом, который трекается), лучше взять на ступень выше.

Комфортный вариант: 2 vCPU, 2–4 ГБ RAM, 30–80 ГБ NVMe. До десятка сайтов, shared_buffers 256–512 МБ, свободный запас под рост базы на год-два вперёд без ручного вмешательства. Для большинства блогов, лендингов и небольших SaaS-проектов это конфигурация «поставил и забыл».

Локация для Umami почти не влияет на функциональность — в отличие от систем со сложной синхронизацией, здесь всё крутится на одном сервере. Выбирайте по географии посетителей вашего сайта: RU для аудитории в России ради минимального пинга у трекинг-скрипта и однозначного соответствия 152-ФЗ, UK или US — если сайт ориентирован на зарубежную аудиторию.

Сам процесс установки — от чистого сервера до первого события в дашборде — подробно разобран в статье про установку Umami на Ubuntu 24.04; там же готовый docker-compose.yml и настройка Nginx с SSL, здесь мы сосредоточились именно на памяти.

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

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

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

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

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

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

Хватит ли 1 ГБ RAM для Umami в реальности, а не только по документации?

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

Правда ли, что Umami совсем не создаёт нагрузку, как Matomo с archiving?

У Umami действительно нет отдельного фонового процесса, который может обвалить сервер по OOM среди ночи — в этом смысле он предсказуемее. Но каждый запрос к дашборду выполняет SQL-агрегацию по живым данным, и эта цена растёт вместе с объёмом накопленной истории, просто без резких скачков.

Нужен ли Redis для нормальной работы?

Нет, это опциональная оптимизация для высокой нагрузки, снижающая число обращений к Postgres при частых событиях трекинга. Для проекта с трафиком до пары сотен тысяч просмотров в месяц Redis почти наверняка не понадобится.

MySQL вместо PostgreSQL сильно меняет требования к памяти?

Принципиально нет — оба варианта поддерживаются официально, логика та же: чем больше данных, тем важнее буфер базы (innodb_buffer_pool_size у MySQL против shared_buffers у Postgres). PostgreSQL в связке с Umami встречается на практике чаще и лучше задокументирован сообществом.

Когда пора партиционировать таблицу событий?

Ориентир не жёсткий, но если у вас десятки миллионов строк и открытие годового отчёта заметно тормозит даже после увеличения shared_buffers, это повод рассмотреть партиционирование по времени или перенос старых данных в отдельное хранилище — на объёмах в сотни тысяч и единицы миллионов строк обычная индексация справляется без дополнительных мер.

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

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

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